

Cours Programmation Mobile Ionic IM2AG


Alexandre DEMEURE - Sylvain DEDIEU

s.dedieu@criteo.com



Sylvain DEDIEU
Software development engineer –
#ui-foundation 🛸
s.dedieu@criteo.com
s.dedieu@criteo.com



alexandre.demeure@univ-grenoble-alpes.fr


Alexandre DEMEURE
Enseignant Chercheur #IIHM #UGA
Agenda
1
2
3
4
Pré-requis
Présentation
Démarrage
Projet


1
2
3
4
Pré-requis
Présentation
Démarrage
Projet


Pré-requis

Installation du JDK


Installation du JDK


export JAVA_HOME=/chemin/vers/java
export PATH=$JAVA_HOME/bin:$PATHVérifier que l'installation du JDK c'est bien passée


your/current/path % java -version
java version "11.x.x.x" YYYY-MM-DD LTS
Java(TM) SE Runtime Environment (build 11.x.x.x+x-LTS-x)
Java HotSpot(TM) 64-Bit Server VM (build 11.x.x.x+x-LTS-x, mixed mode, sharing)Installation du SDK


Téléchargez Android Studio et installez-le.
SDK - Système Linux


export ANDROID_SDK_ROOT=/chemin/vers/Android/Sdk/
export PATH=${PATH}:${ANDROID_SDK_ROOT}/tools
export PATH=${PATH}:${ANDROID_SDK_ROOT}/platform-toolsSDK - Système MacOS


Pour les possesseurs de Mac, installez XCode depuis l'App Store.
Installation de Git


Installez Git si vous ne l'avez pas déjà.
your/current/path % git --version
git version x.xx.x (Apple Git-136)Installation de NodeJS


Installez Node.js si vous ne l'avez pas déjà (préférez la version LTS).
Installation de NodeJS


export PATH=/chemin/vers/node/bin:$PATHVérifier que l'installation de NodeJS s'est bien déroulée


your/current/path % node --version
v22.xx.x
your/current/path % npm --version
10.xx.xInstallation de Ionic


Surtout ne pas faire du sudo sur Linux
npm install -g @ionic/cliyour/current/path % ionic --version
7.x.xInstallation de Angular CLI


Surtout ne pas faire du sudo sur Linux
npm install -g @angular/cliyour/current/path % ng version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI : 21.0.3
Node.js : 22.13.0
Package Manager : npm 10.9.2
Operating System : darwin arm64Update de la version Angular


{
"name": "kahoot",
"version": "0.0.1",
"author": "Ionic Framework",
...
"private": true,
"dependencies": {
"@angular/animations": "^20.0.0",
"@angular/common": "^20.0.0",
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
"@angular/platform-browser-dynamic": "^20.0.0",
"@angular/router": "^20.0.0",
...
},
"devDependencies": {
"@angular-eslint/builder": "^20.0.0",
"@angular-eslint/eslint-plugin": "^20.0.0",
"@angular-eslint/eslint-plugin-template": "^20.0.0",
"@angular-eslint/schematics": "^20.0.0",
"@angular-eslint/template-parser": "^20.0.0",
"@angular/build": "^20.0.0",
"@angular/cli": "^20.0.0",
"@angular/compiler-cli": "^20.0.0",
"@angular/language-service": "^20.0.0",
...
"typescript": "~5.9.0"
},
"description": "An Ionic project"
}{
"name": "kahoot",
"version": "0.0.1",
"author": "Ionic Framework",
...
"private": true,
"dependencies": {
"@angular/animations": "^21.0.6",
"@angular/common": "^21.0.6",
"@angular/compiler": "^21.0.6",
"@angular/core": "^21.0.6",
"@angular/forms": "^21.0.6",
"@angular/platform-browser": "^21.0.6",
"@angular/platform-browser-dynamic": "^21.0.6",
"@angular/router": "^21.0.6",
...
},
"devDependencies": {
"@angular-eslint/builder": "^21.0.6",
"@angular-eslint/eslint-plugin": "^21.0.6",
"@angular-eslint/eslint-plugin-template": "^21.0.6",
"@angular-eslint/schematics": "^21.0.6",
"@angular-eslint/template-parser": "^21.0.6",
"@angular/build": "^21.0.6",
"@angular/cli": "^21.0.6",
"@angular/compiler-cli": "^21.0.6",
"@angular/language-service": "^21.0.6",
...
"typescript": "~5.9.0"
},
"description": "An Ionic project"
}ng update @angular/cli @angular/core1
2
3
4
Pré-requis
Présentation
Démarrage
Projet


Présentation

Qu'est ce qu'un Framework ?


