ns

Native-what?

If you’re anything like myself before embarking on this project then you might wonder the same thing. Everyone has heard of React Native, it’s a popular technology enabling a cross-platform mobile development experience, but not so many have crossed paths with Nativescript, or {N}.

Nativescript is a framework with a similar goal to React Native, providing the ability to publish native apps for both major platforms, iOS and Android, whilst only maintaining a single (mostly) JavaScript codebase.  It is available in three flavours: standard, Angular, and Vue.js, allowing developers with experience in the latter two frameworks to use their existing skills whilst building for mobile.

Put simply, it’s a JavaScript runtime inside a native app, translating code on the fly into native elements.  In this post, I’m going to tell you about a few of the nice experiences we’ve had recently developing with Nativescript, as well as a few of the not so nice issues that were encountered, and whether we’d use it again.

How did I get here?

At the tail end of 2017, we were tasked with quickly building a new native mobile MVP. Basic features at first but likely to extend into a bigger and better project if the three-month build was a success. A purely native approach was ruled out immediately as a single codebase was highly preferred, so the first thing we did was spend a couple of days evaluating which of the myriad cross-platform development tools we’d actually use. Frameworks like Ionic and Cordova were rejected outright as we wanted to use a native rather than hybrid approach, and we don’t run a .NET tech stack so that wasn’t practical either.

In the end, it came down to React Native and Nativescript.  There was another project called Flutter that also looked promising, but it was discarded due to its level of maturity (at the time the latest build was alpha-0.0.12).

Narrowed down to two options, the final task was to build a small prototype in each to determine viability in terms of learning curve and development speed.  This task turned out to be pretty simple regardless of platform, so the deciding factor then turned to the external development environment. In terms of developer skillsets, other team members who would potentially work on the project in the future were heavily Angular focused.  All of our other web-apps are built on either Angular or Angular.js and there is comparatively little React experience within the wider team.

 

So how did that turn out?

Pretty well actually.  While there was some initial concern about whether we’d still have been better off with React Native due to the higher popularity providing a bigger supporting dev community, there have been zero issues that using React Native itself would have solved.

 

Okay, so what’s so good about it?

unicflag
At times this is what {N} feels like

Hot & spicy

Nativescript allows for hot-reloading whilst performing development magic. For those of us with experience developing native applications, the ability to make changes in your code and see them in your app within seconds, either emulated or on a physical device, feels amazing, like riding a fire-breathing laser-unicorn.

In short, development speed is significantly improved by not having to wait for full app build cycles between making changes.

One code to deploy them all

Pretty much a given, but this one is kinda important.  The majority of the time, when using the built-in pre-wrapped native components, the app looks and feels the same regardless of device, though {N} still allows flexibility in writing platform specific code when needed.  In our experience, the majority of platform specific code is for slight tweaks in the style templates, which are written in a stripped-down CSS implementation that wraps native styling properties.  In a few other places, it was required in the application logic to access underlying native APIs.

Documentation

This stuff can make or break a project and for the most part the Nativescript documentation was fairly good.  There’s a great starter tutorial for each flavour of the framework as well as plenty of API documentation, code examples, and comprehensive Github demo projects to be found.

Angular > Learning new things

This was a big feature for us.  The ability to use Angular components and develop using a framework we’re already familiar with saved a lot of time, removing a big chunk of the learning curve.  Using patterns established in our web applications allowed us to rapidly onboard other developers when they joined the team this year.

nsan.png
Who doesn’t enjoy a crossover episode?

Worth a mention here is that this is (most of the time) pure Angular code.  This means that Angular components such as services, pipes, validators, and route guards are able to be bundled into Angular modules and shared between the mobile app and our web applications in either direction.  This is broadly not the case for view components, however this is neither surprising nor expected, as most teams probably wouldn’t bother writing a mobile app if the UI layer was exactly the same as the website anyway.

Since we’re using Angular this includes out-of-the-box support for Typescript, which for reasons I won’t go into here (other Shiners already have), is a big plus when trying to write quality code and reduce sneaky errors.

Nativescript also provides tooling integrations that give us the option of using Webpack to do our bundling and various other production wrap-up voodoo, enabling us to optimize the final output in an effective and familiar way.

Keeping up with the Angularashians

Nativescript, like everything else in the JavaScript ecosystem, is a fast-moving beast.  In the six months I’ve been working with it, there’s been a few minor releases and one major release.  A lot of issues have been addressed and features added in the recent times and it’s only getting better, app performance is improving with every update, sometimes significantly, for example the last update v4.1.0 one claims to reduce android loading time by 50% (Disclaimer: I haven’t actually timed it on our app to see if that claim holds up, but it does feel a little quicker to start)

The side project Nativescript-Angular that we rely on is also fairly quick to keep up with Angular releases.   On day one of development the current {N}Angular release was built to work with Angular v4.x.x.

Soon afterwards, Angular, in keeping with its promised 6-month major release schedule, released version 5 on 02/11/17.  Within five days the {N}Angular team had a release candidate available for those who wanted to start enjoying breaking changes introduced in v5.  The official release came around six weeks later, on 21/12/17.

For the more recent Angular6 it was a similar story, everyone who wanted to enjoy new Angular features and bugs only had to wait 4 short weeks for the official {N}-Angular wrapper to be released.

Debugging + Testing

VSCode is our weapon of choice for Nativescript development and the team at {N} have built a nifty little plugin for VSCode that will allow you to attach to the running instance on a device and step through the code when you really need to see what’s going on in there.  There’s also the option of attaching a debugger through Chrome dev tools; it can’t do everything you can do on the web, but it can be helpful at times.

