Creating Cross-Platform Apps with Ionic and Electron

You may know:

  • Web Development
  • Ionic
  • Javascript
  • Typescript
  • Electron
  • Angular

Buid Tools:

  • Node
  • Git
  • Electron
  • Ionic
  • IDE Visual Studio Code

Mac Tools:

  • Homebrew: package manager for MacOS
  • MacOS Packages: brew install node, brew install git,
  • Npm Packages: npm install -g ionic@latest

Windows Tools:

  • Git
  • Node
  • Npm Packages: npm install -g ionic@latest

First App:

  • Steps with Ionic CLI
    • mkdir ionic
      cd ionic
      ionic start hello-world tabs
      cd hello-world
      ionic serve
      

Why Ionic:

  • Multidevice support
  • Simple clean interface
  • Budget
  • Multi platform

Some Configuration

Ionic behind a proxy

https://ionicframework.com/docs/cli/configuring.html#using-a-proxy

To proxy HTTP requests performed by the CLI, you will need to install the CLI proxy plugin:

npm install -g @ionic/cli-plugin-proxy

// Set env variables
$ export HTTP_PROXY="http://proxy.example.com:8888" # also used by npm
$ export HTTPS_PROXY="https://proxy.example.com:8888" # also used by npm
$ export IONIC_HTTP_PROXY="http://proxy.example.com:8888"

Each CLI that you use must be configured separately to proxy network request.

$ npm config set proxy http://proxy.company.com:8888
$ npm config set https-proxy https://proxy.company.com:8888
$ git config --global http.proxy http://proxy.example.com:8888

SSL Configuration

You can configure the Ionic CLI’s SSL (similar to configuring npm CLI):

$ ionic config set -g ssl.cafile /path/to/cafile # file path to your CA root certificate
$ ionic config set -g ssl.certfile /path/to/certfile # file path to a client certificate
$ ionic config set -g ssl.keyfile /path/to/keyfile # file path to a client key file

Telemetry

Disable to avoid Ionic LCI send data to Ionic.

ionic config set -g telemetry false

Desktop UI with Ionic

Inicial steps:

// Set npm behind a proxy
npm config set proxy http://<username>:<password>@<proxy-server-url>:<port>
npm config set https-proxy http://<username>:<password>@<proxy-server-url>:<port>

ionic start dispatcher blank  // or download from https://d2ql0qc7j8u4b2.cloudfront.net/ionic-angular-official-blank.tar.gz
cd dispatcher
ionic serve
ionic generate --pagesDir src/app/ page setup
ionic serve -b

Open the dispatcher directory into VSC

Follow convertions: https://angular.io/guide/styleguide

Dev server: http://localhost:8100

The library import { NavController } from 'ionic-angular'; is used to manage Navigation into Ionic.

Reference: <ion-fab> and <ion-fab-list>

  1. Create a new page, called setup
    1. ionic generate --pagesDir src/app/ page setup
      ionic serve -b
      
  2. Change setup.html
    1. <ion-content padding>
        <ion-grid>
          <ion-row justify-content-center>
            <ion-col col-8>
              <div class="wr-well">
                <h1>
                  Go Far - Stay safe
                </h1>
                <h6>Before you begin, we need your name and phone number</h6>
              </div>
              <ion-list>
                <ion-item>
                  <ion-input type="text" placeholder="Name" (value)="name"></ion-input>
                  <ion-input type="text" placeholder="Extension" (value)="extension"></ion-input>
                  <button ion-button outline iten-right icon-right (click)="setInfo()">
                    Set
                    <ion-icon name="arrow-forward"></ion-icon>
                  </button>
                </ion-item>
              </ion-list>
            </ion-col>
          </ion-row>
        </ion-grid>
      </ion-content>
      
  3. Change setup.scss

    1. ```
      page-setup {

         ion-content {
             backgound: url(../assets/images/country-road.jpg) no-repeat center center fixed;
             background-size: cover;
         }
      

      }

      1. Update setup.ts

        1. setInfo() { this.navCtrl.setRoot(HomePage); }
      2. Change app.scss for overall styling:

        1. ```
          body {
          font-family: Arial, Helvetica, sans-serif;
          }

        .wr-well {

         text-align: center;  
         margin: auto;  
         max-width: 800px;  
         padding: 20px 15px 0;
        
  h1, h2, h3, h4, h5, h6 {
      color: #fff;
      text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.6);
  }
   }

   .wr-float {  
          position: absolute;  
          top: 25px;  
          left: 15px;  
          right: 15px;  
          background-color: transparent;  
      }  
      \`\`\`

6. Link to the home page into `<ion-content>`  
   1. `<ion-fab top left #fab>              
          <button ion-fab><ion-icon name="more"></ion-icon></button>              
          <ion-fab-list side="right">              
            <button ion-fab (click)="gotoSetup(fab)"><ion-icon name="cog"></ion-icon></button>              
          </ion-fab-list>              
        </ion-fab>`

7. Create gotoSetup method into home:  
   1. `gotoSetup(fab: FabContainer) {            
          fab.close();            
          this.navCtrl.push('SetupPage', {}, { animate: true, direction: 'forward'            
          });            
        }`

8. Serve:  
   1. `ionic serve`

9. aa

### Steps Add Address List Page

Learn: Providers

@Injectable\(\): decorator used in a component for be used in others \(DI\)

See [https://angular.io/guide/dependency-injection](https://angular.io/guide/dependency-injection) for more info on providers and Angular DI

See [https://ionicframework.com/docs/components/\#navigation](https://ionicframework.com/docs/components/#navigation) for more info on Ionic pages and navigation.

See Angular AsyncPipe

See Observables vs Promises

* Create provider:
  *

ionic generate --providersDir src/app/core provider address-service
```
  • Create page into that provider:
    • ionic generate --pagesDir src/app/ page address-list
      
  • Check the created provider into VSC. There is code that coud generate errors, please delete them at this time. Http references and rx. So the component looks like:

    • import { Injectable } from '@angular/core';
      
      @Injectable()
      export class AddressServiceProvider {
      
        constructor() {
          console.log('Hello AddressServiceProvider Provider');
        }
      
      }
      
  • Check the Address-list page in VSC. The address-list.html. Async tells Angular to wait for Promises resolves.`` indicates Angular to execute toString automatically (the string representation).

    • <ion-content padding>
      
        <div class="wr-well">
          <h1>Travel where you want</h1>
          <h6>Make sure emergency services can always find you.
            Select your current location below.
          </h6>
          <ion-card *ngFor="let address of addresses | async">
            <ion-item>
              <ion-icon item-right name="locate" (click)="selectLocation(address)"></ion-icon>
              <ion-icon item-left large [name]="address.icon"></ion-icon>
              <srtong color="dark"></srtong>
              <p> <br /> Last selected: </p>
            </ion-item>
          </ion-card>
        </div>
      </ion-content>
      
  • See address.list.ts. Using promises returned by service provider.

    • import { Component } from '@angular/core';
      import { IonicPage, NavController, NavParams } from 'ionic-angular';
      import { Address } from '../core/address';
      import { AddressServiceProvider } from '../core/address-service/address-service';
      import { HomePage } from '../../pages/home/home';
      
      @IonicPage()
      @Component({
        selector: 'page-address-list',
        templateUrl: 'address-list.html',
      })
      export class AddressListPage {
      
        public addresses : Promise<Address[]>;
      
        constructor(public navCtrl: NavController, private addressService : AddressServiceProvider ) {
        }
      
        ionViewDidLoad() {
          console.log('ionViewDidLoad AddressListPage');
          this.addresses = this.addressService.fetchAll();
        }
      
        selectLocation(address: Address) {
          this.navCtrl.setRoot(HomePage, { address });
        }
      }
      
  • Connect with home page, into home.html, home.ts and address-list.scss respectively

    • // Into fab-list
      <button ion-fab (click)="gotoLocations(fab)">
              <ion-icon name="locate"></ion-icon>
      </button>
      
    • gotoLocations(fab: FabContainer) {
          fab.close();
          this.navCtrl.setRoot('AddressListPage');
        }
      
    • page-address-list {
          ion-content {
              background: url(../assets/images/east-road-sign.jpg) no-repeat center center fixed;
              background-size: cover;
          }
      }
      

Steps Add Google Maps Integration to Home Page

Learn: Providers

Steps:

  • Add Google Maps library
    • npm install @agm/core --save
      
  • Add Module to app.module.ts

    • import {AgmCoreModule} from '@agm/core';
      
      // imports array
      imports [
      ...
      AgmCoreModule.forRoot()
      ]
      
  • Update home.html using the map:

    • <ion-content padding>
        <agm-map [latitude]="getLatitude()" [longitude]="getLongitude()" [zoom]="18">
          <agm-marker [latitude]="getLatitude()" [longitude]="getLongitude()">
            <agm-info-window [disableAutoPan]="true">
              <div *ngIf="located">
                <strong>
                  Current location:
                </strong>
                <br /> 
              </div>
              <div *ngIf="!located">
                <strong>
                  Not protected
                </strong>
                <br /> Current location(estimated)
              </div>
            </agm-info-window>
          </agm-marker>
        </agm-map>
      
        ..
          <div class="wr-well wr-float">
          <h1 *ngIf="located">Congratulations, you are protected!</h1>
          <h1 *ngIf="!located" class="danger">Please set your current location</h1>
        </div>
      </ion-content>
      
  • Update home.scss

    • page-home {
          agm-map {
              height: 100%;
              width: 100%;
          }
      }
      
  • Update home.ts

    • ...
      export class HomePage {
      
        address: Address;
      
        defaultMapInfo = {
          lat: 40.429761,
          lng: -111.8952174
        };
      
        located = false;
      
        constructor(public navCtrl: NavController, private navParams : NavParams) {
          this.address = navParams.data.address;
          if (this.address) {
            this.located = true;
          }
        }
      
        getLatitude() : number {
          return this.located ? Number( this.address.latitude ) : this.defaultMapInfo.lat;
        }
      
        getLongitude() : number {
          return this.located ? Number( this.address.longitude ) : this.defaultMapInfo.lng;
        }
      ...
      
  • Result

https://developer.here.com/lp/mapAPIs?cid=API-Google-MM-T4-Dev-Generic-BMM&utm_medium=paidsearch&utm_campaign=2017_Dev-account_ENT_API&gclid=CjwKCAiA_c7UBRAjEiwApCZi8eYxy27k0nHAH3frWuZrnAk6gwnaPGkpbWfoJo9qdkNORs0t3-rDVhoCf6cQAvD_BwE

https://developers.google.com/maps/documentation/javascript/get-api-key?hl=es-419

To use Google API key:

imports: [
...
AgmCoreModule:.forRoot( {apiKey: '<YOU API KEY GOES HERE>'}) 
]

Electron turns the Web App into a Desktop App which run on Windows or MacOS

Interacting with the Host

Electron uses ES6, Ionic uses Typescript.

Demo: Add electron, application title and icon, menu bar, system tray, ui tweaks

What is Electron?

Now in Electron 2 Beta 1 (21 Feb 2018)

Electron 1.8.2 is stable version (2 Feb 2018)

Set of libraries build on top of Node and Chromium. As Cordova is for Mobile apps, Electron is por Desktop apps.

Electron consists of two process: Main process (to connecting with host operating system) and Rendered Process (related to t the web app been displayed).

What platforms Electron supports?

MacOs 10.9 and later; Windows 7 and later (32 and 64 bit); Linux (32 and 64 bit). For Android and iOS apps.

Which does language Electron use?

ES6 is the default. So it is good to use ES6 for Electron and Typescript for Ionic to avoid difficulties. It is good to learn both languages.

https://electronjs.org/docs

https://github.com/electron/electron/blob/v2.0.0-beta.1/docs/tutorial/about.md

https://electronjs.org/releases

Adding Electron to Dispatcher

Install Electron

npm config set proxy http://Z462725:[email protected]:8020
npm install electron --save-dev

Steps

How to integrate Electron and Ionic? We need to lunch Electron first and tell it about Ionic app.

  1. Create a bootstrap file. Electron will launch this file and this file needs to configure and run the Ionic app. https://electronjs.org/docs and https://electronjs.org/docs/tutorial/quick-start
    1. mkdir server
      cd server
      touch main.js
      
  2. Into the main.js: https://electronjs.org/docs/api/browser-window

    1. ```
      const { app, BrowserWindow } = require('electron'); // provider by electron
      const path = require('path'); // provided by node
      const url = require('url'); // provided by node

    let win

    // This method will be called when Electron has finished initialization
    // and is ready to create browser windows. Some APIs can only be used
    // after this event occurs
    app.on('ready', createWindow);

    function createWindow() {

       // Create the browser window  
       win = new BrowserWindow\( {width: 800, height: 600}\);
    
       // and load the index.html of the app
       // Tell Electron to open its internal Chromium browser to the ionic app
       win.loadURL(url.format({
           pathname: path.join(__dirname, '../www/index.html'),
           protocol: 'file:',
           slashes: true
       }));
    
       // Open dev tools, it is optional
       // win.webContents.openDevTools();
    
       // Emitted when the window is closed
       win.on('closed', () => {
           win = null;
       });
    

    }

    // Quit when all windows are closed
    app.on('window-all-closed', () => {

       // On MacOS it is common for applications and their menu bar to stay active until  
       // the user quits explicitly with cmd + Q  
       if \(process.platform != 'darwin'\) {  
           app.quit\(\);  
       }  
    

    });

    // On MacOS is common to recreate a window in the app when the dock icon is clicked and
    // there are no other windows open
    app.on('activate', () => {

       if \(win === null\) {  
           createWindow\(\);  
       }  
    

    });
    ```

  3. Generate the content in www/. That is executing the build (ionic will build the web app and copy the contents in www folder)

    1. npm run build
  4. Run electron (if it was installed globally)

    1. electron ./server/main.js
      
  5. Instead of that, and because electron was installed as a dev tool, change package.json to add main entry point and start script:
    1.   {
        "name": "dispatcher",
        "version": "0.0.1",
        "author": "Gisela Medina",
        "homepage": "http://ionicframework.com/",
        "main": "server/main.js",
        "private": true,
        "scripts": {
          "start": "electron .",
          "clean": "ionic-app-scripts clean",
          "build": "ionic-app-scripts build",
          "lint": "ionic-app-scripts lint",
          "ionic:build": "ionic-app-scripts build",
          "ionic:serve": "ionic-app-scripts serve"
        },
      
  6. Run
    1. npm start
      
  7. This way the app is running into an electron shell instead of browser, but it seems the same. F12 to see the dev tools, it must work.

Fixing the window title

Electron is a wrapper for the Ionic app, and first it runs the Electron browser window with its title and after the Ionic App is served. The title text is changed between page and page in Ionic. To solve the problem, delete all title tag in HTML pages (index, setup and address-list) and let Electron title be the main.

Changes in main.ts, you need to run: npm start

But electron does not know about Ionic changes so it is necessary to run also the build for Ionic: npm run build & npm start

Setting the application icon

To proxy HTTP requests perform

aa

References

https://app.pluralsight.com/player?course=ionic-electron-building-cross-platform-apps&author=michael-callaghan&name=8bf25424-2572-4228-b8f9-a739c75dc44d&clip=0&mode=live

https://angular.io/guide/styleguide

https://ionicframework.com/docs/cli/configuring.html#using-a-proxy

results matching ""

    No results matching ""