Ensemble de fonctions pouvant être appelées à l’intérieur de votre code.
Libraries
Votre code est lu, transformé par le framework.
Framework
Ensemble d’outils et librairies facilitant la création et la construction d’applications.
SDK
Qu'est ce qu'un Framework ?


-
Qu'est-ce que c'est ?
Un Framework de développement d’applications mobiles.
-
A quoi ça sert ?
A construire des IPA, APK et PWA publiables sur les stores Android, IOS ou sur un serveur WEB.
-
Comment ?
En fournissant un ensemble d’outils permettant de travailler vite et bien.
Écosystème Ionic


SDK
Plateformes
Package manager
Langages Natifs
Components ready to use
Frameworks de développements






Documentation




1
2
3
4
Pré-requis
Présentation
Démarrage
Projet


Démarrage

Nouvelle application


ionic start <nom_de_son_application> blank --type=angularArborescence du projet



Points d'entrées de l'application Web
Fichier de configuration de l'application Mobile
Démarrer son application sur un serveur WEB local


ionic serveAjout de la Plateforme Android - Etape 1


ionic build
npm install @capacitor/android
npx cap add android
Ajout de la Plateforme Android - Etape 2


npx cap open android
Ajout de la Plateforme Android - Etape 3


-
Installez un appareil via le AVD Manager
- Lancez l’application


Ajout de la Plateforme IOS - Etape 1


npm install @capacitor/ios
npx cap add ios
Ajout de la Plateforme IOS - Etape 2



npx cap open iosAjout de la Plateforme IOS - Etape 3


-
Installez un appareil via le Device Manager
- Lancez l’application

1
2
3
4
Pré-requis
Présentation
Démarrage
Projet


Projet

Exercice 1 - Spec


Projet Ionic blank
Départ
Une application de Quiz qui permet de :
- Créer plusieurs Quiz
- Avoir plusieurs Questions par Quiz
-
Un Quiz possède :
- un id
- un label
- une liste de Questions
-
Une Question possède :
- un id
- un label
- un index
- une liste de Choix
-
Un Choice possède :
- un id
- un label
Arrivée
Exercice 1 - Tip


Définition des interfaces
- Créez en premier les interfaces pour les objets métier Quiz Question et Choice.
Astuce: utilisez la méthode generate de la CLI pour aller plus vite
- Renseignez les attributs des interfaces
-
id
-
title
-
description
-
questions
Quiz
-
id
-
text
-
choices
-
correctChoiceId
Question
ionic g interface models/<nom_de_mon_interface>
// eg: ionic g interface models/quiz-
id
-
text
Choice
Exercice 1 - Tip


Définition du service
Créez un service de gestion des Quiz, de leurs Questions et Choix.
Astuce: utiliser la méthode generate de la CLI pour aller plus vite
Le service possède une variable privée qui correspond à un tableau (array) de toutes les Questions existantes.
Le service possède les méthodes:
ionic g service services/<nom_de_mon_service>
// eg: ionic g service services/quizgetAll(): Promise<Quiz[]>;
get(quizId: string): Promise<Quiz>;
addQuiz(quiz: Quiz): Promise<Quiz>;
deleteQuiz(quizId: string): Promise<void>;
updateQuiz(updatedQuiz: Quiz): Promise<Quiz>;Exercice 1 - Tip


Réalisation de la HomePage
- La page d'accueil (home) doit afficher tout les Quiz sous forme d’ion-cards dans une ion-grid.
Documentation utile:
https://ionicframework.com/docs/api/grid
https://ionicframework.com/docs/api/card
- Cette page doit donc faire appel à la méthode de récupération du tableau de Quiz lors de son initialisation.
Documentation utile:
Injecter un @Service dans un @Component
Angular resource
- Elle possède aussi un bouton d’ouverture de modale, qui contient un formulaire pour créer un nouveau Quiz et l’ajouter à la liste existante.
- Chaque ion-card de Quiz est cliquable et permet d'accéder à un écran de détail d'un Quiz.
Documentation utile: https://angular.dev/guide/routing
Exercice 1 - Tip


Réalisation de la Modale de création d'un Topic
-
La modale d’ajout de Quiz doit contenir un formulaire permettant de saisir les différents champs de l’objet Quiz.
Documentation utile:
https://ionicframework.com/docs/api/modal (utiliser ModalController)
https://angular.dev/essentials/signal-forms
-
Lors de la soumission du formulaire, un nouvel objet Quiz doit être créé et renvoyé via la méthode onWillDismiss à la HomePage. Laquelle appellera le QuizService pour ajouter le nouveau Quiz à la liste existante.
Exercice 1 - Tip


