Create your account

Already have an account? Login here

Note: By joining, you will receive periodic emails from Coursetro. You can unsubscribe from these emails.

Create account

How to Make an Ionic 2 App

By Gary simon - Jan 25, 2017

This is the final lesson that's a part of our Free Ionic Course, and we will bring everything together that we learned, by creating an Ionic app from scratch.

The name of the app is "WifeAlert", ha! We'll use several Ionic Native plugins (Geofence, Geolocation, and SMS) to define a parameter from which the app will send a text message if the phone travels outside of said parameter.

While it's a silly concept of an app, it will help us learn how to work with Ionic components, native plugins, and custom themes. Watch the video below if you would like to see the app in action. 

So, let's get started!

First, if you prefer video..

Be sure to subscribe to our youtube channel.

Setting up the Project

First, make sure you have both ionic and cordova installed. If you don't, refer to this earlier clip: Installing Ionic

Hop into your console of choice and run the following command:

$ ionic start wifealert blank --v2

$ cd wifealert

So, we're starting a new Ionic 2 project called wifealert, with the blank project template and --v2 designating that this is an Ionic 2 app.

Simple enough!

Installing the Ionic Native Plugins

As mentioned above, we will use 3 Ionic Native plugins, so they must be installed. In the project folder, type:

$ ionic plugin add cordova-plugin-geofence cordova-plugin-geolocation cordova-sms-plugin

This will add the our plugins all in one command.

  • Geolocation will allow us to fetch the phone's current position using GPS.
  • Geofence will allow us to define a radius around the GPS coordinates (in meters). It will also allow us to monitor the position and execute a task if the fence is broken or entered.
  • SMS will allow us to send a text message once the Geofence is left.

Generating a Page with Ionic CLI

Apart from the home page, we will use a second page called active that's displayed when a Geofence is active. 

So, while we're here in the console, we might as well add it now:

$ ionic g page active

g is short-hand for generate. It will place this in a folder called active in the /src/pages/ folder.

Adding Android to the Project

I will build out my project for an Android phone, since that is what I own. In order to do that, you have to add android as a platform with cordova. You will need to add either android or ios, as this project will not work on a desktop environment.

For Android, you will need Android Studio with the Android-SDK, along with Java

There is a platform guide though that gives you all of the information you need for both iOS and Android:

Once you have what you need installed, run: (or with ios)

$ cordova platform add android

Home Component Code

First, we need a few imports at the top of our /src/pages/home/home.ts file:

import { Component } from '@angular/core';
import { NavController, Platform } from 'ionic-angular';
import { Geofence, Geolocation, SMS } from 'ionic-native';
import { ActivePage } from '../active/active';

We're adding Platform from ionic-angular which allows us to get information about the current device.

Then we're adding our 3 Ionic Native plugins, and also importing our ActivePage we generated with the Ionic-CLI.

Next, inside export class HomePage we need to define 3 properties:

export class HomePage {

  radius: number = 100;
  error: any;
  success:any;

  constructor(public navCtrl: NavController) {
    
  }

}

Radius will be set to 100 meters by default. You probably shouldn't set the radius less than 100, otherwise it can be inaccurate and misfire.

Then we have 2 properties for error and success

In the next code snippet, we'll focus just on the constructor. Change it to:

  constructor(public navCtrl: NavController, private platform: Platform) {
    this.platform.ready().then(() => {
         
      Geofence.initialize().then(
        () => console.log('Geofence Plugin Ready'),
        (err) => console.log(err)
      );
      
    });
  }

So through dependency injection, we're adding the Platform member that we imported at the top.

And then we're calling this.platform.read().then to run Geofence.initialize(). All this means is that once the device is ready, or already ready, it will start the Geofence plugin. When this happens for the first time, the user will be prompted to allow the app access to location and notifications.

Underneath the constructor, paste the following method:


  setGeofence(value: number) {

    Geolocation.getCurrentPosition({
      enableHighAccuracy: true
    }).then((resp) => {
      var longitude = resp.coords.longitude;
      var latitude = resp.coords.latitude;
      var radius = value;

      let fence = {
          id: "myGeofenceID1", 
          latitude:       latitude, 
          longitude:      longitude,
          radius:         radius,  
          transitionType: 2
        }
      
        Geofence.addOrUpdate(fence).then(
          () => this.success = true,
          (err) => this.error = "Failed to add or update the fence."
        );

        Geofence.onTransitionReceived().subscribe(resp => {
          SMS.send('5555555555', 'OMG She lied, leave her now!');
        });

        this.navCtrl.push(ActivePage);


    }).catch((error) => {
      this.error = error;
    });
  }

setGeofence is a method we will call when we press a button. It passes in a radius value that we'll define with a range slider.

Then, we use Geolocation.getCurrentPosition() to get the phone's current position. We're passing in enableHighAccuracy to ensure we get a high quality position.

If it's successful, we define a few variables for longitude, latitude and radius, which are then defined in fence.  fence contains properties that are needed to create or update a Geofence.

  • id - This can be any unique ID.
  • Lat/Long/Radius are self explanatory.
  • TransitionType - This can either be 1 (Entering the Geofence), 2 (Leaving), or 3 (Both). We'll just use 2 for leaving.

Then we use Geofence.addOrUpdate() to create or update the fence.

And Geofence.onTransitionReceived() to send our text message through SMS.send. This is called when the TransitionType of 2 (Leaving) occurs. You will want to enter the number of your device, not the current device. Oh and hey, by the way, if she visits her text messages, she will see this text in her history!

At the end, we navigate to the ActivePage through this.navCtrl.push.

Home HTML Template

In home.html let's add:

<ion-content class="page">
  <h1>WifeAlert</h1>
  <div class="loader"></div>

  <div class="bottom-container">
    <ion-item>
      <ion-range [(ngModel)]="radius" #radiusVal min="40" max="300" color="primary" pin="true" snaps="true" step="20">
      </ion-range>
    </ion-item>
    <ion-label color="secondary" id="lbl">Fence Parameter (Meters)</ion-label>
    <button ion-button large outline block (click)="setGeofence(radiusVal.value)" id="cta" color="primary">Set Geofence</button>

    <p *ngIf="error">{{ error }}</p>

  </div>
</ion-content>

At the top, we'll have the name "WifeAlert" along with an animated loader graphic.

Then, we use ion-range which will allow us to set the radius of the Geofence.

We use an ion-button to call our custom setGeofence method, where we pass the value of the range.

Home SCSS

ion-range, ion-item {
    background-color: transparent !important;
    color:#fff;
}

.item-inner {
    border-bottom:0 !important;
}

h1 {
    padding: 5em 0;
    text-align:center;
    font-weight: 100;

}

.bottom-container {
    display:block;
    width:100%;
    padding: 2em 2em 5em 2em;
}
.item-md, .item-inner {
    padding-left:0;
    padding-right:0 !important;
}
#cta {
    margin: 2em auto 0 auto;
    display:block;
}

#lbl {
    text-transform:uppercase;
    letter-spacing: 2px;
    font-size:.85em;
    margin-top:0;
    text-align:center;
}
.range-md .range-pin {
  -webkit-transform: translate3d(0, 0, 0) scale(1);
  transform        : translate3d(0, 0, 0) scale(1);
}
  html,
  body {
    height: 100%;
    width: 100%;
    overflow: hidden;
  }
  
  .loader {
    position: absolute;
    top: 40%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-style: solid;
    border-radius: 50%;
    border-color: #2BFCBA;
    animation: 1s pulse infinite;
  }
  
  @keyframes pulse {
    0% {
      height: 0px;
      width: 0px;
      border-width: 32px;
      opacity: 0;
    }
    40% {
      opacity: 1;
    }
    80% {
      height: 64px;
      width: 64px;
      border-width: 0px;
      opacity: 0;
    }
    100%{
      opacity: 0;
    }
  }

In here, we're just defining a few CSS rulesets to style the page and also the loader.

Also, head on over to /src/app/app.scss to define a single ruleset that will be used by both of our pages:

.page {
    background-color: #263E44 !important;
    color:#fff;
}

And then finally, we'll define a new primary and secondary color in /src/theme/variables.scss:

$colors: (
  primary:    #0AFDA4,
  secondary:  #578F7A,
  
  .. others..

);

Active Component Code

Now, inside of the /src/pages/active/active.ts component, I will simply paste the entire contents, because there is not much:

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Geofence } from 'ionic-native';
import { HomePage } from '../home/home';

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

  constructor(public navCtrl: NavController, public navParams: NavParams) {}

  ionViewDidLoad() {
    console.log('ionViewDidLoad ActivePage');
  }

  removeFence() {
    Geofence.removeAll();
    this.navCtrl.push(HomePage);
  }

}

All we have here is removeFence() which is a method that's called when a user clicks on a button to remove all fences.

Active HTML

The HTML for this page is very similar to the Home page HTML:

<ion-content class="page">
  <h1>WifeAlert</h1>
  <div class="loader"></div>

  <div class="bottom-container">
      <ion-label color="secondary" id="lbl">MONITORING CURRENTLY ACTIVATED</ion-label>
    <button ion-button large outline block (click)="removeFence()" id="cta" color="primary">Remove Fence</button>
  </div>
</ion-content>

Just a simple button that callst he removeFence() method. Great, we're almost there!

App.module.ts Adjustments

The last thing we need to do is import our ActivePage and add it to the declarations and entryComponents.

In /src/app/app.module.ts add:

.. other imports ..

import { ActivePage } from '../pages/active/active';

@NgModule({
  declarations: [
    .. other declarations ..
    ActivePage
  ],

  .. removed bootstrap and imports just for brevity ..

  entryComponents: [
    .. other entryComponents ..
    ActivePage
  ]
})

And that's it!

Let's try running our app now.

Running the App

Connect your phone via USB cable (ensure debugging, the device's GPS, and all that jazz is on) and in the console, type:

$ ionic run android --device

It will take a good minute on the first run, and then the app will load up in the phone and if all goes according to plan, you will see a screen similar to this:

Give it access to the GPS. Then you can specify a distance in meters, and click the SET GEOFENCE button. 

Now, remember, if you exceed the distance specified for the first time it will prompt you to grant the app permission to send a text. So, if you're really thinking of being a stalking weirdo, you might want to do that first.

Give it a test with 2 phones. If you exceed the Geofence, it should send a text to the number you specified in the home.ts code.

Final Thoughts

Hopefully you learned a lot about how to make an Ionic app! We learned how to create a very simple app, that used multiple Ionic native plugins, as well as a few different components.

As you can see, it's a very powerful framework for building hybrid apps. I'll see you next time!


Share this post




Say something about this awesome post!