Ce qui permet de produire une application native, c’est l’intégration de Capacitor à votre projet. Celle-ci est réalisée de facto lorsque vous créez votre projet Ionic.
Évidemment, comme vous souhaitez produire une application native, il faut la compiler pour chaque plateforme (iOS, android) sur laquelle vous souhaitez l’utiliser. Avant de faire cela, il faut réaliser l’opération suivante, qui vise à créer le répertoire www qui sera utilisé pour compiler en natif :
ionic build
Si vous souhaitez produire des applications Android, il faut installer le package Android de Capacitor et indiquer à votre projet que vous allez l’utiliser :
npm install @capacitor/android
npx cap add android
Si vous souhaitez produire des applications iOS, il faut installer le package Android de Capacitor et indiquer à votre projet que vous allez l’utiliser :
npm install @capacitor/ios
npx cap add ios
Attention
Pour compiler pour iOS, vous avez besoin d’être sur un OS Apple et d’avoir à disposition XCode.
Essentiellement, la production de l’application native se fait en 3 étapes :
Compiler l’application web en exécutant la commande bash :
ionic build
Synchroniser avec l’appli native en exécutant la commande bash :
npx cap copy
Ouvrir Android studio ou XCode :
npx cap open android
Attention
Pour pouvoir utiliser cette commande, il faut préciser à la ligne de commande le « path » d’android-studio :
export CAPACITOR_ANDROID_STUDIO_PATH=`which android-studio`
Pour Xcode, il faut utiliser plutôt :
npx cap open ios
Le résultat obtenu avec Android studio :
Pour transformer votre application en PWA, il faut installer le package suivant :
ng add @angular/pwa
Cela va créer, notamment, deux fichiers : un web manifest (le manifest du PWA) et un fichier de configuration pour ngsw (qui va gérer le cache du service worker).
Notez que l’on a toujours le répertoire www et c’est dans celui-ci que l’on va produire notre PWA. Pour cela, il faut utiliser la commande suivante :
ionic build --prod -- --base-href "/xmobile_cours/maPWA/"
Ici, /xmobile_cours/maPWA/ est l’URL à partir de laquelle on accède à la PWA à partir d’un navigateur, comme indiqué ci-dessous :
Notez également dans la commande ionic build que, juste après le –prod, il y a un –. Celui-ci sert à indiquer que ce qui suit sont des paramètres à passer à Angular plutôt qu’à Ionic.
Attention
Dans le –base-href, il est important de mettre un / à la fin de l’URL.
Dans l’image ci-dessus, on a ouvert les developer tools et, contrairement à d’habitude, ce qui nous intéresse n’est pas la console ou le network mais plutôt l’onglet application. On y voit qu’un service worker est associé à notre page, ce qui prouve bien qu’il s’agit d’une PWA.
Pour permettre d’installer aisément la PWA, on va créer un bouton d’installation. Le HTML est classique : on crée un bouton standard et on associe à son événement click une callback :
<ion-header [translucent]="true">
<ion-toolbar>
<ion-buttons slot="start">
<ion-button *ngIf="promptEvent" (click)="onInstall()">Installer</ion-button>
</ion-buttons>
<ion-title>Blank</ion-title>
<ion-buttons slot="end">
<ion-button (click)="openMenu($event)">
<ion-icon slot="icon-only"
name="add-circle"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<p><a routerLink="/cours">vers la page cours</a></p>
</ion-content>
Notez le *ngIf=promptEvent : l’idée est d’avoir dans le TypeScript un attribut qui permet de déterminer si l’on a installé ou non l’application. Pour cela, ce TypeScript va exploiter l’événement beforeinstallprompt. Quand on démarre notre application, cet événement est émis si et seulement si on n’a pas encore installé l’application. Dans ce cas, on va s’arranger pour que promptEvent ne soit pas null. Ainsi, le bouton d’installation sera visible. Lorsque l’application a été installée, l’événement beforeinstallprompt ne sera pas émis et notre bouton d’installation ne sera pas visible.
import { Component, OnInit } from '@angular/core';
import {
IonHeader, IonToolbar, IonTitle, IonContent,
IonList, IonItem,
IonButtons, IonMenuButton, IonButton, IonIcon, PopoverController
} from '@ionic/angular/standalone';
import {MonServiceService, MyInfo} from "../mon-service.service";
import {RouterLink} from "@angular/router";
import {DropdownMenuComponent} from "../dropdown-menu/dropdown-menu.component";
import {addIcons} from "ionicons";
import {addCircle} from "ionicons/icons";
import {CommonModule} from "@angular/common";
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
standalone: true,
imports: [
IonHeader, IonToolbar, IonTitle, IonContent,
IonItem, IonList,
RouterLink, IonButtons, IonMenuButton, IonButton, IonIcon,
CommonModule
],
})
export class HomePage implements OnInit {
info!: MyInfo;
// un événement qui sera initialisé dans le constructeur si l'application n'a pas
// été installée
promptEvent: any = null;
constructor(private mon_service: MonServiceService,
private popover: PopoverController) {
// l'événement ""beforeinstallprompt" est émis chaque fois que l'on charge la
// page et que l'application n'a pas encore été installée. S'il est émis, on
// met à jour promptEvent
window.addEventListener(
'beforeinstallprompt', event => {
this.promptEvent = event;
});
}
async onInstall() {
if (this.promptEvent !== null) {
this.promptEvent.prompt();
const { outcome } = await this.promptEvent.userChoice;
if (outcome === 'accepted') {
this.promptEvent = null;
}
}
}
async ngOnInit() {
this.mon_service.getInfos().subscribe(res => {this.info = res;});
addIcons({addCircle});
}
openMenu(myevent: MouseEvent) : void {
// on crée le popup contenant le code du menu
this.popover.create({
component: DropdownMenuComponent, // on précise quoi inclure
showBackdrop: true,
cssClass: 'my-menu-class', // on peut préciser un css
event: myevent, // l'événement clic souris
componentProps: { // ici, on indique les propriétés que l'on souhaite
myprop: 'xxxx' // initialiser dans le composant DropdownMenuComponent
}
}).then((popoverElement) => {
popoverElement.present(); // on affiche le menu
popoverElement.onDidDismiss().then((res) => {
console.log(res);
});
});
}
}
Avec le code ci-dessus, lorsque l’application n’est pas installée, on obtient l’affichage suivant :
Lorsque l’on clique sur le bouton :
Après avoir cliqué sur install, l’application est installée. On peut la voir ici en allant sur l’URL chrome://apps :
Si l’on clique sur l’icône, cela démarre notre application. On peut voir tout en haut de la fenêtre qu’il s’agit bien d’une application et non plus simplement d’une page web. On remarque, d’ailleurs, qu’on ne peut plus saisir d’URL.