Skip to content

Cordova cross-platform apps

Apache Cordova is a cross-platform mobile development framework that allows you to build apps for Android, iOS, and other platforms, using HTML5 and JavaScript.

You implement the interface in HTML5 and JavaScript, then use the Cordova framework to build the app for your given platform. Cordova also integrates a system of plug-ins so you could extend the basic browser application using native features of the various platforms.

Ionic Framework is a set of css classes and a library of JavaScript directives and modules, built on top of Cordova, using AngularJS.

IoTize provides a BLE Cordova plug-in to communicate with Tap devices, and libraries of JavaScript IoTize APIs that help you build Tap monitoring apps for Android, iOS and Windows.

Get the Tools

Cross-platform development with Ionic framework interacts with several SDKs for mobile app development, and each relies upon a specific set of tools. You should ensure that your system meets all your targeted platform's requirements:

Create an Ionic Project

In your development folder, use the ionic start command to create a project:

$ ionic start myFirstApp tabs

This command creates a directory called myFirstApp in your working directory. It creates your project, installs node modules for the application, and prompts you to setup Cordova.

Now, you can cd into the folder that was created. To get a quick preview of your app in the browser, use the serve command.

$ cd myFirstApp/
$ ionic serve

alt text

Refer to Ionic documentation to learn more about project architecture and Ionic template files.

Install IoTize plug-ins and library modules

IoTize BLE Cordova plug-in enables wireless communication between smartphones and Taps using BLE communication. To add the plug-in to your project, run the following command:

$ ionic cordova plugin add @iotize/cordova-plugin-iotize-ble

IoTize JavaScript library facilitates the development of mobile applications, so it should be integrated in your Ionic project by running the following command:

$ npm install @iotize/device-client.js --save

IoTize libraries need RxJS version 6, so you need to update RxJS and install the rxjs-compat dependency:

$ npm i rxjs@^6 --save
$ npm i rxjs-compat --save

Run on different platforms

The Cordova Command Line Interface (CLI) does most of the heavy lifting, building and running a Cordova app. But the workload differs depending on the targeted platform.

Android

The CLI supports both building and running Android apps on Windows. You may need to install a USB driver for your Android device (see Android’s installing USB Drivers page). To compile and install it on your device, connect the device over USB and run the following command:

$ ionic cordova run Android

Refer to Cordova Documentation to learn more about Android development with Cordova.

iOS

iOS development needs a MAC computer and XCode version 9 or newer. The following command generates the XCode project in the "platforms\ios" subdirectory of your project:

$ ionic cordova add platform iOS

Refer to Cordova documentation to learn more about iOS development with Cordova. There are several pre-requirements to deploy a device.

Windows 10

When building for Windows 10, Cordova generates a Windows UWP app. The app is launched in Visual Studio, in the same way as a native Windows 10 project. For more information, see Run Your Apache Cordova App on Windows.

The following command generates a Visual Studio 2017 solution in platforms\windows subdirectory of your project:

$ ionic cordova add platform windows

Set the debug settings of this generated project in order to directly build and install the app from Visual Studio 2017. Please note that at the time of writing this documentation, Ionic 4 is not compatible with Windows 10, so if you want to target this platform you should install and use Ionic 3.

Scan BLE Taps

Now that you’ve got all the assets in place, it’s time to make the application itself. IoTize BLE Cordova plug-in could be used to scan and connect to BLE Tap devices.

BLE scan provider

We will use an Angular 4 provider to handle the BLE scanning feature for our application.

$ ionic g provider ble-scanner

This adds and generates ble-scanner.ts file into your project. Edit and modify this file with the following code:

import { Injectable, EventEmitter } from '@angular/core';
import {
  BLEScanner,
  DiscoveredDeviceType,
} from '@iotize/cordova-plugin-iotize-ble';
/*
  BleScannerProvider handles BLE scanning sessions.
*/
@Injectable()
export class BleScannerProvider {
  //BLE Scan handler from cordova-plugin-iotize-ble
  public bleScanner: BLEScanner;

  //List of discovered Tap devices
  public devices: DiscoveredDeviceType[];

