Native mobile apps with JavaScript

Manuel Lehner09.12.2016

This article discusses different ways to create mobile apps with JavaScript. Since there are tons of mobile application frameworks we want to focus on three major players in the native game: React Native (by Facebook), Titanium (by Appcelerator) and NativeScript (by Telerik).

First of all, this is not a Hello World App comparison, nor it instructs how to get started with each of these technologies. And because some of you may know that I used to be very active in the Appcelerator community, I want to state out that I do my best to keep my perspective  fair-minded. No framework bashing.

One thing all three have in common: they empower JavaScript developers to create native apps for multiple platforms.  "But what about Framework XYZ?" you might think? This one is probably also very cool, but this post is not about hybrid frameworks that wrap websites in native apps and I simply didn't have the time to catch up with all possible solutions.

I'm interested in the basic principles behind them, how flexible and extensible they are and what possible burdens lie in wait for being placed on developers.

Entering Nativeland

There are two questions you might ask first:

1. Why should I even develop a native app when my website is already perfectly responsive?

2. Why not develop truly native with no framework?

When talking about cross-platform developing this is a basic discussion. So we don't want to dive too deep into the web vs. native debate. I assume that you decide yourself when you or your customer needs a native app. Most indications for native apps are a better UX, performance and access to native APIs.

Targeting more than just one platform from a single codebase is the key value of using a framework in favor of developing platform-specific. The other advantage is that you can use the language that we all know and love: JavaScript. Considering this, even when you don't care about other platforms but just want an iOS App, using a cross-platform framework may lead you to a satisfying result faster than learning Swift from scratch.

In addition, keep in mind that cross-platform development does not mean that your app looks and behaves the same way on iOS and Android. If done right, you share as much as possible of the codebase across all platforms, like business logic or data management, but implement dedicated parts of the user interface for each platform. This is where the real power of such a framework can come in.

Basic Principles

Let's have a look at how we get a native mobile app using these JS frameworks. First of all, they require to have the native iOS and Android SDKs to be installed on our system. Perhaps Windows too, if you also want to target that, but it's currently only supported by Titanium. But both, React Native and NativeScript, have announced Windows UWP support for the future. You also need to have Node.js installed. The next steps differ but there are "getting started" guides in the framework documentations, so we don't have to go into that here. More interesting are the different development workflows.

React Native

If you already have some experience with React itself, you are well prepared for React Native. Understanding React's basic concepts is fundamental for working with React Native. "Learn once, write anywhere" is how Facebook promotes this.

Declaring the UI works best with JSX, that is a kind of XML embedded into JavaScript. This is how UI components are defined. JSX is optional but recommended. Once I got used to the syntax, I really liked it.

