Ionic 2 : how to build three native mobile apps from one code base

Introduction

I have just created an app using early versions of Ionic 2 (Apache Cordova with AngularJS).  The app has been accepted in to Google and Apple’s app stores.  Obviously, this means I am now Ionic 2 1337 and should write a guide on how to develop using the framework.  There are 750 lines of code in my first app, just to say… there are levels of 1337ness.

One of the reasons for writing up this up is that my colleagues should be able to use this and re-create the steps I took.  To make it interesting for me I am going to create a toy app that includes taking pictures.

Hat tips: of all the research (randomly dipping in to the Internet) I did, Josh Morony has been the greatest help through his blog.  Also, it would have taken even longer, health threateningly longer, to get the Windows tools working without Justin James‘s help.

We need tools

To develop three native apps I’m using three platforms: GNU/Linux, a physical Mac, and a Windows VM.  We could get away with just a Mac but I am way more productive with GNU/Linux.  We have not investigated building the app using a service in the cloud like Ionic’s.  I went through lots of iterations of building the tools that I can’t give detailed  and accurate instructions but hopefully through this I’ll show that it is possible to build Android, iOS and Windows Mobile apps.

Roughly:

  • for GNU/Linux building Android : essentially npm, git, Java SDK, Android SDK and a guide.
  • for Apple: npm, git, Java SDK, Android SDK, Xcode, an Apple Id and a guide.  For an introvert like me, I love the licence (without membership) and Id free world of GNU/Linux.  I can just get on and code.  If you don’t already have an Apple Id then nip over to an Apple store and get something for “free” so that when you create the Id you do not need to register a credit card.  I wrote that bit without swearing.  Set up an Apple Id using this method before you do anything else.  Otherwise, you could, like me, spend too much time trying to get things set up comfortably.  This step, for me, included phone calls!
  • Caveat : Windows hates me.  “Windows” seems apt because the OS seems to be a collection a small opportunities where the thing you have tried repeatedly suddenly works.  I’m sure colleagues who use Windows day in day out will have more luck.  The quickest way into Ionic and Windows might be this guide.  Justin James employs Chocolatey to batch install the tools he needs and because of him you can too.

We need magic

In no particular order these tricks might save your day:

  • I use this to build and deploy to a Windows Mobile set to developer mode and connected by USB to my Windows VM:
    ionic run --device -- --phone --arch=arm
  • Re-install plugins if things go awry:
    $ ionic plugin list
    
    On Linux, build a for loop from the output:
    
    $ for i in cordova-plugin-crosswalk-webview cordova-plugin-device 
    cordova-plugin-network-information cordova-plugin-splashscreen
    cordova-plugin-statusbar cordova-plugin-whitelist
    cordova-sqlite-storage cordova.plugins.diagnostic
    ionic-plugin-keyboard ;
     do   ionic plugin remove $i && ionic plugin add $i; done
    
  • Tidy up before release:
    ionic plugin rm cordova-plugin-console
  • package.json includes version numbers which can be fine tuned to get things working and this will update the current project:
    npm install
  • re-installing Ionic can help (as root):
    npm uninstall -g ionic && npm uninstall -g ionic
  • when you create a new project you get a .gitignore for free.  When you build on a different platform you need to check you have installed the necessary plugins and platform to build your app because these will not get added to your project
  • when we build on a new platform we will have lots missing when we pull from git.  The directory “www” was missing.  Ionic claimed that I was not building an Ionic project
  • also, for a first build on a new platform
    ionic setup sass
  • Icons and splash screens are fun.  For Android and iOS you can put an image 2048×2048 for the splash.png in ./resources and then run the following to build all the images the project needs
    ionic resources --splash && ionic resources --icon
  • Older Android versions have a poor web browser.  Install Crosswalk for consistency across versions:
    ionic plugin add cordova-plugin-crosswalk-webview
  • If you get Sass errors try:
    rm -rf node_modules
    npm install

Hello World

Somewhat riskily I’m upgrading to the official release of version 2 final.  This should be fine but I built my first app with rc3 then rc5.  There will be things to learn with the proper release.

Somewhere neat run:

ionic start IonicHelloWorld tabs --v2 --ts

This will create lots and lots of things, we are mostly interested in:

src
├── app
│   ├── app.component.ts
│   ├── app.html
│   ├── app.module.ts
│   ├── app.scss
│   └── main.ts
├── assets
│   └── icon
│   └── favicon.ico
├── declarations.d.ts
├── index.html
├── manifest.json
├── pages
│   ├── about
│   │   ├── about.html
│   │   ├── about.scss
│   │   └── about.ts
│   ├── contact
│   │   ├── contact.html
│   │   ├── contact.scss
│   │   └── contact.ts
│   ├── home
│   │   ├── home.html
│   │   ├── home.scss
│   │   └── home.ts
│   └── tabs
│   ├── tabs.html
│   └── tabs.ts
├── service-worker.js
└── theme
└── variables.scss

