Building Your Mobile App With Angular Native: Code Sharing + Native Performance

March 22, 2017 2310 Views
← Back
Angular Native - NativeScript with Angular 2

Meet Angular Native – a new platform that allows to create native software using cross-platform technologies. In other words, you get the best of both worlds – native performance and code sharing capabilities.


How is it possible? How does it work? Can it become the perfect budget-saving solution to base your software product on? Read further to see!


What is Angular Native made of?


Angular Native is not a brand name. It's more of a bundle of two technologies, Angular 2 and NativeScript. We are going to see how it works, exemplify it with real cases, and cover strengths and weaknesses of both platforms.


Angular Native


NativeScript is a platform developed by Telerik (currently Progress) for cross-platform mobile app development, which is backed by Google at the moment. The latest releases of NativeScript are marketed not as a standalone technology, but in an inseparable bundle with Angular 2. This allows to write apps for mobile, desktop and web.


But now let's proceed to each of the two parts.



How NativeScript works


A rather simple idea like "to write a native app in JavaScript" can conceal substantial issues. The main question here is, how do you define a native app? There are two possible answers:

• 100% native functionality in your app

• 100% native performance in your app (including UI)

It is important to differentiate these two criteria clearly.


Let us start with 100% native functionality. If we speak about PhoneGap, we speak about an app with an in-built web browser, which becomes the environment for your JS-based app. JS code runs in this browser and gets limited access to API via Cordova plugins. Thus, if you need some element of native functionality, you need a plugin. The good news is that this plugin might already have been written and made available for use.


Native and Hybrid Apps


In case of Xamarin or NativeScript, your code gains full access to native API. How does it work?


The implementation is different for different platforms:


NativeScript Android Implementation

NativeScript iOS Implementation


In the code, everything looks way simpler:



  var file = new java.io.File(path);


This is a valid line in NativeScript, when a variable file is created and a native object java.io.File is assigned to it. Here is the description of the steps that follow, taken from documentation:


• The virtual machine executes the JavaScript code.

• Binding defines corresponding call methods from the native side.

• The transfer service transforms the JavaScript string into object java.lang.String.

• The outcome of the function call is a custom JavaScript object—it works as a proxy for a native object java.io.File, created on the Android side. When a method called for that proxy, it is delegated to the underlying native object instance.


However, it works when the program is launched; the virtual machine executes JS code – V8 for Android and JavaScript Core for iOS. These are two different virtual machines with different mechanisms and interactions with native device API.


But the general idea of how it works remains the same for all platforms. We use the mechanism of metadata, which contains signature for a native method that should be called when you execute JS code.


This means, whenever something new appears in the native SDK, the developers of NativeScript write a method that is called on the native side and a corresponding method signature on the JS side in the metadata file. It's simply a table. When you get a new SDK, they add a new entry for work with this method. This allows to ensure support for the so-called day zero. Within 5-6 hours from the release of the new SDK, an update of NativeScript is released, which already supports this functionality. The developer doesn't have to rewrite anything. Metadata, which allows to use the reflection mechanism between JS and native code, is used for building required interfaces at the moment of app launch. It sets up the correspondence between calls of native objects and the array of JS names. This is the reason why the startup time in NativeScript is longer than in its rivals. However, version 2.5 promises "drastically improved startup time."



What it looks like in the code


Calls of native methods in the app look like this:



// iOS
var array = new NSMutableArray();
array.addObject(new NSObject());
// Android
var context = ...;
var button = new android.widget.Button(context);
// "My Button" is converted to java.lang.String
button.setText("My Button");


In the first example, you work with a native array of objects in iOS. In the second one, you create a native button and assign a text to it. This is the most fascinating thing. Even in NativeScript all plugins for interaction with native functionality, e.g. accelerometer, are written in pure JS.


The following code was taken from a real project. It shows how it's possible to disable selected colors for iOS in NativeScript ListView:



var listView = this.page.getViewById("list_view");
listView.on(ListView.itemLoadingEvent, (args: ItemEventData)=> {
    // disable select colors if it iOS
    if (args.ios) {
        args.ios.selectionStyle =
                UITableViewCellSelectionStyle.UITableViewCellSelectStyleNone;
    }
});



Angular in Angular Native vs. standard Angular


It should be noted that Angular Native isn't really different from the usual Angular 2, except for templates:



<StackLayout verticalAlignment="top" col="1" row="0" class="w-full">
    <AbsoluteLayout class="w-full h-full">
        <ios>
            <Image class="w-full" 
                   [src]="itemObject.img_url" 
                   left="0" top="0"></Image>
        </ios>
        <android>
            <FrescoDrawee class="w-full h-full" 
                          [imageUri]="itemObject.img_url" 
                          left="0" top="0"></FrescoDrawee>
        </android>
        <Label class="t-40 text-white text-wrap p-10 w-full" 
               *ngIf="itemObject.price_formatted" 
               [text]="itemObject.price_formatted" 
               left="0" right="0" ></Label>
    </AbsoluteLayout>
