神刀安全网

Converting Your Ionic 2 Mobile App To NativeScript

As many of you know, I had been using Apache Cordova based frameworks such as Ionic Framework for a long time.  They are convenient and easy to use when it comes to rapidly developing cross platform applications.  The problem with using Apache Cordova frameworks such as PhoneGap, Ionic Framework and Onsen UI is the performance limitations that come with them, particularly because of their use of the platform web view.

NativeScript is a mobile development platform that I recently switched to because it eliminates the performance issues that people experience with web view based frameworks.  This is because it doesn’t render your application in a web view.  Instead the application gets compiled to native code giving the same performance you’d see in an app that was developed with Objective-C or Java.

Being that I spent a long time with Ionic Framework and Ionic 2, which uses AngularJS and Angular 2 , I figured it would make sense to show how easy it is to convert your application to NativeScript, which also uses Angular 2.  As an end result you’ll get a cross platform web application, built with a modern framework, that is native.

To make this tutorial as easy as possible to follow, we’re first going to create an application using Ionic 2.  This application will allow you to add items to a list and navigate between pages.  Then we’re going to take this same application and convert it to NativeScript.

Converting Your Ionic 2 Mobile App To NativeScript

Building a Mobile App with Ionic 2

We’re going to assume you already have the Ionic 2 CLI and other build tools installed on your computer.  Let’s go ahead and start a new Ionic 2 project.  Using your Command Prompt (Windows) or Terminal (Mac and Linux), execute the following:

ionicstartIonicProjectblank --v2 --typescript cd IonicProject ionicplatformaddios ionicplatformaddandroid 

A few things to note above.  We’re going to be creating an Ionic 2 project that uses TypeScript rather than vanilla JavaScript.  Also note that if you’re not using a Mac you cannot build for the iOS platform.

This is going to be a two page application.  In the default template there is one page found at app/pages/home that we are not going to use.  Instead we’re going to create the following:

mkdir app/pages/list mkdir app/pages/create touch app/pages/list/list.html touch app/pages/list/list.ts touch app/pages/list/list.scss touch app/pages/create/create.html touch app/pages/create/create.ts touch app/pages/create/create.scss 

I’m using a Mac so I can make use of the mkdir and  touch commands.  If you’re using Windows, just go ahead and create those files and directories.

Before we start coding each of the pages, let’s add each of our scss files to the theme.  Open the project’s  app/theme/app.core.scss file and include the following two lines:

@import '../pages/list/list'; @import '../pages/create/create'; 

Remove any lines referring to the old and unused home page.

Creating the List Page

This application is going to have a simple list view for showing people that have been added.  Let’s start by developing our application logic.  Open the project’s app/pages/list/list.ts file and include the following code.  Don’t worry, we’re going to break it down:

import {Page, NavController} from "ionic-angular"; import {CreatePage} from "../create/create";   @Page({     templateUrl: "build/pages/list/list.html" }) export class ListPage {       privatenav: NavController;     publicitems: Array<Object>;       constructor(nav: NavController) {         this.nav = nav;     }       onPageDidEnter() {         this.items = localStorage.getItem("items") != null ? JSON.parse(localStorage.getItem("items")) : [];     }       navigateToCreate() {         this.nav.push(CreatePage);     }   } 

The first two lines will allow us to import the appropriate classes and components.  The CreatePage component is something we’re going to create and doesn’t exist as of now.

The page template will refer to the HTML file that exists in the same directory as our logic file.  We haven’t created it yet, but will when we’re done with the logic.

Inside the class we are defining a private nav variable that will allow us to navigate to the creation page and a public  items array that will be bound to the UI.  Inside the  constructor method we initialize the navigation controller.

onPageDidEnter() {     this.items = localStorage.getItem("items") != null ? JSON.parse(localStorage.getItem("items")) : []; } 

The above onPageDidEnter method is a reserved method in Ionic.  Every time the page is entered, whether that be from a navigation push or a navigation pop, the code will execute.  This is useful because when navigating back via a pop, the constructor is not called.  Inside this method we read and parse the saved list of people.

For the Ionic 2 application we are using the browser based local storage.  You’ll notice we do something slightly different in the NativeScript version.

The final function being the navigateToCreate will allow us to navigate to the creation page.

With the TypeScript code out of the way, we can focus on the small bit of UI.  Open the project’s app/pages/list/list.html file and include the following markup:

