Tuesday, December 8, 2015

Building Mobile Apps with Angular 2 and NativeScript


Hi! I’m TJ from the NativeScript team at Telerik. We’ve been working with the Angular team for the greater part of this year to integrate Angular 2 into NativeScript, which together let you write native iOS and Android apps using your existing web and Angular knowledge. In this article I’m going to cover what NativeScript is, why we’re using Angular, and how it all works. If you’re interested, read on!

What’s NativeScript?

NativeScript is an open source JavaScript framework that lets you build native mobile apps from a single code base. NativeScript works by leveraging JavaScript virtual machines—e.g. JavaScriptCore and V8—to create a bridge between the JavaScript code you write and the native APIs used to drive the native application. As a quick example check out the following code:

var myAlert = new UIAlertView();
myAlert.message = "NativeScript rocks!";
myAlert.show();

This is JavaScript code, yet NativeScript instantiates the Objective-C-based iOS UIAlertView control shown below:


And because we know that no web developer wants to learn iOS- and Android-specific APIs like UIAlertView, we offer a large suite of JavaScript modules that abstract the iOS and Android details into simple-to-use JavaScript APIs. For instance, the UIAlertView-based code block above could be rewritten using the NativeScript dialogs module:

var dialogs = require("ui/dialogs");
dialogs.alert({ message: "NativeScript rocks!" });

This same dialogs.alert() call also gives you the following android.app.AlertDialog for your Android app:

Although the dialog example is purposely simple, this same technique can be used to build incredibly robust and gorgeous apps, by utilizing the native iOS and Android UI components that are already available and mature. The best way to see what’s possible with NativeScript is to download our kitchen sink app on your iOS or Android device. You can also peruse our showcase page to see some of the many NativeScript-built apps in the app stores already.

Where does Angular come in?

One of our guiding principles when building NativeScript was to allow developers to leverage their existing skills. As such, NativeScript lets you write your app logic in JavaScript or TypeScript, style your app using a subset of CSS, leverage npm modules, and even use native iOS and Android libraries. So, it seemed logical for us to extend this skill reuse to another library developers know and love: Angular!

At Telerik we’ve long been fans of Angular. We first shipped Angular integration in our popular Kendo UI library nearly two years ago, and we continue to see a ton of demand for Angular from our community. But integrating Angular 1 into NativeScript was impossible, as Angular 1 was tightly coupled to the DOM.... and in NativeScript there is no DOM or browser; NativeScript UIs are native UIs.

Enter Angular 2.

One of Angular 2’s biggest architectural changes was decoupling the Angular framework from the DOM. Whereas Angular 1 was limited to browser-based environments, Angular 2 opened the door a number of different rendering possibilities, including NativeScript. And since earlier this year, we’ve been holding weekly meetings with the Angular team to turn this vision into a reality.

How does it work?

If you know Angular 2, you already know a lot of what you need to know to use Angular 2 in NativeScript. The one big difference is that browser-based elements such as <div> and <span> are not available—instead, you must use NativeScript’s UI components to build your interfaces. Let’s look at an example.

NativeScript apps are primarily made up of three types of files: JavaScript or TypeScript files (for logic), XML files (for defining UI components), and CSS files (for styling). If you create one of each of these files with the same name—e.g. main.js, main.xml, and main.css—NativeScript knows to use the files as a unit. For instance, here’s the full code you need to build the dialog example presented earlier in this article—notice the use of `"loaded"` to tie the XML and JavaScript files together.

<!-- main.xml -->
<page loaded="loaded"></page>

/* main.js */
var dialogs = require("ui/dialogs");
exports.loaded = function() {
    dialogs.alert({ message: "NativeScript rocks!" });
};

Normally in a NativeScript app, your next step would be adding a bunch of UI components to your <page> in main.xml—components like <slider><switch>, and <tab-view>. But with Angular 2 in the picture you can build your UI using the Angular 2 component APIs. Here’s an updated version of main.js (this time built with TypeScript), that shows how to build a “Hello World” page with NativeScript and Angular 2. Look over the code below quickly, and then we’ll break it down in detail.
Note: Using Angular 2 in NativeScript currently requires TypeScript, which is why I’m writing the code below in TypeScript rather than JavaScript. In a future release we will remove this limitation and let you use JavaScript directly.
// main.ts
import {nativeScriptBootstrap} from "nativescript-angular/application";
import {Component, View} from "angular2/angular2";

@Component({})
@View({
  directives: [],
  template: `
    <stack-layout>
      <button text="Hello World"></button>
    </stack-layout>
  `
})
class HelloPage {}

export function loaded() {
  nativeScriptBootstrap(HelloPage);
}

If you’ve built anything with Angular 2 before most of this code will look familiar. There are really only two differences to note:
  • nativeScriptBootstrap() vs. bootstrap()
    • In an Angular 2 web app, you call the bootstrap() function in the "angular2/angular2" module to initialize your components. In NativeScript apps you need to call nativeScriptBootstrap(), which is a lightweight wrapper of bootstrap() that does some NativeScript-specific initialization.
  • The UI components in the template
    • In an Angular 2 web app your “Hello World” button example would probably be rendered as <div><button>Hello World</button></div>. But in NativeScript apps you need to use XML widgets that NativeScript is able to render in native mobile apps. This example uses a <stack-layout> element, which is the simplest of NativeScript’s layouts, and places a single <button> element within it. Here’s how those controls render on iOS and Android.


         

What else can you do?

Once you have the basics down you can really start to leverage your existing web and Angular skills. For instance, want to change the look of your button? Just apply any of NativeScript’s supported CSS properties. For instance, if I add button { color: red; } to my app’s main.css file, I get a button that looks like this:

         

