Ionic
Contents
Ionic Framework is an open source mobile UI toolkit for building high quality, cross-platform native and web app experiences.
It uses typescript and Angular.
QR code scanner
Bar code scanner
Run chrome
1 "/C/Program Files (x86)/Google/Chrome/Application/chrome.exe" --disable-web-security --disable-gpu --user-data-dir="c:\TempChrome" --disable-features=SameSiteByDefaultCookies,SameSiteDefaultChecksMethodRigorously
2 # In Linux
3 google-chrome --disable-web-security --disable-gpu --user-data-dir="/tmp" --disable-features=SameSiteByDefaultCookies,SameSiteDefaultChecksMethodRigorously
Example app
- Requires Android SDK, node 12.16.2 and npm 6.14.5
1 cd ~
2 mkdir IonicTest
3 npm install @ionic/cli
4 node_modules/.bin/ionic start IonicTest
5 #framework angular
6 #starter template tabs
7 #integrate capacitor N
8 #create free ionic account N
9 cd IonicTest
10 npm i
11 npm install @ionic/cli
12 npm install cordova
13 npm install cordova-res
14 node_modules/.bin/ionic cordova plugin add cordova-plugin-advanced-http
15 npm install @ionic-native/http
16 node_modules/.bin/ionic cordova platform add android
17 node_modules/.bin/ionic cordova build android
18 scp ./platforms/android/app/build/outputs/apk/debug/app-debug.apk userx@example.net:/home/userx/www/ionic-test.apk
19 node_modules/.bin/ionic cordova platform add browser
20 node_modules/.bin/ionic cordova build browser
21 node_modules/.bin/ionic serve --cordova --platform=browser
22 # http://localhost:8100
23 # no CORS
24 google-chrome --disable-web-security --disable-gpu --user-data-dir="/tmp"
app.module.ts
1 import { NgModule } from '@angular/core';
2 import { BrowserModule } from '@angular/platform-browser';
3 import { RouteReuseStrategy } from '@angular/router';
4 import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
5 import { SplashScreen } from '@ionic-native/splash-screen/ngx';
6 import { StatusBar } from '@ionic-native/status-bar/ngx';
7 import { AppRoutingModule } from './app-routing.module';
8 import { AppComponent } from './app.component';
9 import { HTTP } from '@ionic-native/http/ngx';
10 import { FirebaseMessaging } from '@ionic-native/firebase-messaging/ngx';
11 import { Device } from '@ionic-native/device/ngx';
12 import { SQLite } from '@ionic-native/sqlite/ngx';
13 import { DbService } from './db.service';
14 import { NotifierService } from './notifier.service';
15
16 @NgModule({
17 declarations: [AppComponent],
18 entryComponents: [],
19 imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
20 providers: [
21 HTTP,
22 StatusBar,
23 SplashScreen,
24 { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
25 FirebaseMessaging,
26 Device,
27 SQLite,
28 DbService,
29 NotifierService
30 ],
31 bootstrap: [AppComponent]
32 })
33 export class AppModule { }
app.component.ts
1 import { Component } from '@angular/core';
2 import { Device } from '@ionic-native/device/ngx';
3 import { Platform } from '@ionic/angular';
4 import { SplashScreen } from '@ionic-native/splash-screen/ngx';
5 import { StatusBar } from '@ionic-native/status-bar/ngx';
6 import { FirebaseMessaging } from '@ionic-native/firebase-messaging/ngx';
7 import { HTTP } from '@ionic-native/http/ngx';
8 import { DbService } from './db.service';
9 import { NotifierService } from './notifier.service';
10
11 @Component({
12 selector: 'app-root',
13 templateUrl: 'app.component.html',
14 styleUrls: ['app.component.scss']
15 })
16 export class AppComponent {
17
18 constructor(
19 private platform: Platform,
20 private splashScreen: SplashScreen,
21 private statusBar: StatusBar,
22 private firebaseMessaging: FirebaseMessaging,
23 private http: HTTP,
24 private device: Device,
25 private dbservice: DbService,
26 private notifier: NotifierService
27 ) {
28 this.initializeApp();
29 }
30
31 initializeApp() {
32 this.platform.ready().then(() => {
33 this.statusBar.styleDefault();
34 this.splashScreen.hide();
35 this.handleNotifications();
36 });
37 }
38
39 private fcmGetToken() {
40 this.firebaseMessaging.getToken().then((token: any) => {
41 let url: string = "https://example.org/logit.php";
42 let body: any = { "devUUID": this.device.uuid };
43 console.log("Body:" + JSON.stringify(body));
44 this.http.post(url, body, {}).then(data => {
45 console.log(data.status);
46 console.log(data.data); // data received by server
47 console.log(data.headers);
48 // subscribe to topic with token name
49 this.firebaseMessaging.subscribe(this.device.uuid);
50 })
51 .catch(error => {
52 alert("Error " + JSON.stringify(error.error));
53 });
54 });
55 }
56
57 private handleNotifications() {
58 this.firebaseMessaging.requestPermission().then(() => {
59 this.fcmGetToken();
60
61 this.firebaseMessaging.onTokenRefresh().subscribe(() => {
62 this.fcmGetToken();
63 });
64
65 this.firebaseMessaging.onMessage().subscribe((payload: any) => {
66 this.dbservice.insertPush("fg msg " + payload.body);
67 this.notifier.notify(NotifierService.GOT_PUSH);
68 });
69
70 this.firebaseMessaging.onBackgroundMessage().subscribe((payload: any) => {
71 this.dbservice.insertPush("back msg " + payload.body);
72 this.notifier.notify(NotifierService.GOT_PUSH);
73 });
74 });
75 }
76 }
tab1.page.ts
1 import { Component } from '@angular/core';
2 import { HTTP } from '@ionic-native/http/ngx';
3
4 @Component({
5 selector: 'app-tab1',
6 templateUrl: 'tab1.page.html',
7 styleUrls: ['tab1.page.scss']
8 })
9 export class Tab1Page {
10 public res;
11
12 constructor(private http: HTTP) {}
13
14 public ionViewDidEnter(){
15 console.log("Stuff");
16 this.http.get("https://labs.bitarus.allowed.org/xapps/rest/version/", {}, {})
17 .then(data => {
18 console.log(data.status);
19 console.log(data.data); // data received by server
20 this.res=data.data;
21 console.log(data.headers);
22 })
23 .catch(error => {
24 console.log(error.status);
25 console.log(error.error); // error message as string
26 console.log(error.headers);
27 });
28 }
29 }
tab1.page.html
1 <ion-header [translucent]="true">
2 <ion-toolbar>
3 <ion-title>
4 Tab 111 {{res}}
5 </ion-title>
6 </ion-toolbar>
7 </ion-header>
8
9 <ion-content [fullscreen]="true">
10 <ion-header collapse="condense">
11 <ion-toolbar>
12 <ion-title size="large">Tab 111</ion-title>
13 </ion-toolbar>
14 </ion-header>
15
16 <app-explore-container name="Tab 111 page {{res}}"></app-explore-container>
17 </ion-content>
tab2.page.html
1 <ion-header [translucent]="true">
2 <ion-toolbar>
3 <ion-title>
4 Sum
5 </ion-title>
6 </ion-toolbar>
7 </ion-header>
8 <ion-content [fullscreen]="true">
9 <ion-header collapse="condense">
10 <ion-toolbar>
11 <ion-title size="large">Sum</ion-title>
12 </ion-toolbar>
13 </ion-header>
14 <ion-item>
15 <ion-label>Value 1</ion-label>
16 <ion-input [(ngModel)]="in1"></ion-input>
17 </ion-item>
18 <ion-item>
19 <ion-label>Value 2</ion-label>
20 <ion-input [(ngModel)]="in2"></ion-input>
21 </ion-item>
22 <ion-button color="primary" (click)="sumValuesButtonClicked()">Sum values</ion-button>
23 </ion-content>
tab2.page.ts
1 import { Component } from '@angular/core';
2 import { AlertController } from '@ionic/angular';
3
4 @Component({
5 selector: 'app-tab2',
6 templateUrl: 'tab2.page.html',
7 styleUrls: ['tab2.page.scss']
8 })
9 export class Tab2Page {
10 in1:string;
11 in2:string;
12
13 constructor(public alertController: AlertController) {}
14
15 sumValuesButtonClicked(){
16 let res:Number;
17 res = parseInt(this.in1) + parseInt(this.in2);
18 this.presentResult(res).then(()=>{
19 console.log("Done");
20 });
21 }
22
23 async presentResult(res:Number) {
24 const alert = await this.alertController.create({
25 header: 'Sum',
26 subHeader: 'Result',
27 message: res.toString(),
28 buttons: ['OK'],
29 });
30
31 await alert.present();
32 let result = await alert.onDidDismiss();
33 console.log(result);
34 }
35 }
tab3.page.html
1 <ion-header [translucent]="true">
2 <ion-toolbar>
3 <ion-title>
4 Push notifications list
5 </ion-title>
6 </ion-toolbar>
7 </ion-header>
8
9 <ion-content [fullscreen]="true">
10 <ion-header collapse="condense">
11 <ion-toolbar>
12 <ion-title size="large">Push notifications list</ion-title>
13 </ion-toolbar>
14 </ion-header>
15 <ul>
16 <li *ngFor="let pushNotification of items">
17 {{pushNotification}}
18 </li>
19 </ul>
20 </ion-content>
notifier.service.ts
- ./node_modules/.bin/ionic generate service notifier
1 import { Injectable } from '@angular/core';
2
3 @Injectable({
4 providedIn: 'root'
5 })
6 export class NotifierService {
7 static readonly GOT_PUSH: 'GotPush';
8
9 private actions: string[];
10 private callbacks: Function[];
11
12 constructor() {
13 this.actions = [];
14 this.callbacks = [];
15 }
16
17 /**
18 * Subscribe a callback to an action
19 * @param action
20 * @param callback
21 */
22 public subscribe(action: string, callback: Function) {
23 this.actions.push(action);
24 this.callbacks.push(callback);
25 }
26
27 public notify(action: string) {
28 let idx: number;
29 idx = -1;
30 for (idx = 0; idx < this.actions.length; idx++) {
31 if (this.actions[idx] == action) {
32 break;
33 }
34 }
35
36 if (idx != -1) {
37 this.callbacks[idx]();
38 }
39 }
40 }
tab3.page.ts
1 import { ChangeDetectorRef, Component } from '@angular/core';
2 import { DbService } from '../db.service';
3 import { NotifierService } from '../notifier.service';
4
5 @Component({
6 selector: 'app-tab3',
7 templateUrl: 'tab3.page.html',
8 styleUrls: ['tab3.page.scss']
9 })
10 export class Tab3Page {
11 public items: string[];
12
13 constructor(private dbService: DbService, private notifier: NotifierService, private changeDetectionRef: ChangeDetectorRef
14 ) {
15 this.updateData();
16 this.notifier.subscribe(NotifierService.GOT_PUSH, this.gotPush.bind(this));
17 //setInterval(this.refresh.bind(this), 5000);
18 }
19
20 // private refresh() {
21 // // triggers change detection when called by setInterval
22 // }
23
24 public gotPush() {
25 try {
26 this.updateData();
27 } catch (e) {
28 alert("Caught error in gotPush");
29 }
30 }
31
32 public updateData() {
33
34 this.dbService.getNotifications().then((data: string[]) => {
35 this.items = data;
36 this.changeDetectionRef.detectChanges();
37 });
38 }
39
40 public ionViewDidEnter() {
41 this.updateData();
42 }
43 }
db.service.ts
- ./node_modules/.bin/ionic generate service db
1 import { Injectable } from '@angular/core';
2 import { SQLite, SQLiteObject } from '@ionic-native/sqlite/ngx';
3
4 @Injectable({
5 providedIn: 'root'
6 })
7 export class DbService {
8
9 constructor(private sqlite: SQLite) {
10 }
11
12 private getDb(): Promise<SQLiteObject> {
13 let async: Promise<SQLiteObject> = new Promise<SQLiteObject>((resolve, reject) => {
14 let promise = this.sqlite.create({
15 name: 'data.db',
16 location: 'default'
17 });
18
19 promise.then((db: SQLiteObject) => {
20 db.executeSql('CREATE TABLE IF NOT EXISTS PushNotificationsTable (push text)', [])
21 .then(() => {
22 resolve(db);
23 })
24 .catch((e) => { reject('Table not created ' + JSON.stringify(e)); });
25 });
26
27 promise.catch(e => reject("Create db error " + JSON.stringify(e)));
28 });
29
30 return async;
31 }
32
33 public insertPush(body: string) {
34 this.getDb().then((db: SQLiteObject) => {
35 if (db != null) {
36 db.executeSql('INSERT INTO PushNotificationsTable VALUES (?)', [body])
37 .then(() => {
38 })
39 .catch(e => alert("Insert error " + JSON.stringify(e)));
40 } else {
41 alert('insertPush: this.db is null');
42 }
43 });
44 }
45
46 public getNotifications(): Promise<string[]> {
47 let asyncTask: Promise<string[]> = new Promise<string[]>((resolve, reject) => {
48
49 this.getDb().then((db: SQLiteObject) => {
50 if (db != null) {
51 db.executeSql('SELECT * FROM PushNotificationsTable', []).then((data) => {
52 let items: string[];
53 items = [];
54 for (let i = 0; i < data.rows.length; i++) {
55 let item = data.rows.item(i);
56 items.push(item.push);
57 }
58 resolve(items);
59 }).catch((e) => {
60 reject(e);
61 });
62 } else {
63 alert('getNotifications: this.db is null');
64 reject('getNotifications: this.db is null');
65 }
66 });
67 });
68
69 return asyncTask;
70 }
71 }
EchoPlugin
- www/EchoPlugin.js
- echo-plugin/plugin.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
3 id="org.allowed.bitarus.EchoPlugin"
4 version="1.0.0">
5 <name>echo-plugin</name>
6 <description>echo plugin</description>
7 <license>null</license>
8
9 <js-module src="www/EchoPlugin.js" name="EchoPlugin">
10 <clobbers target="EchoPlugin" />
11 </js-module>
12
13 <platform name="android">
14 <config-file target="res/xml/config.xml" parent="/*">
15 <feature name="EchoPlugin" >
16 <param name="android-package" value="org.allowed.bitarus.EchoPlugin"/>
17 </feature>
18 </config-file>
19 <config-file target="AndroidManifest.xml" parent="/*">
20 <uses-permission android:name="android.permission.INTERNET" />
21 </config-file>
22 <source-file src="src/main/java/org/allowed/bitarus/EchoPlugin.java" target-dir="src/org/allowed/bitarus" />
23 </platform>
24 </plugin>
- echo-plugin/package.json
1 {
2 "name": "org.allowed.bitarus.echoplugin",
3 "version": "1.0.0",
4 "description": "Echo plugin",
5 "cordova": {
6 "id": "org.allowed.bitarus.echoplugin",
7 "platforms": [
8 "android"
9 ]
10 },
11 "keywords": [
12 "ecosystem:cordova",
13 "cordova-android"
14 ],
15 "author": "Vitor",
16 "license": "null"
17 }
- echo-plugin/src/main/java/org/allowed/bitarus/EchoPlugin.java
1 package org.allowed.bitarus;
2
3 import org.apache.cordova.CordovaPlugin;
4 import org.apache.cordova.CallbackContext;
5 import org.json.JSONArray;
6 import org.json.JSONException;
7 import org.json.JSONObject;
8 import org.apache.cordova.CordovaWebView;
9 import org.apache.cordova.CordovaInterface;
10
11 public class EchoPlugin extends CordovaPlugin {
12 @Override
13 public void initialize(CordovaInterface cordova, CordovaWebView webView) {
14 super.initialize(cordova, webView);
15 }
16
17 @Override
18 public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
19 if (action.equals("echo")) {
20 String message = "Echo " + args.getString(0) + " !!!";
21 this.echo(message, callbackContext);
22 return true;
23 }
24
25 if (action.equals("getintentdata")) {
26 this.getintentdata(callbackContext);
27 return true;
28 }
29
30
31 return false;
32 }
33
34 private void echo(String message, CallbackContext callbackContext) {
35 if (message != null && message.length() > 0) {
36 callbackContext.success(message);
37 } else {
38 callbackContext.error("Expected one non-empty string argument.");
39 }
40 }
41
42 private void getintentdata(CallbackContext callbackContext) {
43 String data = this.cordova.getActivity().getIntent().getDataString() ;
44 String action = this.cordova.getActivity().getIntent().getAction();
45 String result = String.format( "{\"data\":\"%s\" , \"action\":\"%s\"}",data,action );
46 callbackContext.success(result);
47 }
48 }
- tab1.page.ts
1 import { Component } from '@angular/core';
2 import { HTTP } from '@ionic-native/http/ngx';
3 import { Platform } from '@ionic/angular';
4
5 declare let cordova: any;
6
7 @Component({
8 selector: 'app-tab1',
9 templateUrl: 'tab1.page.html',
10 styleUrls: ['tab1.page.scss']
11 })
12 export class Tab1Page {
13 public res;
14 public echo: string;
15
16 constructor(private http: HTTP, private platform: Platform) {
17
18 this.platform.ready().then(() => {
19 this.init();
20 }
21 );
22
23 }
24
25 public init() {
26 this.getEcho();
27 }
28
29 getEcho() {
30 if (this.platform.is('cordova')) {
31 try {
32 cordova.exec(
33 (success) => {
34 this.echo = success;
35 },
36 (error) => { },
37 //feature name in /home/vitor/MyIonicProject/echo-plugin/plugin.xml
38 //feature name in /home/vitor/MyIonicProject/platforms/android/app/src/main/res/xml/config.xml
39 "EchoPlugin", // class Service name
40 "echo", // action
41 ["argxyz"] // arguments
42 );
43 } catch (e) {
44 this.echo = "Got error in get echo " + JSON.stringify(e) + e.message;
45 }
46 }
47 }
48
49 public ionViewDidEnter() {
50 console.log("Stuff");
51 this.http.get("https://labs.bitarus.allowed.org/version/", {}, {})
52 .then(data => {
53 console.log(data.status);
54 console.log(data.data); // data received by server
55 this.res = data.data;
56 console.log(data.headers);
57 })
58 .catch(error => {
59 console.log(error.status);
60 console.log(error.error); // error message as string
61 console.log(error.headers);
62 });
63 }
64 }
- tab1.page.html
1 <ion-header [translucent]="true">
2 <ion-toolbar>
3 <ion-title>
4 Tab 111 {{res}}
5 </ion-title>
6 </ion-toolbar>
7 </ion-header>
8 <ion-content [fullscreen]="true">
9 <ion-header collapse="condense">
10 <ion-toolbar>
11 <ion-title size="large">Tab 111</ion-title>
12 </ion-toolbar>
13 </ion-header>
14 <app-explore-container name="Tab 111 page {{res}} {{echo}}"></app-explore-container>
15 </ion-content>
SQLite
- npm install @ionic-native/sqlite
- node_modules/.bin/ionic cordova plugin add cordova-sqlite-storage
Create page
- node_modules/.bin/ionic generate page test
Create service
- node_modules/.bin/ionic generate service notifier
- Add in providers in app.module.ts
- Inject in constructor of classes that might use the dependency/bean/service
Angular change detection
In short, the framework will trigger a change detection if one of the following events occurs: any browser event (click, keyup, etc.) setInterval() and setTimeout() HTTP requests via XMLHttpRequest
Setup environment debian bullseye
setup_debian.sh
1 cd ~
2 rm -rf android/
3 rm -rf gradle-7.4.2/
4 rm -rf jdk8u222-b10/
5 wget https://downloads.gradle-dn.com/distributions/gradle-7.4.2-bin.zip
6 unzip gradle-7.4.2-bin.zip
7 sudo apt install -y curl sudo wget net-tools nodejs unzip
8 wget https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz
9 tar xvzf OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz
10 wget https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip
11 mkdir ~/android
12 unzip commandlinetools-linux-6858069_latest.zip
13 mv cmdline-tools/ ~/android/
14 cd ~/android/cmdline-tools/ && mkdir latest && mv bin/ lib/ NOTICE.txt source.properties latest/
15 echo "export ANDROID_HOME=$HOME/android/" >> ~/.bashrc
16 echo "export ANDROID_SDK_ROOT=$HOME/android/" >> ~/.bashrc
17 echo "export PATH=/usr/local/bin:/usr/bin:/bin:$HOME/jdk8u222-b10/bin:$HOME/gradle-7.4.2/bin" >> ~/.bashrc
18 echo "export JAVA_HOME=$HOME/jdk8u222-b10/" >> ~/.bashrc
19 cat ~/.bashrc
20 source ~/.bashrc
21 $HOME/android/cmdline-tools/latest/bin/sdkmanager --update
22 $HOME/android/cmdline-tools/latest/bin/sdkmanager --version
23 yes | $HOME/android/cmdline-tools/latest/bin/sdkmanager --install "build-tools;30.0.3"
24 $HOME/android/cmdline-tools/latest/bin/sdkmanager --list # should show installed packages
25
setup_ionic_debian.sh
1 #!/bin/sh
2 rm IonicTest -rf
3 rm node_modules -rf
4 npm install @ionic/cli
5 node_modules/.bin/ionic start ITest --type angular tabs
6 # angular, tabs, share anon data: no, create ionic account: no,
7 cd ITest
8 npm i
9 npm i @ionic/cli
10 npm i cordova
11 npm i cordova-res
12 node_modules/.bin/ionic integrations disable capacitor
13 node_modules/.bin/ionic cordova plugin add cordova-plugin-advanced-http
14 npm i @ionic-native/http
15 npm i typescript
16 npm i @angular/cli
17 npm i @angular/core
18 npm i @angular/compiler-cli
19 npm i @angular/compiler
20 npm i @angular/forms
21 npm i @angular/common
22 npm i @angular/platform-browser-dynamic
23 npm i @angular/router
24 npm i angular
25 npm i @ionic/angular
26 npm i @angular/platform-browser
27 npm i zone.js
28
29 node_modules/.bin/ionic cordova platform add android
30 node_modules/.bin/ng add @ionic/cordova-builders
31 # remove from platforms/android/gradlew the --illegal-access = permit
32 # vi platforms/android/gradlew
33 node_modules/.bin/ionic cordova build android # no to report statistics
34 #node_modules/.bin/ionic cordova platform add browser
35 #node_modules/.bin/ionic cordova build browser
36 #node_modules/.bin/ionic serve --cordova --platform=browser
37 #node_modules/.bin/ionic serve --cordova --platform=browser --host 0.0.0.0 --port 8081
38 # http://localhost:8081/
39