</StackLayout>


They have no HTML tags, things you got used to in the HTML layouting. Views and layouts are native here.


In ReactNative it's necessary to use JSX, which leads to duplications of code of components for different platforms. As opposed to that, in Angular Native you simply have different templates for different platforms, for cases of need. Otherwise, NativeScript provides cross-platform abstractions over native views.


We should mention a major difference on the platform level. In ReactNative, all layouts are based on the FlexBox positioning algorithm. In NativeScript, there are simpler cross-platform abstractions for implementation of positioning. It means that you have options for every case.


Another thing that helps in NativeScript development is automated use of specified code for every platform.



*.android.*
*.ios.*
*.-common.*



There are magic postfixes for that. When they are used, NativeScript utilizes platform-specific code. This related to templates and JS code.



A couple of words about performance


Only old versions were tested. However, it's enough for general understanding and evaluation.

Last update: March 2016

Requirements: iOS 8 + device (iPhone 5S)


  • Native - Xcode 6.3.2
  • NativeScript - NativeScript for iOS 1.6.0
  • Xamarin - Xamarin Studio 5.10.2
  • Appcelerator - Appcelerator CLI 4.1.0
  • Cordova - Apache Cordova 5.1.1
  • React Native - 0.19


We will start with the simplest: startup time of a simplest app with a single button:



NativeScript vs React Native vs Cordova vs Xamarin




Platform
Run 1 Run 2 Run 3
Native 111ms 105ms 108ms
React Native 358ms 361ms 353ms
Xamarin Forms 484ms 471ms 469ms
Cordova 613ms 612ms 609ms
NativeScript 674ms 672ms 670ms


As you can see, NativeScript ranks last. When an app loads, a reflection of JS code call to corresponding native objects is being built. It takes time. The official website offers tips to speed up the startup time, e.g. code minification and packaging in a single bundle. However, this refers only once to startup time. This mechanism is not required after the launch.


Now we'd like to discuss work with primitive data types. The following tables illustrate data transmissions between the native and JS parts:


Here is transmission of average data packages (1 kilobyte) between the JS and native parts.


NativeScript vs React Native vs Cordova vs Xamarin


Platform Run 1 Run 2 Run 3
Native 5ms 4ms 4ms
Xamarin 27ms 27ms 28ms
NativeScript 989ms 998ms 980ms
Cordova 613ms 612ms 609ms
Appcelerator 34444ms 33969ms 35916ms
React Native 130600ms 125140ms 127220ms
Cordova 351420ms 357940ms 356740ms


However, test and real life are two different things. Real native apps require a special approach to ensure and increase responsiveness.



Performance in real apps


In order to ensure high responsiveness in native apps, flows are used. All business logic, all calculations are in a separate UI flow, which helps the app react to any interaction with the end user instantly.


Use flow in native apps


Here is an interesting fact about ReactNative—the reason why it fell behind NativeScript in tests. Both technologies have different realization of architecture. In NativeScript, interaction with native code is synchronous. In ReactNative, JS code is in a separate flow, and interaction with the native functionality is asynchronous—there is no need to take care of it.

JS need to be synced and bathched

This illustration is taken from the London React keynote. This is why they have a lapse in performance at the moment when flows in ReactNative transmit data between each other.


The end user does not care how many milliseconds it takes to run an operation. They need an app that looks great, works fast, and does everything that has been promised. In this regard, flows become the killer feature of ReactNative. NativeScript solves this problem differently, supports standards, and suggests use of Web Workers in apps.


Web Workers For The Win


They have the same APIs as browsers and the same functionality, with a subtle difference: if you work with Web Workers in the browser, there will be no access to DOM. Access to UI is granted; however, its use becomes an obstacle to all flows. Web Workers are the optimal solution here.


Code sharing


One of the best features of Native Script is code sharing. As we mentioned above, there are no differences from Angular 2. If native functionality is required, it is simply injected as a provider or a service into the app. The following picture exemplifies this with an HTTP provider that uses native libraries, which run in another flow. See how it works for different platforms:


Native Script Code Sharing


Here is a real app (based on cross-platform Seed), where not a line was changed, except for layout templates.


Real app based on cross-platform Seed


iOS Simulator, Android Emulator, and Chrome. This is a demo app, which contains all the key points of a real app, several pages, localization, routing, and a simplest data structure. Besides that, this app is assembled as a desktop one, using ElectronJS for macOS and Windows as a basis. The source data can be downloaded here: github.com/NathanWalker/angular-seed-advanced


We should mention the opportunity of making a native app with Ionic 2 and NativeScript: hybridtonative.com/#developing-a-ui-with-ionic-2. This is a massive document that describes the step-by-step process of making a native app out of an existing PhoneGap/Ionic application.