Want to add some behavior to the button? Just add a tap handler using Angular 2’s event binding mechanism. The following code alters the previous main.ts example to show an alert when the app’s button is tapped:

import {nativeScriptBootstrap} from "nativescript-angular/application";
import {Component, View} from "angular2/angular2";
import {dialogs} from "ui/dialogs";

@Component({})
@View({
    directives: [],
    template: `
        <stack-layout>
            <button
              (tap)="showAlert()"
              text="Hello World"></button>
        </stack-layout>
    `
})
class HelloPage {
    showAlert() {
        dialogs.alert({ message: "NativeScript rocks!" });
    }
}

export function loaded() {
    nativeScriptBootstrap(HelloPage, []);
}

There’s a whole lot more you can do in a NativeScript app—like using npm install to add JavaScript utility libraries to your app, installing NativeScript plugins to add some powerful native functionality, or trying out NativeScript’s rich animation APIs to move UI elements around the screen—but let’s take a minute to step back and consider why we’re taking this approach to building apps in the first place.

The benefits of using NativeScript and Angular 2


The examples presented in this article have been purposely simple to introduce basic concepts, but think of how much work you’d have to do to build these simple Android and iOS apps using traditional native development approaches. For iOS you’d have to launch Xcode, drag a UIButton control onto a Storyboard, figure how to change that button’s text, and use outlets in Xcode to tie your button to an event handler written in Objective–C or Swift. On Android you’d have to figure out how to accomplish the same tasks in a completely different environment (Eclipse or Android Studio).

With NativeScript and Angular 2 you can build that same button in a few lines of code; you can write that code in JavaScript/TypeScript; you can place that button in an Angular 2 component; you can style that button with CSS; you can install JavaScript modules to help you out from npm; and at the end of the day you only have one code base to maintain. This is why we’re excited about NativeScript—it brings a familiar web tool set to the native app world.

And it gets even better. In addition to skill reuse—aka being able to write native apps with JavaScript—using Angular 2 in NativeScript opens up one other cool possibility: the ability to share code between your web and native apps. After all, NativeScript code is just JavaScript code, so as long as that code isn’t tied to the DOM, there’s no reason that code can’t run in NativeScript. And with Angular 2 support coming to NativeScript, you even have the potential to share your Angular components. Let’s look at an example.

Sharing code between web and mobile apps


Suppose you need to write a simple checkbox component for your next Angular app. For your web app you might use the following TypeScript to implement the component:

import {Component, View, EventEmitter} from "angular2/angular2";

@Component({
    selector: "checkbox",
    templateUrl: "checkbox.html",
    input: ["checked"],
    output: ["click"]
})
export class Checkbox {
    public click: EventEmitter = new EventEmitter();
    public checked: boolean = false;

    public onClick(): void {
        this.click.next(this.checked);
    }
}

Above I define a component with a single checked input (or property) and a single click output (or event). I use Angular’s templateUrl option to define the component’s template in an external file named checkbox.html. That file contains the following HTML:

<input type="checkbox" [checked]="checked" (click)="onClick()">

Here’s where things get cool though. Now suppose that you want to make this component work on your NativeScript iOS and Android apps. What code would you have to change?

Only the template.

Seriously, that’s it. All you need to do is define how your component gets rendered on each platform—web and native. For instance, continuing the previous example, to get this code working in NativeScript you only need to swap out the contents of checkbox.html. The version of the template below uses the NativeScript <switch> widget:

<switch [checked]="checked" (tap)="onClick()"></switch>

By using two different templates, your component can now render on three platforms—the web, iOS, and Android. Here’s what that looks like visually:


It gets even better. NativeScript actually includes support for a few common web APIs, most notably XMLHttpRequest and fetch() This support means you can write your components for the web, and let NativeScript translate these APIs to native code for your mobile apps. As one example, because of NativeScript’s XMLHttpRequest support, Angular 2’s HTTP component works out of the box in NativeScript already. Here’s what that looks like visually:


Obviously not all code makes sense to share across all platforms, and you’ll certainly want to fork your code in places to handle individual platforms separately. But at the very least NativeScript and Angular can help you share code for the mundane things in your app—such HTTP calls and model objects—and in certain cases you may want to share entire interfaces.

We’re excited about the potential this architecture provides to the Angular world, and we can’t wait to see what you build with it.

Awesome! When will this be ready?

Our Angular integration is currently in an alpha state, much like Angular 2 itself. If you’re the type of developer that likes digging in early, head to https://github.com/NativeScript/nativescript-angular and follow the instructions in the README to get up and running. You may also want to check out our TodoMVC example, or Sebastian Witalec’s presentation on NativeScript and Angular 2 from Angular Connect—each have more advanced examples of NativeScript and Angular 2 in action.

Long term, our Angular integration will roughly follow Angular 2’s own release schedule; therefore, you can expect a stable release of NativeScript’s Angular integration around Angular 2’s own stable release date.

But although NativeScript’s Angular integration is in an alpha state, NativeScript itself is a production-ready framework being used to develop a wide variety of apps today. If you’re interested in learning more, take an hour and go through the NativeScript getting started guide. You’ll build a functioning iOS and Android app, and learn whether NativeScript makes sense for your next development project.

If you want to keep up to date with the latest with our Angular integrations, bookmark our weekly meeting notes document, and follow @nativescript on Twitter for updates. If you’re looking for help, or want to chat with others in the NativeScript community, head over to our Google Group. Overall, we’re excited about bringing Angular 2 to a new mobile world, and we hope you are too.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.