and resources, config.xml, package.json.

At this point we can already run our app in a web browser:

ionic serve

“ionic serve –lab” doesn’t work for me yet.

Let’s add a platform.  I’m on GNU/Linux, because it is my Happy Place, so I will add Android:

ionic platform add android

and now we can run our app in an emulator:

ionic run android

AndroidEmulatorThe are two ways to get the app on to a mobile device:

  • copy the android-debug.apk that was built in the last step and copy it on a device, then tell the device to trust apps found outside of the Playstore (Android app store) and install the app.  The signature for the app is the identification of the app.  New versions built in the same circumstances will replace the old version.  An app built with a different signature will appear as a separate app
  • via USB.  Set up the device so that it is in “developer mode”.  Connect it using a USB cable and check with “adb devices” that the computer can see it:
  • $ adb devices
    List of devices attached
    42eb627e device

    and then run “ionic run android” again.  Excited yet?  Maybe not, if you got a blank screen.  The plugin for loop from above fixed this for me

  • Google Chrome web browser has a trick we can use at this point: chrome://inspect will let us inspect and debug our running app.

Change some code

Looking at the tree structure above we can see that src/pages/home contains the home “tab”.  This will not be very exciting but if I go straight to trying to add camera functionality this blog entry is likely to crash and burn.  In the directory we have: home.html, home.scss, and home.ts.  We can change the text in the .html, the CSS in .scss and the Angular JS in the .ts file.  I spent a week learning version 1 of Ionic and I think version 2 will be better.  Let’s change the home tab… First of all run:

ionic serve

and navigate to http://localhost:8100/.  When we change a file the app will reload in the browser giving us the sense that what we change is what we see.  I use vi (Vim) in most situations because it is nearly always available (hey Windows, get with the programme!)  Edit home.html under src/pages/home/home.html.  Change “Welcome to Ionic!” to “My Little Camera App.” and save the code.  We should see the app reload in the browser and instantly display the change:

$ diff src/pages/home/home.html src/pages/home/home.html.orig 
8c8
< <h2>My Little Camera App.</h2>
---
> <h2>Welcome to Ionic!</h2>

Now, just for fun, let make the title green:

$ diff src/pages/home/home.scss src/pages/home/home.scss.orig
2,4d1
< h2 {
< color: green;
< }

Currently, I’m nervous of style changes.  When we imagine the range of devices and browsers, a style change might not be reflected the way we hope it would in every situation.

Time to get funky

Straight from the horse’s mouth, add the camera plugin:

ionic plugin add cordova-plugin-camera

This is where the fun begins.  Desktop web browsers do not have a native camera available to them.  We need to install our toy app on to a device to see the functionality.  I hope we can borrow a device from work and not compromise our own devices.

Next, let’s change “About” to be “Snap”.  This is fairly complex but essentially we are looking for instances in the file system and code that have “About” or “about” and changing to “Snap” and “snap”.  Change files:

$ find src -name '*about*'
src/pages/about
src/pages/about/about.html
src/pages/about/about.ts
src/pages/about/about.scss

and strings:

