Using Ionic DevApp to test mobile applications

November 8, 2017, 8:00 am Categories:

Categories

Even with the improved technology developments of the last few years it can still be challenging for developers to build applications for iOS & Android due to the required software and system configurations that need to be in place.

Fortunately the team at Ionic have recently released a free iOS/Android application to help tackle this problem: Ionic DevApp.

Testing goodness

Ionic DevApp was created to help developers resolve the all-too common frustrations with installing and configuring Native SDK's for iOS and Android in order for them to be able to build/test their applications on those platforms.

Available as a free download for iOS and Android Ionic DevApp works in the following way:

  • Run your Ionic project in the desktop browser using ionic serve
  • Launch the installed Ionic DevApp on your iOS/Android device
  • Connect your desktop and handheld device to the same Wi-Fi network
  • Within the Ionic DevApp application select the detected Ionic project running on your desktop
  • Test the selected project using Ionic DevApp

Pretty simple and straightforward yet incredibly powerful.

No more tripping over potential issues with Native SDK's - just run in your browser and pick up and test with Ionic DevApp!

Importantly this free application provides strong and impressive pre-built support for Ionic Native/Apache Cordova with the following list of pre-installed plugins.

This means you can access such plugin functionality by simply running your Ionic project in the desktop browser followed by launching the Ionic DevApp on your handheld device and then, over the same Wi-Fi network, previewing that project using the DevApp software.

Pretty cool huh?

Here's what the Ionic DevApp software looks like when first launched on your device:

You'll need to log into your Ionic account (which, if you don't already have one, can be created here) to begin with and then follow the helpful instructions (displayed in the above right hand screen capture - notice that the software is actively scanning the network to detect any Ionic projects currently running? Nice touch.)

As always with technology support is going to be a deciding factor in what you can/can't use so you will need to ensure you have the following minimum requirements in place with your development environment/devices:

  • Ionic CLI 3.13.2+ (preferably the latest release though)
  • iOS 9.2+
  • Android 4.1+

What we'll be developing

Now that we're familiar with Ionic DevApp and how it works we'll be creating a very basic application that allows users to add and display details of their favourite software using the Ionic Native SQLite plugin.

This will consist of a simple one page application that uses the Ionic AlertController component to display a form that we can enter data into that will then be saved within the application's SQLite database.

Previewed and tested within the Ionic DevApp software our application will appear as demonstrated in the following screen captures:

Once a record has been successfully saved the application will automatically update the HomePage component template to display all stored records like so:

Setting the stage

Now we know what to expect let's get cracking with building the project!

First you'll need to ensure that you're running the most recent version of the Ionic CLI and then, using your system CLI software, navigate to a location on your computer where you want the project to be created before running the following commands (one after the other):

ionic start ionic-developa blank
cd ./ionic-developa
ionic cordova platform add ios
ionic cordova platform add android
ionic cordova plugin add cordova-sqlite-storage
npm install --save @ionic-native/sqlite
ionic g provider database

Here we simply create a new Ionic project named ionic-developa (using a blank project template), install the required iOS and Android platforms followed by the Ionic Native SQLite plugin before finally creating a database service that will manage the plugin logic for our project.

Rooting the application

Before we start developing the necessary logic and templating for the project we need to ensure that the application root module - ionic-developa/src/app/app.module.ts - is configured with the necessary plugin/service imports and declarations:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { SQLite } from '@ionic-native/sqlite';


import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { DatabaseProvider } from '../providers/database/database';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    SQLite,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    DatabaseProvider
  ]
})
export class AppModule {}

The application database

As the SQLite plugin provides the necessary database support for our project we'll start with crafting the required logic for implementing selected plugin methods in our DatabaseProvider service.