Réalisation de la page de détail d'un Quiz
-
Un clic sur un objet Quiz de la HomePage permet d'accéder à la page de détails de cet objet Quiz.
-
La page doit afficher toutes les Questions sous forme d’ion-item.
Documentation utile: https://ionicframework.com/docs/api/list https://ionicframework.com/docs/api/item
-
Elle possède aussi un bouton d'édition qui provoque l’ouverture de modale, qui contient un formulaire pour modifier le Quiz existant.
Exercice 1 - Pour aller plus loin - Test


npm install --save-dev cypress @testing-library/cypress
npx cypress open- Installation de Cypress


Exercice 1 - Pour aller plus loin - Test


- Créer un fichier tsconfig.json dans "/cypress"
{
"extends": "../tsconfig.json",
"include": [
"../node_modules/cypress",
"**/*.cy.ts"
],
"compilerOptions": {
"noEmit": false,
"sourceMap": false,
"types": [
"cypress",
"@testing-library/cypress"
]
}
}- Editer le fichier cypress.config.ts
import { defineConfig } from "cypress";
export default defineConfig({
viewportHeight: 760,
viewportWidth: 360,
e2e: {
baseUrl: 'http://localhost:8100'
},
});- Editer dans cypress/support/commands.ts
import '@testing-library/cypress/add-commands'Exercice 1 - Pour aller plus loin - Test


- Créer une nouvelle spec "add-a-new-quiz.cy.ts"

- Ecrire son premier test
Exercice 1 - Suite


- Ajout d'une méthode de suppression de Quiz
HomePage
Cours Asynchrone


Exercice 2 - Observables


Le quizService doit retourner uniquement des Observables
Les méthodes de:
- Récupération des Quiz
- Récupération d'un Quiz
doivent à présent retourner des Observables.
getAll(): Observable<Quiz[]>;
get(quizId: string): Observable<Quiz>;Pour cela, changez la variable topics en BehaviorSubject et utilisez les méthodes asObservable() (pour la récupération) et next() (pour la modification).
Corrigé


Exercice 3 - Firebase - Créer son projet 1/5



Exercice 3 - Firebase - Créer son projet 2/5



Exercice 3 - Firebase - Créer son projet 2/5 (Google Analytics optionel)



Exercice 3 - Firebase - Créer son projet 3/5 (Google Analytics optionel)



Exercice 3 - Firebase - Créer son projet 4/5



Exercice 3 - Firebase - Créer son projet 5/5



Exercice 3 - Firebase - Créer sa base Firestore (1/4)



Exercice 3 - Firebase - Créer sa base Firestore (2/4)



Exercice 3 - Firebase - Créer sa base Firestore (3/4)



Exercice 3 - Firebase - Créer sa base Firestore (4/4)



Exercice 3 - Firestore - Mocker un Quiz (1/4)



Exercice 3 - Firestore - Mocker un Quiz (2/4)



Exercice 3 - Firestore - Mocker un Quiz (3/4)



Exercice 3 - Firestore - Mocker un Quiz (3/4) - Ne pas ajouter les questions dans le document !



Exercice 3 - Firestore - Mocker un Quiz (4/4)



Exercice 3 - Firestore - Mocker une Question (1/3)



Exercice 3 - Firestore - Mocker une Question (2/3)



Exercice 3 - Firestore - Mocker une Question (3/3)



Exercice 3 - Firestore - Récupérer les données


Affichage des données crées dans l'application
- Installer l'API @angular/fire
npm i @angular/fire --legacy-peer-deps- Configurer l'accès à la firebase en renseignant ses fichiers environments


Exercice 3 - Firestore - Récupérer les données


Affichage des données crées dans l'application
export const environment = {
production: false,
firebaseConfig: {
apiKey: "<API_KEY>",
authDomain: "<AUTH_DOMAIN>",
projectId: "<PROJECT_ID>",
storageBucket: "<STORAGE_BUCKET>",
messagingSenderId: "<MESSAGING_SENDER_ID>",
appId: "<APP_ID>",
measurementId: "<MEASUREMENT_ID>"
}
};- Configurer l'accès à la firebase en renseignant ses fichiers environments


Exercice 3 - Firestore - Récupérer les données


Ne pas commiter d'informations sensibles
git rm --cached src/environments/environment.ts
// do the same for production if neededExercice 3 - Firestore - Récupérer les données


Provide Firestore
bootstrapApplication(AppComponent, {
providers: [
...
provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
provideFirestore(() => getFirestore()),
],
});Exercice 3 - Firestore - Récupérer les données


