Comparing Cordova, Nativescript, Ionic, Xamarin and React Native Architectures

  • Cordova
    • Plugins comprise a single JavaScript interface along with corresponding native code libraries for each supported platform. In essence this hides the various native code implementations behind a common JavaScript interface.
    • Once you define JavaScript for your plugin, you need to complement it with at least one native implementation.

  • Ionic
    • Ionic apps are built with Cordova. Cordova is a means of packaging html/css/js into apps that can run on mobile and desktop devices and provides a plugin architecture for accessing native functionality beyond the reach of JS run from a web browser. As such, Ionic apps have the Cordova file structure.
    • Ionic uses Angular 2 for it’s App code in Angular 2, and for any native features access, it uses Cordova.
    • Ionic Native is a curated set of ES5/ES6/TypeScript wrappers for Cordova/PhoneGap plugins that make adding any native functionality you need to your Ionic, Cordova, or Web View mobile app easy.
  •  NativeScript
    • The difficultly of accessing native APIs in Cordova is one of the reasons we built NativeScript, and why designed NativeScript to give you direct access to iOS and Android APIs in your JavaScript or TypeScript code. This direct access negates the entire need to write a plugin to access features of the underlying native platforms. For instance, you can recreate the entirety of Max’s Android getDate()call with one line of code in your NativeScript app: (new java.util.Date()).toString();
    • V8 engine has hooks that make possible for NativeScript to inject a global android object. This is actually the same mechanism Node.js uses to make its global APIs available – e.g. require() – and NativeScript uses it to inject APIs that let you access native code. JavaScriptCore has a similar mechanism that makes the same technique possible for iOS.
    • NativeScript uses reflection to build the list of the APIs that are available on the platform they run on. reflection is what lets NativeScript build a comprehensive list of APIs for each platform, including android.text.format.Time. Because generating this data is non-trivial from a performance perspective, NativeScript does it ahead of time, and embeds the pre-generated metadata during the Android/iOS build step.
    • For example, the code new android.text.format.Time() invokes a JavaScript function, which V8 has a callback for. That is, V8 has a callback that lets NativeScript intercept the function call, take some action with custom C++ code, and provide a new result.
    • In the case of Android, the NativeScript runtime’s C++ code cannot directly access Java APIs such as android.text.format.Time. However, Android’s JNI, or Java Native Interface, provides the ability to bridge between C++ and Java, so NativeScript uses JNI to make the jump. On iOS this extra bridge is unnecessary as C++ code can directly invoke Objective-C APIs.
    • Modules:
      • Think of NativeScript modules as Node modules that depend on the NativeScript runtime. NativeScript modules follow the same CommonJS conventions as Node modules, so if you already know how require() and the exports object work, then you already know how NativeScript modules work.
      • NativeScript modules allow you to abstract platform-specific code into a platform-agnostic API, and NativeScript itself provides several dozens of these modules for you out of the box. As an example, suppose you need to create a file in your iOS/Android app. You could write the following code for Android:
        new path );

        As well as the following code on iOS:

        fileManager.createFileAtPathContentsAttributes( path );

        But you’re better off just using the NativeScript file-system module, as it lets you write your code once, without having to worry about the iOS/Android internals:

        var fs = require( "file-system" );
        var file = new fs.File( path );

        The NativeScript modules also support TypeScript as a first-class citizen; therefore, you could optionally write the code in TypeScript if you prefer:

        import {File} from "file-system";
        let file = new File( path );
      • the NativeScript layout mechanisms and UI elements are nothing more than NativeScript modules that use the NativeScript runtime. A  is implemented as a button NativeScript module that leverages the android.widget.Button and UIButton APIs under the hood.

        If you want to try NativeScript out, the best to place to start is with our JavaScript Getting Started Guide, or our TypeScript & Angular Getting Started Guide. The guides will walk you through building a NativeScript app from scratch, and you’ll get hands-on experience using the native API access that this article discussed. Happy NativeScript-ing!

Image result for nativescript architecture

  • React Native
    • Unlike in Nativescript, where you call the Android APIs directly from JS, in React Native, you need to create your own Native wrappers around Android/IOs APIs, which you then annotate to indicate to React Native that these Native methods can be called from JS.
    • The UI Components here work the same as in NativeScript. For instance, when you use <ScrollView>, On iOS, a React Native ScrollView uses a native UIScrollView. On Android, it uses a native ScrollView.
    • React Native combines smoothly with components written in Objective-C, Java, or Swift. Eg.
      • import { TheGreatestComponentInTheWorld } from ‘./your-native-code’;
      • use in template: <TheGreatestComponentInTheWorld />
    • React Native is a hybrid creature, running on two realms on iOS (JScorevirtual machine for JS, and native runtime for ObjC/swift) and three realms on Android (JSCore, Android runtime for java, and native runtime for C/C++)
    • MessageQueue.js, the final frontier between JS and native, this is where all the communication between the two is being handled. Messages look a bit like JSON-RPC, passing method calls from JavaScript to native, and callbacks from native back to JavaScript. This is the sole connection between the JavaScriptcontext and the native context. Everything is being passed through MessageQueue, every network request, network response, layout measurement, render request, user interaction, animation sequenceinstructions, invocation of native modules, I/O operation, you get the idea… Making sure MessageQueue isn’t congested is critical in order to ensure a smooth operation of our app.
    • Write Custom Native Modules in Native Languages