As there is no DOM in a mobile app, React Native is hooked up with all components you need to access the native UI elements (remember: you don't just want to make your web app deploy to an iPhone). Most of them are abstracted to a platform-agnostic API. Platform specific components are suffixed accordingly.

Components are controlled by static props that get passed from the parent component. Data that intends to change is managed in the state, a large immutable object that represents your application state. You can use state containers like Redux to manage your state, just as you know from React.

A little hint: if you are wondering if there is a kickstarting tool like create-react-app for React Native, there is! Ignite gives you all you need to get started with your project.

Titanium

Titanium embraces itself as a "Write once, Adapt everywhere"  - framework. You can and should take full advantage of the target platform while reusing as much code as possible. That's what cross-platform development is about.

The cool Titanium developers use Alloy to build up their apps' UI. That is the MVC framework on top of Titanium with Backbone.js and Underscore.js built-in. Just like JSX, Alloy is not a must but recommended.

This pattern wants you to manage your application state within models and separate your UI in views. The application logic goes into controllers, which is where models and views are connected. Views can be platform-specific (partially or completely) and are declared in XML files. Alloy also supports CSS-like Stylesheets, a JSON-formatted so-called Titanium Stylesheet (TSS). Apps can not only modularize into controllers but also into Alloy widgets. Widgets are self-contained components with their own controllers, views, styles and models and can be dropped into the project.

The Titanium SDK gives you a complete set of APIs to access the native UI controls and System APIs. These are abstracted into modules that can be accessed through the global Titanium namespace from the JS source code. 

NativeScript

In NativeScript the declarative UI is also written in XML along with CSS files. Of course, not real CSS as there is no HTML. It looks and feels like Appcelerator's Alloy at the first look. But NativeScript follows an MVVM pattern. No big difference at the second look: models represent the data and views represent the UI. And then there is the view model that contains the model and binds its data to the view using Observables.

Important to know: you can use NativeScript with Angular 2 and TypeScript. That brings a bunch of opportunities we won't expose here. It's all perfectly explained in the guides.

The most interesting functionality of NativeScript is the direct native platform access. I consider this  their USP. More on this in a moment, hold on!

Behind the scenes

How do such frameworks work in general? How do I come from JavaScript to the platform's native code? Does it pre-compile my sources or execute it at runtime? Let's have a look under the hood.
The magic behind this architecture is pretty simple and shared between all three frameworks. Basically, the JS code you write will indeed execute at runtime in a JavaScript virtual machine. Therefore, on iOS the WebKit's built-in JavaScriptCore is used. On Android it's Googles V8. 

How Appcelerator and Facebook do it

Starting with Titanium, the oldest player in the game, as they did it first. Titanium compiles a project into a native application which, when it launches, will create a JS runtime environment. Now for bridging the gap between JS and native code, they have so-called proxies. The SDK provides a native class for the proxy and a proxy-object that gets injected into the JS code. Now when you call a function on the JS proxy, the native proxy can invoke that function on the native class. So far, so good. We don't want to dive deeper for now. There's a lot more magic happening under the hood.

React Native basically does the same thing but calls the native class bridge instead of proxy and catalyst on JS side. But don't get me wrong. I'm not calling Facebook a copycat. They already had React as their basis. And with React comes a completely different approach to frontend development. Of course that should be applied to mobile app development as well. And they did some very clever things to bring that experience to React Native.

How NativeScript does it

NativeScript is different. As far as I can tell, there is nothing like these native bridge classes or proxies. But there is a custom JS runtime engine. When the app gets built, NativeScript will package your JS sources together with a dedicated iOS runtime, respectively a custom V8 on Android. Those runtimes become injected with custom C++ code and global scope objects that contain so-called metadata. This is the custom data format for listing the native APIs, it's generated platform-specific during the build process. Calling a function on that custom scope object will invoke a callback in the runtime. This again executes the custom C++ code which in turn can access native iOS APIs. On Android the JNI (Java Native Interface) is used to jump from C++ to Java.

I admit I have no idea what exactly happens behind the scenes or how this works in detail. But you now should have an idea how these techniques  basically work. Each of these frameworks does a lot of magic that is probably only understood by the person who wrote it or by a core developer.

Customizing & Extending

When using a framework everybody comes to that point in time where a limitation is reached. Imagine you are developing that new app for days and weeks and then you need to access a third-party library. Or a new platform feature for which there is no API in that framework's SDK. Or a missing feature in an existing one. Or just a bug. Anyway, you need to find a way to integrate your own native code into the framework.

The good news is: All three frameworks are open source software. So if you found a bug and you want to fix it, you can! The same applies for features. If there is  a community, there are pull requests.

And the bad news: there are actually no bad news. You can extend Titanium and React Native with your own native modules. They must be implemented for each platform in the particular language. The frameworks provide base classes and helpers for that. There are also well-documented guides for developing native Titanium or React Native modules. What you basically do is writing a wrapper API for that missing functionality you want to expose to JS.

NativeScript doesn't need these wrapper APIs. You can actually access everything directly from the JS code as described above. This is how all of the modules which come with the framework are made of. That means you can instantiate a Java object from JavaScript (on Android, of course) and call methods on it. Crazy!

I also need to mention that Appcelerator has something similar for Titanium, called Hyperloop. But as it's not open source anymore (it used to be) and only available with a paid Pro account it's less attractive for most developers.

Thinking further 

From a CTO's perspective it's important to understand the technology stack behind these frameworks. When you must make a decision but all you know about the options is that they're basically doing the same, then you have to find out in which circumstances one performs better than the other. For example, I'd ask myself if NativeScript is already matured into a sophisticated production-ready software. Or if Titanium still is, after Appcelerator moved a long way since it all started as an open-source product. Now they offer a full-stack development PaaS with a bunch of other tools.

Another concern many developers have when deciding on open-source projects is how popular they are. How big is the community? How can I get support when I run into problems? How well maintained is project? This can express as, for example, how long it takes for a pull request to be merged or how bug reports and feature requests are handled. Some do it good, others even better.
This isn't always easy to find out. I didn't do any big opinion research on that but checked out things like stars on GitHub, the StackOverflow ranking and how many members the main developer community channel (Slack or Facebook Group) has. React Native clearly is the most popular one out of those three. This is most likely due to the success of React. The smallest community seems to be NativeScript which is also the youngest framework, so this is not a huge surprise.

This may be opinionated but there is no clear winner in this comparison. As always, it depends on what you want, what you have and also what you like. There are various other factors that are important to determine the appropriate framework. If you already have a web frontend built with React, you'll probably lean towards React Native. If you are more the Angular guy and like the native capabilities you might choose NativeScript. Or if you have some experienced Titanium developers in your team and want to take advantage of the Appcelerator platform, you'll walk this way. 

I really look forward to our next mobile app project and wonder which technology we'll go for. Hopefully I can share some more insights then.

Dein Besuch auf unserer Website produziert laut der Messung auf websitecarbon.com nur 0,28 g CO₂.