Size: 3430
Comment:
|
← Revision 42 as of 2024-07-27 13:22:53 ⇥
Size: 23083
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 2: | Line 2: |
<<TableOfContents(2)>> |
|
Line 5: | Line 7: |
It uses [[typescript]] and [[Angular]]. == QR code scanner == * https://github.com/bitpay/cordova-plugin-qrscanner * https://ionicframework.com/docs/v3/native/qr-scanner/ == Bar code scanner == * https://github.com/phonegap/phonegap-plugin-barcodescanner * https://ionicframework.com/docs/native/barcode-scanner |
|
Line 6: | Line 19: |
{{{ | {{{#!highlight bash |
Line 8: | Line 21: |
# In Linux google-chrome --disable-web-security --disable-gpu --user-data-dir="/tmp" --disable-features=SameSiteByDefaultCookies,SameSiteDefaultChecksMethodRigorously |
|
Line 26: | Line 41: |
node_modules/.bin/ionic cordova plugin add cordova-plugin-advanced-http npm install @ionic-native/http |
|
Line 38: | Line 55: |
{{{ | {{{#!highlight javascript |
Line 42: | Line 59: |
Line 46: | Line 62: |
Line 50: | Line 65: |
import { FirebaseMessaging } from '@ionic-native/firebase-messaging/ngx'; import { Device } from '@ionic-native/device/ngx'; import { SQLite } from '@ionic-native/sqlite/ngx'; import { DbService } from './db.service'; import { NotifierService } from './notifier.service'; |
|
Line 59: | Line 79: |
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy } | { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, FirebaseMessaging, Device, SQLite, DbService, NotifierService |
Line 63: | Line 88: |
export class AppModule {} | export class AppModule { } }}} === app.component.ts === {{{#!highlight javascript import { Component } from '@angular/core'; import { Device } from '@ionic-native/device/ngx'; import { Platform } from '@ionic/angular'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; import { FirebaseMessaging } from '@ionic-native/firebase-messaging/ngx'; import { HTTP } from '@ionic-native/http/ngx'; import { DbService } from './db.service'; import { NotifierService } from './notifier.service'; @Component({ selector: 'app-root', templateUrl: 'app.component.html', styleUrls: ['app.component.scss'] }) export class AppComponent { constructor( private platform: Platform, private splashScreen: SplashScreen, private statusBar: StatusBar, private firebaseMessaging: FirebaseMessaging, private http: HTTP, private device: Device, private dbservice: DbService, private notifier: NotifierService ) { this.initializeApp(); } initializeApp() { this.platform.ready().then(() => { this.statusBar.styleDefault(); this.splashScreen.hide(); this.handleNotifications(); }); } private fcmGetToken() { this.firebaseMessaging.getToken().then((token: any) => { let url: string = "https://example.org/logit.php"; let body: any = { "devUUID": this.device.uuid }; console.log("Body:" + JSON.stringify(body)); this.http.post(url, body, {}).then(data => { console.log(data.status); console.log(data.data); // data received by server console.log(data.headers); // subscribe to topic with token name this.firebaseMessaging.subscribe(this.device.uuid); }) .catch(error => { alert("Error " + JSON.stringify(error.error)); }); }); } private handleNotifications() { this.firebaseMessaging.requestPermission().then(() => { this.fcmGetToken(); this.firebaseMessaging.onTokenRefresh().subscribe(() => { this.fcmGetToken(); }); this.firebaseMessaging.onMessage().subscribe((payload: any) => { this.dbservice.insertPush("fg msg " + payload.body); this.notifier.notify(NotifierService.GOT_PUSH); }); this.firebaseMessaging.onBackgroundMessage().subscribe((payload: any) => { this.dbservice.insertPush("back msg " + payload.body); this.notifier.notify(NotifierService.GOT_PUSH); }); }); } } |
Line 67: | Line 172: |
{{{ | {{{#!highlight javascript |
Line 83: | Line 188: |
this.http.get("https://labs.bitarus.allowed.org/cebapps/r/core/version/", {}, {}) | this.http.get("https://labs.bitarus.allowed.org/xapps/rest/version/", {}, {}) |
Line 100: | Line 205: |
{{{ | {{{#!highlight xml |
Line 119: | Line 224: |
=== tab2.page.html === {{{#!highlight xml <ion-header [translucent]="true"> <ion-toolbar> <ion-title> Sum </ion-title> </ion-toolbar> </ion-header> <ion-content [fullscreen]="true"> <ion-header collapse="condense"> <ion-toolbar> <ion-title size="large">Sum</ion-title> </ion-toolbar> </ion-header> <ion-item> <ion-label>Value 1</ion-label> <ion-input [(ngModel)]="in1"></ion-input> </ion-item> <ion-item> <ion-label>Value 2</ion-label> <ion-input [(ngModel)]="in2"></ion-input> </ion-item> <ion-button color="primary" (click)="sumValuesButtonClicked()">Sum values</ion-button> </ion-content> }}} === tab2.page.ts === {{{#!highlight javascript import { Component } from '@angular/core'; import { AlertController } from '@ionic/angular'; @Component({ selector: 'app-tab2', templateUrl: 'tab2.page.html', styleUrls: ['tab2.page.scss'] }) export class Tab2Page { in1:string; in2:string; constructor(public alertController: AlertController) {} sumValuesButtonClicked(){ let res:Number; res = parseInt(this.in1) + parseInt(this.in2); this.presentResult(res).then(()=>{ console.log("Done"); }); } async presentResult(res:Number) { const alert = await this.alertController.create({ header: 'Sum', subHeader: 'Result', message: res.toString(), buttons: ['OK'], }); await alert.present(); let result = await alert.onDidDismiss(); console.log(result); } } }}} === tab3.page.html === {{{#!highlight xml <ion-header [translucent]="true"> <ion-toolbar> <ion-title> Push notifications list </ion-title> </ion-toolbar> </ion-header> <ion-content [fullscreen]="true"> <ion-header collapse="condense"> <ion-toolbar> <ion-title size="large">Push notifications list</ion-title> </ion-toolbar> </ion-header> <ul> <li *ngFor="let pushNotification of items"> {{pushNotification}} </li> </ul> </ion-content> }}} === notifier.service.ts === * ./node_modules/.bin/ionic generate service notifier {{{#!highlight javascript import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class NotifierService { static readonly GOT_PUSH: 'GotPush'; private actions: string[]; private callbacks: Function[]; constructor() { this.actions = []; this.callbacks = []; } /** * Subscribe a callback to an action * @param action * @param callback */ public subscribe(action: string, callback: Function) { this.actions.push(action); this.callbacks.push(callback); } public notify(action: string) { let idx: number; idx = -1; for (idx = 0; idx < this.actions.length; idx++) { if (this.actions[idx] == action) { break; } } if (idx != -1) { this.callbacks[idx](); } } } }}} === tab3.page.ts === {{{#!highlight javascript import { ChangeDetectorRef, Component } from '@angular/core'; import { DbService } from '../db.service'; import { NotifierService } from '../notifier.service'; @Component({ selector: 'app-tab3', templateUrl: 'tab3.page.html', styleUrls: ['tab3.page.scss'] }) export class Tab3Page { public items: string[]; constructor(private dbService: DbService, private notifier: NotifierService, private changeDetectionRef: ChangeDetectorRef ) { this.updateData(); this.notifier.subscribe(NotifierService.GOT_PUSH, this.gotPush.bind(this)); //setInterval(this.refresh.bind(this), 5000); } // private refresh() { // // triggers change detection when called by setInterval // } public gotPush() { try { this.updateData(); } catch (e) { alert("Caught error in gotPush"); } } public updateData() { this.dbService.getNotifications().then((data: string[]) => { this.items = data; this.changeDetectionRef.detectChanges(); }); } public ionViewDidEnter() { this.updateData(); } } }}} === db.service.ts === * ./node_modules/.bin/ionic generate service db {{{#!highlight javascript import { Injectable } from '@angular/core'; import { SQLite, SQLiteObject } from '@ionic-native/sqlite/ngx'; @Injectable({ providedIn: 'root' }) export class DbService { constructor(private sqlite: SQLite) { } private getDb(): Promise<SQLiteObject> { let async: Promise<SQLiteObject> = new Promise<SQLiteObject>((resolve, reject) => { let promise = this.sqlite.create({ name: 'data.db', location: 'default' }); promise.then((db: SQLiteObject) => { db.executeSql('CREATE TABLE IF NOT EXISTS PushNotificationsTable (push text)', []) .then(() => { resolve(db); }) .catch((e) => { reject('Table not created ' + JSON.stringify(e)); }); }); promise.catch(e => reject("Create db error " + JSON.stringify(e))); }); return async; } public insertPush(body: string) { this.getDb().then((db: SQLiteObject) => { if (db != null) { db.executeSql('INSERT INTO PushNotificationsTable VALUES (?)', [body]) .then(() => { }) .catch(e => alert("Insert error " + JSON.stringify(e))); } else { alert('insertPush: this.db is null'); } }); } public getNotifications(): Promise<string[]> { let asyncTask: Promise<string[]> = new Promise<string[]>((resolve, reject) => { this.getDb().then((db: SQLiteObject) => { if (db != null) { db.executeSql('SELECT * FROM PushNotificationsTable', []).then((data) => { let items: string[]; items = []; for (let i = 0; i < data.rows.length; i++) { let item = data.rows.item(i); items.push(item.push); } resolve(items); }).catch((e) => { reject(e); }); } else { alert('getNotifications: this.db is null'); reject('getNotifications: this.db is null'); } }); }); return asyncTask; } } }}} == EchoPlugin == * www/EchoPlugin.js {{{#!highlight javascript window.echo = function(str, callback) { cordova.exec(callback, function(err) { callback('Nothing to echo.'); }, "Echo", "echo", [str]); }; }}} * echo-plugin/plugin.xml {{{#!highlight xml <?xml version="1.0" encoding="UTF-8"?> <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="org.allowed.bitarus.EchoPlugin" version="1.0.0"> <name>echo-plugin</name> <description>echo plugin</description> <license>null</license> <js-module src="www/EchoPlugin.js" name="EchoPlugin"> <clobbers target="EchoPlugin" /> </js-module> <platform name="android"> <config-file target="res/xml/config.xml" parent="/*"> <feature name="EchoPlugin" > <param name="android-package" value="org.allowed.bitarus.EchoPlugin"/> </feature> </config-file> <config-file target="AndroidManifest.xml" parent="/*"> <uses-permission android:name="android.permission.INTERNET" /> </config-file> <source-file src="src/main/java/org/allowed/bitarus/EchoPlugin.java" target-dir="src/org/allowed/bitarus" /> </platform> </plugin> }}} * echo-plugin/package.json {{{#!highlight javascript { "name": "org.allowed.bitarus.echoplugin", "version": "1.0.0", "description": "Echo plugin", "cordova": { "id": "org.allowed.bitarus.echoplugin", "platforms": [ "android" ] }, "keywords": [ "ecosystem:cordova", "cordova-android" ], "author": "Vitor", "license": "null" } }}} * echo-plugin/src/main/java/org/allowed/bitarus/EchoPlugin.java {{{#!highlight java package org.allowed.bitarus; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CallbackContext; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaInterface; public class EchoPlugin extends CordovaPlugin { @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); } @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { if (action.equals("echo")) { String message = "Echo " + args.getString(0) + " !!!"; this.echo(message, callbackContext); return true; } if (action.equals("getintentdata")) { this.getintentdata(callbackContext); return true; } return false; } private void echo(String message, CallbackContext callbackContext) { if (message != null && message.length() > 0) { callbackContext.success(message); } else { callbackContext.error("Expected one non-empty string argument."); } } private void getintentdata(CallbackContext callbackContext) { String data = this.cordova.getActivity().getIntent().getDataString() ; String action = this.cordova.getActivity().getIntent().getAction(); String result = String.format( "{\"data\":\"%s\" , \"action\":\"%s\"}",data,action ); callbackContext.success(result); } } }}} * tab1.page.ts {{{#!highlight javascript import { Component } from '@angular/core'; import { HTTP } from '@ionic-native/http/ngx'; import { Platform } from '@ionic/angular'; declare let cordova: any; @Component({ selector: 'app-tab1', templateUrl: 'tab1.page.html', styleUrls: ['tab1.page.scss'] }) export class Tab1Page { public res; public echo: string; constructor(private http: HTTP, private platform: Platform) { this.platform.ready().then(() => { this.init(); } ); } public init() { this.getEcho(); } getEcho() { if (this.platform.is('cordova')) { try { cordova.exec( (success) => { this.echo = success; }, (error) => { }, //feature name in /home/vitor/MyIonicProject/echo-plugin/plugin.xml //feature name in /home/vitor/MyIonicProject/platforms/android/app/src/main/res/xml/config.xml "EchoPlugin", // class Service name "echo", // action ["argxyz"] // arguments ); } catch (e) { this.echo = "Got error in get echo " + JSON.stringify(e) + e.message; } } } public ionViewDidEnter() { console.log("Stuff"); this.http.get("https://labs.bitarus.allowed.org/version/", {}, {}) .then(data => { console.log(data.status); console.log(data.data); // data received by server this.res = data.data; console.log(data.headers); }) .catch(error => { console.log(error.status); console.log(error.error); // error message as string console.log(error.headers); }); } } }}} * tab1.page.html {{{#!highlight xml <ion-header [translucent]="true"> <ion-toolbar> <ion-title> Tab 111 {{res}} </ion-title> </ion-toolbar> </ion-header> <ion-content [fullscreen]="true"> <ion-header collapse="condense"> <ion-toolbar> <ion-title size="large">Tab 111</ion-title> </ion-toolbar> </ion-header> <app-explore-container name="Tab 111 page {{res}} {{echo}}"></app-explore-container> </ion-content> }}} == SQLite == * npm install @ionic-native/sqlite * node_modules/.bin/ionic cordova plugin add cordova-sqlite-storage * https://github.com/storesafe/cordova-sqlite-storage {{{#!highlight javascript // app.module.ts import { SQLite } from '@ionic-native/sqlite/ngx'; providers SQLite // app.component.ts import { SQLite } from '@ionic-native/sqlite/ngx'; constructor private sqlite:SQLite }}} == Create page == * https://ionicframework.com/docs/cli/commands/generate * 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 == * https://www.mokkapps.de/blog/the-last-guide-for-angular-change-detection-you-will-ever-need/ {{{ 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 }}} * https://angular.io/api/core/ChangeDetectorRef {{{#!highlight javascript constructor(private ref: ChangeDetectorRef) { //... } this.ref.detectChanges(); // trigger detection change }}} == Setup environment debian bullseye == === setup_debian.sh === {{{#!highlight bash cd ~ rm -rf android/ rm -rf gradle-7.4.2/ rm -rf jdk8u222-b10/ wget https://downloads.gradle-dn.com/distributions/gradle-7.4.2-bin.zip unzip gradle-7.4.2-bin.zip sudo apt install -y curl sudo wget net-tools nodejs unzip wget https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz tar xvzf OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz wget https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip mkdir ~/android unzip commandlinetools-linux-6858069_latest.zip mv cmdline-tools/ ~/android/ cd ~/android/cmdline-tools/ && mkdir latest && mv bin/ lib/ NOTICE.txt source.properties latest/ echo "export ANDROID_HOME=$HOME/android/" >> ~/.bashrc echo "export ANDROID_SDK_ROOT=$HOME/android/" >> ~/.bashrc echo "export PATH=/usr/local/bin:/usr/bin:/bin:$HOME/jdk8u222-b10/bin:$HOME/gradle-7.4.2/bin" >> ~/.bashrc echo "export JAVA_HOME=$HOME/jdk8u222-b10/" >> ~/.bashrc cat ~/.bashrc source ~/.bashrc $HOME/android/cmdline-tools/latest/bin/sdkmanager --update $HOME/android/cmdline-tools/latest/bin/sdkmanager --version yes | $HOME/android/cmdline-tools/latest/bin/sdkmanager --install "build-tools;30.0.3" $HOME/android/cmdline-tools/latest/bin/sdkmanager --list # should show installed packages }}} === setup_ionic_debian.sh === {{{#!highlight bash #!/bin/sh rm IonicTest -rf rm node_modules -rf npm install @ionic/cli node_modules/.bin/ionic start ITest --type angular tabs # angular, tabs, share anon data: no, create ionic account: no, cd ITest npm i npm i @ionic/cli npm i cordova npm i cordova-res node_modules/.bin/ionic integrations disable capacitor node_modules/.bin/ionic cordova plugin add cordova-plugin-advanced-http npm i @ionic-native/http npm i typescript npm i @angular/cli npm i @angular/core npm i @angular/compiler-cli npm i @angular/compiler npm i @angular/forms npm i @angular/common npm i @angular/platform-browser-dynamic npm i @angular/router npm i angular npm i @ionic/angular npm i @angular/platform-browser npm i zone.js node_modules/.bin/ionic cordova platform add android node_modules/.bin/ng add @ionic/cordova-builders # remove from platforms/android/gradlew the --illegal-access = permit # vi platforms/android/gradlew node_modules/.bin/ionic cordova build android # no to report statistics #node_modules/.bin/ionic cordova platform add browser #node_modules/.bin/ionic cordova build browser #node_modules/.bin/ionic serve --cordova --platform=browser #node_modules/.bin/ionic serve --cordova --platform=browser --host 0.0.0.0 --port 8081 # http://localhost:8081/ }}} |
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