A karma test runner is available with the nativescript-karma plugin, and popular testing, assertion and mocking libraries such as jasmine or mocha are able to be configured to work with it.  It’s pretty similar to testing Angular components for the web (with some issues and one big exception, but I’ll hit that later).

For end-to-end testing, we utilised Appium (think Selenium, but for phones) with cucumber style test specs to run our automated UI tests.

 

It’s not all sunshine and rainbows

When Nativescript worked, it worked really well, but sometimes seemingly simple features turned out to be a bit harder than they may have been in a purely native build.  So, what kind of problems did we encounter?

Breaking Build

One problem experienced on a fairly regular occasion was the issue of corrupted build files and processes.  In a typically Pavlovian way, we found ourselves in the habit of automatically removing the generated platforms folder from the project and trying a rebuild before investigating further into any issue that wasn’t immediately obvious from the stack-trace.  This tended to magically rectify many mysterious problems that appeared, seemingly at random, during development.  Whilst not a huge issue, it happened with enough frequency that it became something of an in-joke in the team, the process is even one of our npm scripts!

giphy
Carefully tweaking the build process

Another thing that caused a more than a few head scratches was the way that the node processes kicked off by the build and run commands had a tendency to not die when the run was killed, continuing to execute in the background and causing subsequent runs to behave in weird and unpredictable ways.  This can be easily solved with a quick killall “node”, but it’s still something that you should be aware of to check when things don’t appear to be functioning properly.

An Unexpected Wrap Career

Whilst the documentation may give you the impression that you can easily use any native library you could possibly desire, in reality this may not be the case.  A lot can depend on the implementation of the native library in question and whether or not it is open sourced.  We ran into both of these scenarios during development which slowed the pace on those features.

In the first case, we were trying to use some native charting libraries, MPAndroidChart for Android and the similar Charts for iOS, in order to give our UX team the look and feel they were after.  Wrapping up the Android version actually was a simple affair, but the iOS one proved difficult, eventually requiring a rewrite of the native code in order to pass data through a common interface for both.

The second time around, we needed to include a proprietary SDK in our app due to architectural integration requirements.  This particular SDK is closed-source and as our app is not a purely native one we couldn’t follow the standard instructions for including the SDK that were provided by the vendor.

This actually required decompiling and reverse engineering the SDK in order to write a wrapper for it.  There was also issues with the order of initialisation of the various pieces of the app, for example to make sure that the {N} runtime was available when it we needed it to apply certain configuration options, so we had to get creative in writing wrappers and plugins to make it all work.

It should be noted that neither of these problems are really a Nativescript one, but are the result of using a cross-platform development approach, the solution to minimise these issues would be to use a purely native development approach.

Wisdom of the Ancients

As noted before, the community is not quite as large as that of React Native, and more than once we hit issues that had only been encountered by DenverCoder9.  That’s not to say that there wasn’t any help available, the Nativescript team is very active in the community and solutions for most of our confusing issues were easy to find, in some cases caused by a lack of experience with the framework, in others actual bugs that were patched in following {N} versions.  There were more than a few days wasted trying to discern cryptic error messages and digging into the {N} core to try and figure out what went wrong.

wisdom_of_the_ancients
Somewhat relatable after a little time spent in {N} development – via https://xkcd.com/979/

More Testing!

If you’ve done testing of Angular components before you’ll probably be familiar with using TestBed to inject test-doubles of component dependencies.  Up until two weeks ago, this wasn’t possible in {N} testing as it would cause the tests to throw errors instead.  What we ended up doing was an awkward manual instantiation of the component under test, passing test stubs into the constructor and calling Angular lifecycle hook methods to ensure they were triggered appropriately.  Obviously not ideal and a fair bit messier test code than you might want.

Another issue in testing was the performance of the e2e Appium tests, they can take a really long time to execute, it’s fine if you have a build machine to run them on, but if you had to use your development machine, it’d get quite frustrating, quite fast.

Performance

Not gonna lie, page-routing can be slooooow, especially on older Android phones, iOS doesn’t appear to suffer anywhere near as much.  Old issues on Github suggest this problem has come and gone from {N} during various releases, but all I can say is, it’s been there ever since our app grew larger than some trivial pages.  At the moment, the team has a task up to profile route transitions to see where all the time is going and comb through our views, optimising where possible to improve page-load performance.  If we manage to improve it significantly I might even write a follow-up post on how to go about doing that.  For now, it’s an issue we’re working on.

 

So… should I use it?

Possibly.

The biggest factor, in my own opinion, is what you want to do in your app. If you’re making some kind of ChatSnap app with lots of fancy filters, image rendering, and transitions, I’d probably stick to writing pure native code.  That’s also the case for anything where there is a requirement for high performance.

If you want to embrace cross-platform then, much like us, your decision will probably depend on the skills your team already has.  If you’re more familiar with React and Redux than Angular, I’d say go with React Native, if it’s the other way around then yes, give Nativescript a go.

At this point in time, even with the issues we came up against, I can comfortably recommend {N} to a team that it’s appropriate for.  Nativescript has a lot to offer and can provide just as good a development experience as React Native, with the team making performance improvements and adding a bunch of new features with every release.

At the recent Google I/O, the Angular guys mentioned that they’re working closely with the Nativescript team to improve the tooling and experience so I think it’ll stick around and is only going to get even better.

Happy coding!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s