  //Angular event emitter that notifies the app each time a new device has been discovered during scan
  public updateDisplay: EventEmitter<void>;

  constructor() {
    this.bleScanner = new BLEScanner();
    this.devices = [];
    this.updateDisplay = new EventEmitter();

    this.subscribeToDevices();
  }

  subscribeToDevices() {
    this.bleScanner.devicesObservable().subscribe({
      next: (device) => {
        this.devices.push(device); // Push the discovered device to the devices array
        this.updateDisplay.emit(); // Emit an event
      },
    });
  }

  startScan() {
    this.devices.splice(0); // Refresh discovered devices array
    this.bleScanner.start({}); // Launch BLE scan
  }

  stopScan() {
    this.bleScanner.stop();
  }
}

We are going to use this provider to scan and display available Taps.

Scan the available BLE Taps

We will modify the home page of the app to add:

  • the scanning commands
  • two buttons to start and stop the scanning session.
  • a list to display the discovered devices.

Open pages/home/home.html and replace its content with the following:

<ion-header>
  <ion-navbar>
    <ion-title>IoTize Taps</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <button ion-button (click)="bleScanner.startScan()">Start scan</button>
  <button ion-button (click)="bleScanner.stopScan()">Stop scan</button>

  <ion-list>
    <ion-item *ngFor="let device of bleScanner.devices">
      <p>Name: {{device.name}}</p>
      <p>Id: {{device.address}}</p>
      <p *ngIf="device.rssi">RSSI: {{device.rssi}}</p>
    </ion-item>
  </ion-list>
</ion-content>

We use BLEScannerProvider to handle the scanning session, and display a list in the following manner (pages/home/home.ts) :

import { Component, ChangeDetectorRef } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BleScannerProvider } from '../../providers/ble-scanner/ble-scanner';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public navCtrl: NavController,
            public bleScanner: BleScannerProvider,
            public changeDetector: ChangeDetectorRef){
            }
}

ionViewWillLoad() {

    //subscribe to the events from ble scanner
    this.bleScanner.updateDisplay.subscribe(() => {

        //the list of devices has been changed
        //notify the change to rerender the page
        this.changeDetector.detectChanges();

    });
}

Build and run the app, you should have something like the following screen:

alt text

The format of BLE advertising data varies depending on your platform. On Android advertising, data will be the raw advertising bytes. iOS does not allow access to raw advertising data, so a dictionary of data is returned. iOS indentifies BLE devices using a UUID, whereas Android and Windows use the MAC address.

Android platforms return the following information:

{
    "name": "demo",
    "id": "00:1A:7D:DA:71:13",
    "rssi": -37
}

iOS platform returns the UUID of the device (not the MAC address):

{
    "name": "demo"
    "id": "15B4F1C5-C9C0-4441-BD9F-1A7ED8F7A365",
    "rssi": -61
}

Now that that we have the list of available Tap devices, we are ready to start a communication session. In the following section we use IoTize Tap APIs to connect and retrieve some information from a Tap.

Connect to a BLE Tap

IoTize provides device-client Javascript API to handle the heavy lifting of the communication with the device, and to give you access to the high level functionalities of Taps such as monitoring, authentication and encrypted communication.

We must add a new IoTizeDevice member to our BLEScannerProvider class to get access to the Taps' functionalities.

import { IoTizeDevice } from '@iotize/device-client.js/device';
....
this.tap = IoTizeDevice.create();

To connect with the Tap using BLE, IoTizeDevice needs cordova-plugin-iotize-ble.

import { BLEComProtocol } from '@iotize/cordova-plugin-iotize-ble';
....
await this.tap.connect(new BLEComProtocol(AddressOrUUID));

Once connected, we can use the exposed services of IoTizeDevice class. In this example we are going to read the serial number of the Tap.

let serialNumber =  await  this.tap.service.device.getSerialNumber();
...
selectedDevice.serialNumber = serialNumber.body();

Modify the three source files, ble-scanner.ts, home.ts and home.html, as follows:

  • providers/ble-scanner/ble-scanner.ts