Open the ionic-developa/src/providers/database/database.ts service, remove the default Http import and Http constructor initialisation code (trust me - we won't be needing these at all) and configure the code so that it resembles the following (comments supplied to assist with understanding the purpose of each declared property, method and what is happening at each stage of the service):

import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';


@Injectable()
export class DatabaseProvider {



   /**
    * @name _DB
    * @type {object}
    * @private
    * @description     Defines an object for handling interfacing with the 
    				   SQLite plugin
    */
   private _DB 	: SQLiteObject;



   // Initialise the necessary component/plugin(s)
   constructor(private _SQL    : SQLite,
               private _PLAT   : Platform) 
   {
      // When platform is fully loaded create the database and table 
      // (IF they don't already exist)
      this._PLAT.ready()
      .then(() => 
      {
         this.createDatabaseAndTable();
      });
   }




   /**
    * Create the database and necessary table for storing our data
    *
    * @public
    * @method createDatabaseAndTable
    * @return {none}
    */
   createDatabaseAndTable() : void
   {

      // Define the application SQLite database
      this._SQL.create({
         name: 'ionic.db',
         location: 'default'
      })
      .then((db: SQLiteObject) => 
      {

         // Associate the database handler object with the class-wide private property
         this._DB = db;

        
         // Create the favouriteSoftware table
         this._DB.executeSql('CREATE TABLE IF NOT EXISTS favouriteSoftware(name VARCHAR(30) NOT NULL, description TEXT NOT NULL)', {})
         .then(() => 
         {
            console.log('The table favouriteSoftware was successfully created');
         })
         .catch((e) => 
         {  
            console.log(e);
         });      
      
      })
      .catch((e) => 
      {
         console.log(e);
      });

   }




   /**
    * Retrieve ALL records stored within the favouriteSoftware table
    *
    * @public
    * @method retrieveRecords
    * @return {Promise}
    */
   retrieveRecords() : Promise<any>
   {
      return new Promise((resolve, reject) => 
      {
         this._DB.executeSql('SELECT name, description FROM favouriteSoftware', {})
         .then((data : any) => 
         {			
            let items : any 	= [];
            if(data.rows.length > 0) 
            {
               var k;

               // iterate through returned records and push as nested objects into
               // the items array
               for(k = 0; k < data.rows.length; k++) 
               {	    
                  items.push(
                  {
	                 name 			: data.rows.item(k).name,
	                 description 	: data.rows.item(k).description
                  });
               }
            }
            resolve(items);
         }) 
         .catch((error) => 
         {
            reject(error);
         });
      });
   }




   /**
    * Add a new record to the favouriteSoftware table
    *
    * @public
    * @method addRecord
    * @param  name 				    {String}           The value for the table's name field
    * @param  description           {String}           The value for the table's description field 
    * @return {Promise}
    */
   addRecord(name 			: string,
             description 	: string) : Promise<any>
   {
      return new Promise((resolve, reject) => 
      {
         let sql = "INSERT INTO favouriteSoftware(name, description) VALUES('" + name + "', '" + description + "')";
	     this._DB.executeSql(sql, {})
	     .then((data : any) => 
	     {
	        resolve(true);
         }) 
         .catch((error : any) => 
         {
	        reject(error);
         });
      });	
   }

}

Our component logic

With our plugin logic managed by the recently configured DatabaseProvider service we can now concentrate on crafting the necessary code to integrate this into the HomePage component so we can add and retrieve database records stored in SQLite.

Open the ionic-developa/src/pages/home/home.ts class and structure the code contained within this file so that it resembles the following:

import { Component } from '@angular/core';
import { AlertController, NavController, Platform } from 'ionic-angular';
import { DatabaseProvider } from '../../providers/database/database';

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



   /**
    * @name items
    * @type {object}
    * @public
    * @description     Defines an array for storing retrieved records from the 
    				   SQLite table
    */
   public items : any   = [];



   // Initialise services/components
   constructor(public navCtrl  : NavController,
               private _DB     : DatabaseProvider,
               private _PLAT   : Platform,
               private _ALERT  : AlertController) 
   {  }




   /**
    * Retrieve database records WHEN the template view 
    * AND the platform have fully loaded
    *
    * @public
    * @method ionViewDidLoad
    * @return {none}
    */
   ionViewDidLoad() : void
   {
      this._PLAT
      .ready()
      .then(() => 
      {
         this.retrieveRecords();
      });
   }




   /**
    * Retrieve database records using the DatabaseProvider 
    * service and, if the task was successful and records 
    * were returned, store these in the items array for 
    * rendering to the template
    *
    * @public
    * @method retrieveRecords
    * @return {none}
    */
   retrieveRecords() : void
   {
      this._DB.retrieveRecords()
      .then((records : any) => 
      {
         this.items = records;
      })
      .catch((e) => 
      {  
         console.log(e)
      }); 
   }




   /**
    * Add a new record to the favouriteSoftware table 
    * using the addRecord method of the DatabaseProvider 
    * service
    *
    * @public
    * @method addRecord
    * @param  name 				    {String}           The value for the table's name field
    * @param  description           {String}           The value for the table's description field 
    * @return {none}
    */
   addRecord(name       	: string, 
             description 	: string) : void
   {
      this._DB.addRecord(name, description)
      .then((records : any) => 
      {
         // IF our record was saved then reload
         // ALL records to update the template to 
         // include the latest addition 
         this.retrieveRecords();
      })
      .catch((e) => 
      {  
         console.log(e);
      }); 
   }




   /**
    * Create and launch a modal window - using Ionic's 
    * AlertController method - to display a form for adding 
    * name/description values to the SQLite database  
    * service
    *
    * @public
    * @method launchAlert
    * @return {none}
    */
   launchAlert() : void
   {
      let alert = this._ALERT.create({
         title: 'Add a new record',
         message: 'Enter details for your favourite software here',
         inputs: [
           {
             name				: 'name',
             placeholder		: 'Software name'
           },
           {
             name				: 'description',
             placeholder		: 'Software description'
           }
         ],
         buttons: [
           {
             text		: 'Cancel',
             handler	: data => 
             {
               console.log('Cancel clicked');
             }
           },
           {
             text		: 'Save',
             handler	: (data) => 
             {
                // Call the addRecord method to save the data
                this.addRecord(data.name,
                			   data.description);
             }
           }
         ]
      });
      alert.present();
   }

}