Affichage des données crées dans l'application
Continuer en utilisant la documentation de l'API
import { Firestore, collection, collectionData, doc, docData } from '@angular/fire/firestore';
export class UserProfileService {
private firestore: Firestore = inject(Firestore); // inject Cloud Firestore
getAll() {
// get a reference to the user-profile collection
const userProfileCollection = collection(this.firestore, 'users');
// get documents (data) from the collection using collectionData
return collectionData(userProfileCollection, {idField: 'id'}) as Observable<UserProfile[]>;
}
getById(id: string) {
// get a reference to the user-profile doc
const userProfileDoc = doc(this.firestore, `users/${id}`);
// get document (data) from the doc using docData
return docData(userProfileDoc, {idField: 'id'}) as Observable<UserProfile>;
}
}Exercice 3 - Firestore - Post / Update /Delete


import { Firestore, addDoc, setDoc, deleteDoc } from '@angular/fire/firestore';
export class UserProfileService {
private firestore: Firestore = inject(Firestore); // inject Cloud Firestore
add(user: User) {
// get a reference to the user-profile collection
const userProfileCollection = collection(this.firestore, 'users');
// add document from the collection using addDoc
return addDoc(userProfileCollection, user);
}
edit(user: User) {
// get a reference to the user-profile doc
const userProfileDoc = doc(this.firestore, `users/${id}`);
// add document from the collection using addDoc
return setDoc(userProfileCollection, user);
}
delete(user: User) {
// get a reference to the user-profile doc
const userProfileDoc = doc(this.firestore, `users/${id}`);
// delete document from the doc using deleteDoc
return deleteDoc(userProfileDoc);
}
}Exercice 3.5 - Firestore - Tests


Installation de firebase emulator
# install firebase CLI
npm i -g firebase-tools
# login to firebase account
firebase login
# init frebase conf / link to existing project
firebase init
◉ Firestore: Configure security rules and indexes files for Firestore
◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
◉ Emulators: Set up local emulators for Firebase products
? Please select an option: Use an existing project
? Select a default Firebase project for this directory: (Use arrow keys)
❯ m2pgi-topic-manager (m2pgi-topic-manager)
# validate all unitl
? What do you want to use as your public directory? www
? Configure as a single-page app (rewrite all urls to /index.html)? No
? Set up automatic builds and deploys with GitHub? No
✔ Wrote www/404.html
? File www/index.html already exists. Overwrite? No
=== Emulators Setup
? Which Firebase emulators do you want to set up? Press Space to select emulators, then Enter to confirm
your choices. (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to
proceed)
◉ Authentication Emulator
◉ Firestore Emulator
◉ Hosting EmulatorExercice 4 - Fireauth - Configuration (1/4)



Exercice 4 - Fireauth - Configuration (2/4)



Exercice 4 - Fireauth - Configuration (3/4)



Exercice 4 - Fireauth - Configuration (4/4)



Exercice 4 - Fireauth - Implémentation (1/3)


- Créer un AuthService en utilisant la CLI
Le service possède des méthodes pour: - Enregistrer un nouvel utilisateur (createUser)
- Connecter un utilisateur existant (signIn)
- Déconnecter un utilisateur existant (signOut)
- Savoir si quelqu'un est connecté ou non
ionic g service services/<nom_de_mon_service>
// eg: ionic g service services/authcreateUser(
email: string,
password: string
): Promise<UserCredential>;
signIn(
email: string,
password: string
): Promise<UserCredential>;
signOut(): Promise<void>;
isConnected(): User;Exercice 4 - FireAuth - Implémentation (2/3)


- Créer deux pages LoginPage & RegisterPage en utilisant la CLI
- Créer un lien de Router pour aller à la page register depuis la page login (pas encore de compte ?)
- Implémenter les formulaires
ionic g page pages/<nom_de_ma_page>
// eg: ionic g page services/loginRéalisation des pages formulaires register & login
Exercice 4 - FireAuth - Implémentation (3/3)


Ajouter un Guard pour éviter qu'un utilisateur non-connecté n'accède aux pages home et quiz-details
Ajout d'un Router Guard
Exercice 4.5 - FireAuth - Pour aller plus loin


Ajout de la confirmation de l'email et la récupération d'un mot de passe oublié
Exercice 5 - Topic Ownership & Sharing


Ajout de la fonctionnalité de propriété et partage d'un Topic
- Un Quiz appartient à son "Owner", c'est-à-dire le User qui a créé le Topic.
- Le Owner peut ajouter d'autres Users à son Quiz soit en tant que "Reader", soit en tant que "Editor".
- Un User ne voit que les Quiz où il est soit Owner, soit Editor soit Reader.
- Un User Reader ne peut ni éditer ni ajouter de Questions.
- Un User Owner ou Editor peut éditer et ajouter des Questions.
Exercice 5 - Topic Ownership & Sharing


Ecrire ses Security Rules Firebase
IM2AG - Cours Programmation Mobile Ionic
By Dedieu Sylvain
IM2AG - Cours Programmation Mobile Ionic
- 1,057