import { Injectable, EventEmitter } from '@angular/core';
import {
  BLEScanner,
  DiscoveredDeviceType,
} from '@iotize/cordova-plugin-iotize-ble';
import { BLEComProtocol } from '@iotize/cordova-plugin-iotize-ble';
import { IoTizeDevice } from '@iotize/device-client.js/device';

//Tap object
class TapDevice implements DiscoveredDeviceType {
  public serialNumber: string;

  constructor(
    public name: string,
    public address: string,
    public rssi?: string
  ) {
    this.serialNumber = '';
  }
}

/*
 * BLEScannerProvider handles BLE communication with Taps
 */
@Injectable()
export class BleScannerProvider {
  //BLE Scan handler from cordova-plugin-iotize-ble
  public bleScanner: BLEScanner;

  //List of discovered Tap devices
  public devices: TapDevice[];

  //Tap handler
  public tap: IoTizeDevice;

  //Angular event emitter that notifies the app each time a new device has been discovered during scan
  public updateDisplay: EventEmitter<void>;

  constructor() {
    this.bleScanner = new BLEScanner();
    this.devices = [];
    this.updateDisplay = new EventEmitter();
    this.tap = IoTizeDevice.create();

    this.subscribeToDevices();
  }

  //subscribe to discovery notification
  subscribeToDevices() {
    this.bleScanner.devicesObservable().subscribe({
      next: (device) => {
        let discoveredTap: TapDevice = new TapDevice(
          device.name,
          device.address,
          device.rssi
        );

        this.devices.push(discoveredTap); // Push the discovered device to the devices array
        this.updateDisplay.emit(); // Emits an event
      },
    });
  }

  startScan() {
    this.devices.splice(0); // Refreshes discovered devices array
    this.bleScanner.start({}); // Launches BLE scan
  }

  stopScan() {
    this.bleScanner.stop();
  }

  //connect, read the Serial Number and disconnect from the Tap
  async readSerialNumber(addressOrUUID: string) {
    let selectedDevice = this.devices.find((x) => x.address == addressOrUUID);

    //Connect
    try {
      await this.tap.connect(new BLEComProtocol(addressOrUUID));
    } catch (error) {
      selectedDevice.serialNumber = 'connection error :' + error;
      return;
    }

    //read serial number
    let serialNumber = await this.tap.service.device.getSerialNumber();
    selectedDevice.serialNumber = serialNumber.body();

    //disconnect
    await this.tap.disconnect();

    //send a notification
    this.updateDisplay.emit(); // Emits an event to update display
  }
}

  • pages/home/home.html

<ion-header>
  <ion-navbar>
    <ion-title>IoTize Taps</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <button ion-button (click)="bleScanner.startScan()">Start scan</button>
  <button ion-button (click)="bleScanner.stopScan()">Stop scan</button>
  <ion-list>
    <ion-item *ngFor="let device of bleScanner.devices" >
      <p>Name: {{device.name}}</p>
      <p>Address: {{device.address}}</p>
      <p *ngIf="device.rssi">RSSI: {{device.rssi}}</p>
      <button (click)="bleScanner.readSerialNumber(device.address)">Serial Number: {{(device.serialNumber == '') ? 'click to read' : device.serialNumber}}</button>
    </ion-item>
  </ion-list>
</ion-content>

  • pages/home/home.ts

import { Component, ChangeDetectorRef } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BleScannerProvider } from '../../providers/ble-scanner/ble-scanner';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
})
export class HomePage {
  constructor(
    public navCtrl: NavController,
    public bleScanner: BleScannerProvider,
    public changeDetector: ChangeDetectorRef
  ) {}

  ionViewWillLoad() {
    //subscribe to the events from ble scanner
    this.bleScanner.updateDisplay.subscribe(() => {
      //the list of devices has been changed
      //notify the change to rerender the page
      this.changeDetector.detectChanges();
    });
  }

  //read Serial Number of the Tap device
  async readSerialNumber(AddressOrUUID: string) {
    await this.bleScanner.readSerialNumber(AddressOrUUID);
  }
}

Build and run the App, then connect to your Tap to read its Serial Number:

alt text

This concludes the Cordova Getting Started tutorial. You are now ready to learn more about IoTize Device APIs from the documentation.

You can also try the sample projects from Github: