Ionic Tutorials: Working with electron(API's)

in utopian-io •  6 years ago 

ionic.jpg
image source

Repository: Ionic Github Repository

Software Requirements:
Visual Studio Code(Or any preferred code editor),
npm, ionic.

What you will learn:
In this tutorial you would learn about how to manage your ionic app on whatever platform you choose to target covering these major concepts

  • How to startup up an ionic-electron project
  • Understanding Renderer and Main processes while in use with ionic
  • How to make electron native API calls based on function

Tutorial

Javacript is bigger and better and ever, you can use it to build almost anything across almost any platform. But what if you could you a single code base for every platform on every device. Yes it is possible and you can use ionic for you and logic across all your platforms.

What is electron?
Electron is a framework for building desktop applications. It is build based on chromium and gives a variety of native api's that help you do alot of relevant native stuff. To read more about it, you could simply follow this link as it is already well documented.

On the other hand, i would be showing you how to combine ionic with electron. These are two independent platforms but can be used together to prevent having to build the same app from the start all over again.

How to start up an ionic-electron application

Getting started can be quite confusing and as more releases become available the simple google search doesn't give you the right way to go about it. Electron has a basic project structure, which only needs three essential files.

your-app/
├── package.json
├── main.js
└── index.html

But ionic has a rather different file structure.

 ├── <PROJECT_ROOT>
        └── /src
            └── /app                                  -  App Module
                ├── app.component.ts
                ├── app.html
                ├── app.module.ts
                ├── app.scss
                ├── main.ts
                └── /core                             - Core Feature Module (e.g., Singleton Services/Providers)
                    ├── core.module.ts
                    ├── module-import-guard.ts  
                    └── /logger
                        ├── console-logger.service.ts
                        ├── logger.service.ts                               
                └── /pages                            - Page (Component) Modules
                    └── /home
                        ├── home.page.html
                        ├── home.page.module.ts 
                        ├── home.page.scss   
                        ├── home.page.spec.ts
                        ├── home.page.ts                                                                                                               
                └── /shared                           - Shared Feature Module (shared Components, Directives and Pipes)
                    ├── shared.module.ts                
            └── /assets
            └── /environments                         - Environment specific configuration   
                ├── environment.dev.ts
                ├── environment.ts                        
            └── /theme
                ├── facebook-messenger-theme.scss            
                ├── gradient-mixins.scss
                ├── gradient.scss
                ├── green-and-blue-theme.scss                    
                ├── variables.scss
            ├── index.html
            ├── manifest.json
            ├── service-worker.js
        └── /config                                   - Webpack Configuration
            ├── webpack.config.json
        └── /e2e                                      - E2E Test Configuration
            ├── app.e2e-spec.ts
            ├── app.po.ts
            ├── tsconfig.e2e.json
        └── /resources                                - Default Resources (e.g., Icon and Splash)
        └── /www                                      - Ionics 'dist' directory
            └── /assets
            └── /build   
            ├── index.html
            ├── manifest.json
            ├── service-worker.js
        ├── .editorconfig
        ├── .gitignore
        ├── config.xml
        ├── ionic.config.json
        ├── karma.conf.json           
        ├── package.json
        ├── protractor.conf.json
        ├── README.md     
        ├── tsconfig.json
        ├── tsconfig.ng-cli.json        
        ├── tslint.json             

This is the structure of a typical ionic 4 application. Note however that this will work for an ionic 3 project. If you have any problems however you can leave a comment below.

How do they work together
When you build an ionic app it compiles your code into a www folder which i like to call the main soup. All we have to do when using it with electron is open a browser window with the native electron api and load the www folder into this window. Easy as pie.

So lets get started

//Start a new ionic project --type=ionic-angular
ionic start  newproject Blank

//install electron as a development dependency
npm install electron --save-dev
//Yarn should have the same command

Next thing would be simply to create a main.js file like the one shown in our electron directory and help make it identifiable from our package.json. Add this to your package.json after making the main.js file.

.......
"main": "main.js"
.....

In our main.js file just as stated earlier we would have to make a new browser window and inject the www files into it. Simply do this

const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const path = require('path')
const url = require('url')

let win, serve
const args = process.argv.slice(1)
serve = args.some(val => val === '--serve')

function createWindow () {
  win = new BrowserWindow({
    width: 1800,
    height: 1200,
    center: true,
    icon: path.join(__dirname, './resources/electron/icons/64x64.png')
  })

  if (serve) {
    require('electron-reload')(__dirname, {
      electron: require(`${__dirname}/node_modules/electron`)
    })
    win.loadURL('http://localhost:4200')
  } else {
    win.loadURL(url.format({
      pathname: path.join(__dirname, 'www/index.html'),
      protocol: 'file:',
      slashes: true
    }))
  }

  win.webContents.openDevTools()

  // Emitted when the window is closed.
  win.on('closed', () => {
    // Dereference the window object, usually you would store window
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
  })
}
try {
  // 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)

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    // On OS X 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()
    }
  })

  app.on('activate', () => {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (win === null) {
      createWindow()
    }
  })
} catch (e) {
  // Catch Error
  // throw e;
}

And then we can run this application by building from ionic and then running electron. Add this to your scripts so you can do this from your command-line.

..Package.json
....Other code here

//Your scripts should be exactly this
"scripts": {
    "debug-main": "electron --inspect-brk=5858 .",
    "build": "ionic-app-scripts build",
    "clean": "ionic-app-scripts clean",
    "dev": "gulp dev",
    "lint": "ionic-app-scripts lint",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve",
    "ionic:watch": "ionic-app-scripts watch",
    "start": "npm run build && electron .",
  },

We can begin by running

npm start

And this should be the resultbrowser-ionic-blank.png

Understanding the main and renderer processes

This is one of the major concepts you need to understand to successfully build an electron application.
The application runs with multiple processes based on function. Chromium is built this way so that if one window of an application crashes, it does not destroy the whole application. Some apis can be called from the main process, while others can be called from renderer processes. For a full list click Here.

Ionic runs in a renderer process. Meaning that you cannot make main process calls through ionic. You would need to use ipc to send a message to the main process to make that call. To send this messages appriopriately, there is an awesome angular module called Ngx-Electron-Module.
This is what we would use to make the api calls.

Making API calls

First thing you need to do is install the ngx-electron module and add it to your imports

npm install ngx-electron --save-dev

Then
...

\\...Other code here

mport { NgxElectronModule } from 'ngx-electron'

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, NgxElectronModule],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

We can now proceed to making api calls like this

import { ElectronService } from 'ngx-electron'
import { Platform, Events } from '@ionic/angular'
...

constructor(public electron: ElectronService, private platform: Platform, private events: Events) {}
...

public setup() {
    const ctx = this
    console.log('Setting up the application database')

    ctx.electron.ipcRenderer.sent('asyncronous-message','ping')//Make the api call
}

And we receive it from main.js like

ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.sender.send('asynchronous-reply', 'pong')
})

Thanks for reading, Hope you found it helpful.
Find the code in Github

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Thank you for your contribution @yalzeee.
We've been reviewing your contribution and suggested the following points for your next tutorial:

  • We suggest you put more images of the results than you are explaining. Images help make the tutorial more enjoyable to read.

  • The comments in the code were fine, but you need to explain in more detail about the code section that you put in your tutorial.

Thank you for your work in developing this tutorial.
Looking forward to your upcoming tutorials.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

Thank you for your review, @portugalcoin! Keep up the good work!

Great tutorial!!!

Posted using Partiko Android

Thanks
Glad you like it

Hi @yalzeee!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @yalzeee!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Hi. I am part of this project to increase the number of Steem minnows (over 500 SP). You are pretty close and I wonder if you would like some support to get there. We just ask that you do a post committing to powering up and sticking with Steem using the tag #TenKMinnows. If you are interested then please reply to this.