<ion-navbar*navbar>     <ion-title>Ionic 2 - Home</ion-title>     <ion-buttonsend>         <button(click)="navigateToCreate()">Add</button>     </ion-buttons> </ion-navbar>   <ion-contentclass="list">     <ion-list>         <ion-item*ngFor="let item of items">             {{ item.firstname }} {{ item.lastname }}         </ion-item>     </ion-list> </ion-content> 

The UI has a navigation button in the header and a list view as the core content.  Each row of the list will be an object from the items array that was created in the TypeScript file.

Creating the Page for New Content

With the first page out of the way, we can create the second page.  It will have a form that allows us to save data to be displayed in the list view.  Like previously mentioned, we are using local storage for saving data.

Let’s start this page by working with the TypeScript file.  Open the project’s app/pages/create/create.ts file and include the following code:

import {Page, NavController} from "ionic-angular";   @Page({     templateUrl: "build/pages/create/create.html" }) export class CreatePage {       privateitems: Array<Object>;     privatenav: NavController;     publicfirstname: string;     publiclastname: string;       constructor(nav: NavController) {         this.nav = nav;         this.items = localStorage.getItem("items") != null ? JSON.parse(localStorage.getItem("items")) : [];         this.firstname = "";         this.lastname = "";     }       save() {         if(this.firstname != "" && this.lastname != "") {             this.items.push({firstname: this.firstname, lastname: this.lastname});             localStorage.setItem("items", JSON.stringify(this.items));             this.nav.pop();         }     }   } 

Like with the previous page we are importing certain classes and components and defining the template to be used.  The constructor method will initialize our variables.  Since this page will never be accessed via a  pop event we don’t need to have an  onPageDidEnter method.  We can load from our local storage directly from the  constructor method.

The save method in this page is where the magic happens.

In this case we check to make sure firstname and  lastname are set.  If they are, add them to the  items array and serialize the array so it can be saved to local storage.  When done, we can navigate back to the previous page.

Now we can take a look at the UI that goes with this particular page.  Open the project’s app/pages/create/create.html file and include the following markup:

<ion-navbar*navbar>     <ion-title>Ionic 2 - Create</ion-title>     <ion-buttonsend>         <button(click)="save()">Save</button>     </ion-buttons> </ion-navbar>   <ion-contentclass="create">     <ion-list>         <ion-item>             <ion-inputtype="text" placeholder="First Name" [(ngModel)]="firstname"></ion-input>         </ion-item>         <ion-item>             <ion-inputtype="text" placeholder="Last Name" [(ngModel)]="lastname"></ion-input>         </ion-item>     </ion-list> </ion-content> 

Like with the first page, there is a button in the header.  More important is the form that exists in the content.  There are two fields and they are bound to the TypeScript file via the Angular 2 [(ngModel)] tag.  With the variables bound, they can be saved when we click the  save button.

Fixing the Routing File

Since we’re not using the stock home page, we need to fix up the routing file.  Open the project’s  app/app.ts file and include the following code:

import {App, Platform} from 'ionic-angular'; import {StatusBar} from 'ionic-native'; import {ListPage} from './pages/list/list';   @App({     template: '<ion-nav [root]="rootPage"></ion-nav>',     config: {} }) export class MyApp {       rootPage: any = ListPage;       constructor(platform: Platform) {         platform.ready().then(() => {             StatusBar.styleDefault();         });     }   } 

The only thing that really changed here is that we changed HomePage to  ListPage wherever it occurs.

The Ionic 2 app that we’re going to convert is now finished.  If you’d like to download the project, clickhere.

Building a Mobile App with NativeScript

The Ionic 2 project wasn’t too difficult to make.  You’ll notice that it contains a lot of proprietary components in it, such as how navigation is done, or the particular markup tags. NativeScript is more vanilla to how Angular 2 operates.  This means that your Angular 2 code can be more easily migrated to a web application.  The UI is still proprietary, but this time it gets compiled to native UI components which again is great for performance.

Let’s start building our project.  We’re going to assume you already have the NativeScript CLI installed at this point.  Using your Command Prompt (Windows) or Terminal (Mac and Linux), execute the following:

tnscreateNativeScriptProject --ng cd NativeScriptProject tnsplatformaddios tnsplatformaddandroid 

There are a few things you should note here.  By using the --ng tag we are creating an Angular 2 project that uses TypeScript.  Also note that if you’re not using a Mac you cannot build for iOS.