Diagram illustrating React Native's runtime architecture

  • Xamarin
    • Xamarin is cross platform because it uses a language (C#) that can be compiled to the native code (roughly speaking) of various different target architectures, and it includes interfaces with Android, iOS, and other platforms.
    • It’s not that different from why a program written in C or C++ (or any of a dozen other compiled languages) can be compiled to run on multiple platforms (including Android and iOS — native languages notwithstanding).
    • Xamarin goes farther than C or C++ in allowing developers to create code in a cross-platform manner by adding direct interfaces between C# and native APIs. They also add their own library layer that allows you to create cross-platform user interface components. If you’re using C or C++ on Android or iOS, you typically have to go through either Java or Objective-C to talk to the native APIs, respectively. (With some exceptions.)
    • Xamarin.Android applications run within the Mono execution environment (written in C and so easily compiled to iOS and Android). This execution environment runs side-by-side with the Android Runtime (ART) virtual machine. Both runtime environments run on top of the Linux kernel and expose various APIs to the user code that allows developers to access the underlying system. The Mono runtime is written in the C language.

      You can be using the System, System.IO, System.Net and the rest of the .NET class libraries to access the underlying Linux operating system facilities.

      On Android, most of the system facilities like Audio, Graphics, OpenGL and Telephony are not available directly to native applications, they are only exposed through the Android Runtime Java APIs residing in one of the Java.* namespaces or the Android.* namespaces. The architecture is roughly like this:

      Xamarin.Android developers access the various features in the operating system either by calling into .NET APIs that they know (for low-level access) or using the classes exposed in the Android namespaces which provides a bridge from c# wrapper to the Java APIs that are exposed by the Android Runtime.

      For more information on how the Android classes communicate with the Android Runtime classes see the API Designdocument.

    • Xamarin.Forms

      Xamarin.Forms lets you apply even more of the code between apps for different devices. Forms is built on XAML, which is familiar to most .NET developers, and it essentially renders native controls so each interface looks like it belongs on the platform. With Forms, more than 90% of the code you write for an app on one type of device will work on the versions for the other types of device. You may not be able to make full use of all of each device’s unique features, so in some instances you’ll still want to use Xamarin.iOS and Xamarin.Android. But for most line-of-business apps, Forms will be a great deal quicker and a great deal cheaper to work with.

    • The C# source makes its way into a native app in very different ways on each platform:
      • iOS – C# is ahead-of-time (AOT) compiled to ARM assembly language. The .NET framework is included, with unused classes being stripped out during linking to reduce the application size. Apple does not allow runtime code generation on iOS, so some language features are not available (see Xamarin.iOS Limitations ).
      • Android – C# is compiled to IL and packaged with MonoVM + JIT’ing. Unused classes in the framework are stripped out during linking. The application runs side-by-side with Java/ART (Android runtime) and interacts with the native types via JNI (see Xamarin.Android Limitations ).
      • Windows – C# is compiled to IL and executed by the built-in runtime, and does not require Xamarin tools. Designing Windows applications following Xamarin’s guidance makes it simpler to re-use the code on iOS and Android. Note that the Universal Windows Platform also has a .NET Native option which behaves similarly to Xamarin.iOS’ AOT compilation.

      The linker documentation for Xamarin.iOS and Xamarin.Android provides more information about this part of the compilation process.

      Runtime ‘compilation’ – generating code dynamically with System.Reflection.Emit – should be avoided.

      Apple’s kernel prevents dynamic code generation on iPhone and iPad, therefore emitting code on-the-fly will not work in Xamarin.iOS. Likewise, the Dynamic Language Runtime features cannot be used with Xamarin tools.

      Some reflection features do work (eg. MonoTouch.Dialog uses it for the Reflection API), just not code generation.

      Platform SDK Access

      Xamarin makes the features provided by the platform-specific SDK easily accessible with familiar C# syntax:

      • iOS – Xamarin.iOS exposes Apple’s CocoaTouch SDK frameworks as namespaces that you can reference from C#. For example the UIKit framework that contains all the user interface controls can be included with a simple using MonoTouch.UIKit; statement.
      • Android – Xamarin.Android exposes Google’s Android SDK as namespaces, so you can reference any part of the supported SDK with a using statement, such as using Android.Views; to access the user interface controls.
      • Windows – Windows apps are built using Visual Studio on Windows. Project types include Windows Forms, WPF, WinRT, and the Universal Windows Platform (UWP).

      Seamless Integration for Developers

      The beauty of Xamarin is that despite the differences under the hood, Xamarin.iOS and Xamarin.Android (coupled with Microsoft’s Windows SDKs) offer a seamless experience for writing C# code that can be re-used across all three platforms.

      Business logic, database usage, network access and other common functions can be written once and re-used on each platform, providing a foundation for platform-specific user interfaces that look and perform as native applications.


Leave a Reply

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

You are commenting using your 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 )

Google+ photo

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

Connecting to %s