$ find src -type f| xargs grep -i about
src/declarations.d.ts: Declaration files are how the Typescript compiler knows about the type information(or shape) of an object.
src/declarations.d.ts: They're what make intellisense work and make Typescript know all about your code.
src/declarations.d.ts: To learn more about using third party libraries in an Ionic app, check out the docs here:
src/pages/tabs/tabs.html: <ion-tab [root]="tab2Root" tabTitle="About" tabIcon="information-circle"></ion-tab>
src/pages/tabs/tabs.ts:import { AboutPage } from '../about/about';
src/pages/tabs/tabs.ts: tab2Root: any = AboutPage;
src/pages/snap/snap.html: About
src/pages/snap/snap.scss:page-about {
src/pages/snap/snap.ts: selector: 'page-about',
src/pages/snap/snap.ts: templateUrl: 'about.html'
src/pages/snap/snap.ts:export class AboutPage {
src/app/app.module.ts:import { AboutPage } from '../pages/about/about';
src/app/app.module.ts: AboutPage,
src/app/app.module.ts: AboutPage,

I made those changes so quickly that the Ionic web server has become confused.  Rebuild the app “ionic build android“, restart the server “ionic serve“, and reload the web page.  Now, the icon “i” for Snap does not make sense.  Browse through the icons and choose a new one.  Make the following change to “tabs.html”:

$ diff src/pages/tabs/tabs.html src/pages/tabs/tabs.html.orig
3c3
< <ion-tab [root]="tab2Root" tabTitle="Snap" tabIcon="camera"></ion-tab>
---
> <ion-tab [root]="tab2Root" tabTitle="Snap" tabIcon="information-circle"></ion-tab>

Next, we need to tell the AngularJS to use the camera library, in “snap.ts”:

$ diff src/pages/snap/snap.ts src/pages/snap/snap.ts.orig
5,6d4
< import {Camera} from 'ionic-native';
<

Adding this will change the warning to the user if they were to install the app to their device.  The warning will say that the app wants access to the camera.

Skipping, because this is so easy, I’ll add a few more bit from the tutorial…

$ diff src/pages/snap/snap.ts src/pages/snap/snap.ts.orig 
5,6d4
< import {Camera} from 'ionic-native';
< 
13,14d10
< public base64Image: string;
< 
17,29d12
< }
< 
< takePicture(){
< Camera.getPicture({
< destinationType: Camera.DestinationType.DATA_URL,
< targetWidth: 1000,
< targetHeight: 1000
< }).then((imageData) => {
< // imageData is a base64 encoded string
< this.base64Image = "data:image/jpeg;base64," + imageData;
< }, (err) => {
< console.log(err);
< });

and:

$ diff src/pages/snap/snap.html src/pages/snap/snap.html.orig
10,19d9
< <ion-card>
< <ion-card-content>
< Hello World, this is my camera app
< 
< <button (click)="takePicture()">Take a Picture</button>
< 
< Latest Picture:
< <img [src]="base64Image" *ngIf="base64Image" />
< </ion-card-content>
< </ion-card>

We have linked, I like this bit, the event ‘click‘ and the function “takePicture()“.  Further down we can see:

*ngIf="base64Image"

The “*ngIf” is another bit of magic.  The image is displayed if “base64Imageis true.  Once we understand this we can do all sorts of things using the power of the evil side-effect.  If a variable is shared across the application a variable set in one tab can effect the magic on another tab.

Right, quick, build the app and deploy it to a device.  Plug the device in again test test “adb devices”.  Then run “ionic run android”.  If I have done a good job in explaining this, we should now have a little camera app running on Android.

Git it

As this is a toy app we won’t add this to TFS but we could do this…

Now we have something running it is probably a good time to add it to our Git repo (TFS).  We can develop on GNU/Linux and pull changes to Windows and Apple rather than go through the pain of developing on either of those platforms.  Ionic works well with git because a little code goes a long way.  A new feature can be added as code and push to git and make sense as a unit.  If we could automate the tools we might even see automatic building of the native apps ready for testing.

Another bite of the Apple

If we are lucky, we will have access to an polite but ancient (think hard drive and too little RAM) Mac Mini.  As above we should have all the tools including Xcode installed.

The slow Mac Mini I am using is headless and I use Remmina to VNC to the Mac Mini.  First, we copy the project on to the Mac because we have not set up git for this “toy” application.  In this case it can be useful to use the trick:

rm -rf node_modules
npm install

A good test is to run “ionic serve”.  Once that is working we can run:

ionic build ios

which is if completes successfully will create

platforms/ios/IonicHelloWorld.xcodeproj/

which can be opened as a project in Xcode.  Attach an iDevice to the Mac and then set up Xcode to connect to it:

Mac Mini running Xcode

Mac Mini running Xcode

The device I am using is called TESTBOX21 which whould be in the drop down circled.  When we select it Xcode will do some jiggery pokery.  Click to edit the project and set “team” to an Apple Id.  Then click “play”.  Shortly, or longly for this Mac, we will be asked to allow the app to run on the iDevice.  On the iDevice go to Settings > General > Device Management.  Click on the Apple Id that you used, trust it and verify the app.  The app is install but we can click on “play” again.  Once again, we have a native version of our app but for iOS this time.

I’ve got that Windows feeling ♪ ♫ ♬

The toy app’s code is not in Git.  I’m stymied.  How do I get the code on to the Windows VM?  Apple has SSH.  The advice is to set up Samba on the GNU/Linux host.  Luckily, we have some Windows infrastructure and I can do two copies to get going…  I might take up knitting.  These copies are going very slowly…bigly slow.  I Ctrl-Ced that and put the code up to DMU’s open git server.

On the Windows VM:

git clone https://git.dmu.ac.uk/appdev/MyLittleCameraApp.git

Tell the project about Windows 10, edit using ‘code‘ config.xml:

$ diff config.xml config.xml.orig 
22d21
< <preference name="windows-target-version" value="10.0" />

Connect a Windows device to the Windows VM via USB.  Go in to the directory and :

npm install
ionic platform add windows
ionic plugin add cordova-plugin-camera

Finally, run the magic:

ionic run --device -- --phone --arch=arm

And there you have it.  One set of code running on three devices.

About c3iq

Opensource, Linux, Unix, Fish, Family
This entry was posted in app, Development, ITMS and tagged , , , , , , . Bookmark the permalink.