This should all be fairly straightforward to understand from the method names and commenting that is in place so now let's progress onto adding the necessary templating for the HomePage component.

Crafting the view

Open the ionic-developa/src/pages/home/home.html template and add the following basic markup structure:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  
   <button 
      ion-button 
      block 
      color="primary" 
      (click)="launchAlert()">
      Add software details here
   </button>



   <ion-list *ngIf="items.length != 0">
      <ion-item 
         *ngFor="let item of items">
	     <h2>{{ item.name }}</h2>
	     <p>{{ item.description }}</p>
      </ion-item>
   </ion-list>

</ion-content>

We could probably change the <ion-title> value but I'll leave that for you to decide!

Testing the application

With all the necessary code now in place we can test that our application actually works (always important as a developer!) by running the following Ionic CLI command to preview the project in our desktop browser:

ionic serve

Now launch the Ionic DevApp application on your handheld device (ensuring that your desktop computer and handheld device are connected to the same network - this is VERY important so DO get this right!) and, once logged in to your Ionic account, select and run the detected ionic-developa application like so:

Pretty cool huh!

To capture console logs generated from the application (which will be displayed in the terminal window where the application is being run from) you will need to append the -c flag to the ionic serve command like so:

ionic serve -c

As you have seen by now Ionic DevApp makes testing your project builds on a platform by platform basis super easy - and all whilst running in your desktop browser.

In summary

Hopefully this short tutorial has given you a taste for using the Ionic DevApp testing tool and how effective that can be for helping preview projects on a handheld device.

Being able to run your project on a desktop computer and simultaneously preview/test that, as if it were natively published, on an iOS/Android device is pretty incredible when you think about it (particularly where this helps overcome any issues with Native SDK installations/configurations).

I expect this tool will evolve to include further helpful features over subsequent releases but even in its nascent state the application is a deceptively powerful addition to any Ionic developer's software toolkit.

I hope you enjoyed this tutorial and please feel free to leave feedback in the comments section below.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top