One more advantage is an option of using ES6 by default. As we mentioned, NativeScript utilizes the V8 virtual machine in Android and JavaScript Core in iOS. All the ES6, which is available in the abovementioned machines, can be used directly in NativeScript.


  • Extension of existing native apps
  • Native modules in С++ are similar to Node.js add-ons
  • Node.JS API by the end of the year
  • Work with Android widgets
  • Tests with Mocha.js, Appium, etc.
  • Universal Windows Platform
  • Telerik App Builder
  • WebInspector & NodeInspector for debugging
  • Default Themes
  • v.2.4


  • Feedback


    Here is feedback from a QA engineer who works on one of our related projects:


    – Almost any button crashes if one taps "back" on an Android device during an animation.
    + Lists of 3000 elements scroll well! ;-)



    Difficulties for software developers:


    • Command line interface. The problem is that simulators don't always launch on the first try. There's a large stack which loads for quite a while.


    • You cannot put a container in a view. That's the reason why emulators may crash during composition of a component structure from standard layout templates.


    • Unfortunately, currently there is no inspector that would help check the layout. It's native development, and components are different for every platform (e.g. listview for Android and UI table for iOS).


    • No option of using standard HTML elements in layouts. There is no HTML here. Stylization of off-the-shelf templates is hindered by impossibility to see basic CSS properties. No wonder—native development is less flexible. It provides less opportunities for stylization and customization of elements than web development.


    PositiveNow let's proceed to the positive impressions:


    Command line interface, off-the-shelf animations, key frame animation, off-the-shelf layout elements, which are rendered according to the specifics of every platform.


    NegativeNow, what were the negative impressions?


    First of all, NativeScript development is less convenient than web development. It does not have the set of tools as broad and convenient as the one for web development. Stylization with custom design is also problematic.


    Here is an opinion of a developer who was not involved; he simply sees the NativeScript-based apps on the market:


    App demos are regularly studied by developers on framework websites.


    ReactNative gains the upper hand because it's asynchronous, and the developer does not need to understand the specifics of native development. However, it will never provide you with the same stylization without a native developer, as opposed to Angular Native. The latter is closer to native rather than web.


    We have a test case: a project called Property Cross, made for evaluation of different platforms for cross-platform development. Currently we have an app there, which utilizes an older version of NativeScript (1.7, as opposed to the current 2.5). Feel free to visit GitHub and check the implementation of the same app with a variety of frameworks.



    You can see animations, transitions, rounded images, and stylization of native controls.



    Conclusions


    1. First and foremost, the platform is product-ready.

    2. But keep in mind that it's required to know the specifics of the platforms.

    3. Async does not equal flows. If complex calculations are required, Web Workers should be used.

    4. Keep an eye on official bugs. We had a case when an Android app was lagging, and within 4-5 seconds after transition to another screen the app stopped responding altogether. The official repository had an issue, and we found a solution in a matter of minutes.



    So which one fits your project better – ReactNative or NativeScript?


    ReactNativeReactNative – you need a tool to create a rather simple app and launch it quickly on the market. As the software product owner, you might leave out a couple of ideas regarding design or functionality in case there is no corresponding plugin for a needed component or feature. ReactNative works best if your software product stands out not with its design, but rather with the business logic.


    NativeScriptNativeScript – requires more effort to ensure responsiveness for the end user—the same responsiveness that is achieved in ReactNative with Web Workers in case of complex calculations. In return, you get absolute control over any native functionality and high level of customization of any control directly from JS code. Your developer does not need to know Objective-C or Java to write a new plugin or a wrapper for a 3rd-party native library. What's more, it's possible to extend classes of native components using JS.


    These two tools address different cases and have different pros and cons.



    Useful links


    Here is a list of useful links. We'd recommend the official documentation as a great start.


    nativescript.org

    docs.nativescript.org

    hybridtonative.com

    nativescript.github.io

    nativescript.org

    developer.telerik.com/featured/nativescript-a-technical-overview

    developer.telerik.com/featured/nativescript-works

    developer.telerik.com/featured/nativescript-android

    github.com/NativeScript/sample-iOS-Profiling/tree/performance-tests

    developer.telerik.com/featured/benefits-single-threading-model-nativescript

    quora.com/What-are-the-key-difference-between-ReactNative-and-NativeScript/answer/Valentin-Stoychev

    github.com/NativeScript/NativeScript/issues/1563

    medium.com/@enchev/extend-your-existing-android-app-with-angular-2-and-nativescript

    github.com/NativeScript/docs/blob/master/publishing/creating-launch-screens-android




    Yurii Luchaninov


    Based on a keynote contributed to KharkivJS #7 2016
    by Yurii Luchaninov, HTML/ JS Group Leader at MobiDev.


    Read more:
    scroll top