Like with the Ionic 2 application, the NativeScript version will be a two page application.  This time however, instead of pages we’re going to refer to them as components.  This is how Angular 2 intended pages to be called.  Let’s go ahead and create the necessary files and directories:

mkdir app/components mkdir app/components/list mkdir app/components/create touch app/components/list/list.component.ts touch app/components/list/list.xml touch app/components/create/create.component.ts touch app/components/create/create.xml 

Again I’m using a Mac which lets me create files and directories from my Terminal using mkdir and  touch .  If you’re using Windows, go ahead and create them however you see fit.

The default NativeScript Angular 2 template comes with a bunch of CSS that we don’t necessarily want for our project.  Open the project’s app/app.css file and remove everything that is in there.

Now we can start developing each of our components.

Creating the List Component

Remember how we created the list page for Ionic 2?  It is going to be near identical in NativeScript.  The core difference is that we’re going to use actual Angular 2 components and classes rather than proprietary Ionic 2 components.

Starting with the logic that exists in our TypeScript file, open the project’s app/components/list/list.component.ts file and include the following code:

import {Component} from "@angular/core"; import {Router} from "@angular/router-deprecated"; import {Location} from "@angular/common"; import * as ApplicationSettingsfrom "application-settings";   @Component({     selector: "list",     templateUrl: "./components/list/list.xml", }) export class ListComponent {       privaterouter: Router;     publicitems: Array<Object>;       constructor(router: Router, location: Location) {         this.router = router;         this.items = JSON.parse(ApplicationSettings.getString("items", "[]"));         location.subscribe((path) => {             this.items = JSON.parse(ApplicationSettings.getString("items", "[]"));         });     }       navigateToCreate() {         this.router.navigate(["Create"]);     }   } 

The first three imports are directly out of the Angular 2 documentation.  This means that we could use most of this code in a web application if we wanted to.

The last import is a bit different though.  Since this is a native application and doesn’t use a web browser or the DOM, we don’t have access to local storage.  Instead we can make use of application-settings which behaves in nearly the same way.

You’ll notice that we’re defining our template as the soon to be created app/components/list/list.xml file.  That will come next.  Inside the  ListComponent class we define a private variable for routing and a public variable that will allow us to bind our list to the UI.

The constructor method is slightly different from what we saw in Ionic 2:

constructor(router: Router, location: Location) {     this.router = router;     this.items = JSON.parse(ApplicationSettings.getString("items", "[]"));     location.subscribe((path) => {         this.items = JSON.parse(ApplicationSettings.getString("items", "[]"));     }); } 

With vanilla Angular 2, we don’t have the onPageDidEnter method that Ionic 2 was using to detect navigation and return events.  Instead we have to subscribe to them using the  Location component.  In reality it isn’t much different and not any more difficult.  You’ll also notice that the use of  ApplicationSettings isn’t much different than the use of local storage.

The final method in this file will navigate us to the component for creating data.  Navigation happens using the Angular 2 router that we’ll configure after designing our components.

With the logic out of the way, it is time to look at the UI that will be paired with it.  Open the project’s app/components/list/list.xml file and include the following markup:

<ActionBartitle="NativeScript - Home">     <ActionItemtext="Add" (tap)="navigateToCreate()" ios.position="right"></ActionItem> </ActionBar> <GridLayout>     <ListView[items]="items">         <templatelet-item="item">             <Label[text]="item.firstname + ' ' + item.lastname"></Label>         </template>     </ListView> </GridLayout> 

Like with Ionic 2, NativeScript has its own proprietary markup.  The core difference is that this markup gets compiled to native UI code in the end.

At the top of this file we are defining an action bar with a single button.  This button will call the navigateToCreate method that we created for navigating to the next component.

The core content of this component is the ListView .  We tell it to bind to the  items array that we created in the TypeScript file and to loop through it where each item in the array should be called  item .  Using  item we can access the properties that exist in each of the objects and display them on the row with a  Label tag.

Although different syntax, it isn’t too different than what we saw with Ionic 2.

Creating the Component for Adding New Data

Now we can focus on our second component, the one for creating new data for the list component.  Again, you’ll notice many similarities between the Ionic 2 version and the NativeScript version.

Starting with the TypeScript file, open the project’s app/components/create/create.component.ts file and include the following code:

import {Component} from "@angular/core"; import {Location} from "@angular/common"; import * as ApplicationSettingsfrom "application-settings";   @Component({     selector: "create",     templateUrl: "./components/create/create.xml", }) export class CreateComponent {       privatelocation: Location;     privateitems: Array<Object>;     publicfirstname: string;     publiclastname: string;       constructor(location: Location) {         this.location = location;         this.items = JSON.parse(ApplicationSettings.getString("items", "[]"));         this.firstname = "";         this.lastname = "";     }       save() {         if(this.firstname != "" && this.lastname != "") {             this.items.push({firstname: this.firstname, lastname: this.lastname});             ApplicationSettings.setString("items", JSON.stringify(this.items));             this.location.back();         }     }   } 

We start by importing the appropriate Angular 2 components and the NativeScript application-settings component.  We define the XML UI file that will pair with the TypeScript file and define all of our variables in the  constructor method.  No surprises as of now.

In the save method we make sure the  firstname and  lastname variables are not empty and then save them to storage.  When this has completed we navigate back in the navigation stack.

Now we can take a look at the XML file that is paired with the logic code.  Open the project’s app/components/create/create.xml file and include the following markup:

<ActionBartitle="NativeScript - Create">     <NavigationButtontext="Back" ios.position="left"></NavigationButton>     <ActionItemtext="Save" (tap)="save()" ios.position="right"></ActionItem> </ActionBar> <StackLayout>     <TextFieldhint="First Name" [(ngModel)]="firstname"></TextField>     <TextFieldhint="Last Name" [(ngModel)]="lastname"></TextField> </StackLayout> 

In the UI we create an action bar with potentially two buttons.  iOS does not have hardware or software back buttons like Android, so we must create a navigation button for navigating back in the stack.  We also create a button for saving our data.

Just like with Ionic 2 we make use of [(ngModel)] , not because it is part of NativeScript or Ionic 2, but because it is the Angular 2 thing to do for binding data to a TypeScript class.

Defining the Application Routes

This is where things can get a little different.  Up until now, with the exception of minor framework differences, the Angular 2 code between the frameworks have been pretty much the same.  Ionic 2 does its own voodoo when it comes to navigation between pages or components.  This is not vanilla Angular 2.  NativeScript does navigation the Angular 2 way.  This means we need a core routing file.

Open your project’s app/app.component.ts file and include the following code:

import {Component} from "@angular/core"; import {RouteConfig} from "@angular/router-deprecated"; import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "nativescript-angular/router";   import {ListComponent} from "./components/list/list.component"; import {CreateComponent} from "./components/create/create.component";   @Component({     selector: "my-app",     directives: [NS_ROUTER_DIRECTIVES],     providers: [NS_ROUTER_PROVIDERS],     template: "<page-router-outlet></page-router-outlet>" }) @RouteConfig([     { path: "/list", component: ListComponent, name: "List", useAsDefault: true },     { path: "/create", component: CreateComponent, name: "Create" }, ]) export class AppComponent {   } 

In this file we define all components used in our application.  You can see we define both the ListComponent and  CreateComponent in this file.

In the @RouteConfig we can define how to access these components.  The  ListComponent is the default component, while the  CreateComponent can be accessed by trying to navigate to  Create .

Fixing the Bootstrap for the iOS Platform

Since we are using the action bar in our NativeScript UIs, we need to make a revision to how the application is bootstrapped so it will work properly with iOS.  Lucky for us, this isn’t complicated to do.

Open the project’s app/main.ts file and include the following code:

import {nativeScriptBootstrap} from "nativescript-angular/application"; import {AppComponent} from "./app.component";   nativeScriptBootstrap(AppComponent, null, { startPageActionBarHidden: false }); 

As you can see, the only difference from the original is the { startPageActionBarHidden: false } part.  With that altered, it should work fine now.

The Ionic 2 application has now been converted to NativeScript.  If you’d like to see the full project, it can be downloadedhere.  Using  application-settings isn’t the only way to store data in NativeScript.  I chose it because it was most relatable to local storage.  I have other tutorials on how to useSQLite or Couchbase NoSQL for data storage.

Conclusion

We just saw how to take an Ionic 2 application that is based on Apache Cordova and convert it into a fully native NativeScript mobile application.  Both Ionic 2 and NativeScript use Angular 2 with the core difference being in the fact that you are left with a native application with NativeScript rather than an app that runs in a slow web view.

Most of the NativeScript code can be repurposed to a web application after changing the UI from NativeScript’s proprietary XML markup to HTML markup.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Converting Your Ionic 2 Mobile App To NativeScript

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址