91
Développement Mobile Web avec IONIC2 Version du 29/03/2017 Jean David Olekhnovitch [email protected] @gidehault

Développement web mobile avec IONIC 2

Embed Size (px)

Citation preview

Développement Mobile Web

avec IONIC2Version du 29/03/2017

Jean David Olekhnovitch 📧 [email protected] @gidehault

Web et mobile : deux mondes à part

• Le web est basé depuis la fin des années 90 sur un mode orienté serveur :

• Un serveur HTTP qui centralise tous les traitements

• Des clients HTML/CSS qui affichent passivement l’information

• De multiples tentatives existent pour ‘dynamiser’ le côté client, Javascript en tête

• Un handicap : ça rappelle furieusement le modèle mainframe/client texte des années 60/70

• Un souhait : préserver un standard ouvert

2

Web et mobile : deux mondes à part

• Le mobile s’appuie sur des outils de développements plus sophistiqués, mais dédiés à des plateformes incompatibles entre elles

3

Android- Langage Java - Environnement propriétaire

Google, sur base Linux - Développement Android

Studio - Distribution : Google Play

iOS- Langage Swift - Environnement propriétaire

Apple, sur base NetBSD - Développement XCode - Distribution : App Store

FirefoxOSWindows

PhoneBlackberry

UbuntuTizen

Mais la mixité subsiste

• D’un côté, il est possible de faire tourner des choses assez évoluées dans le navigateur de son téléphone

• De l’autre, il est aujourd’hui possible d’accéder à des fonctions ‘natives’ depuis son navigateur

5

1 - Historiquement : les "sites mobiles"

• A l'époque des premiers smartphones, il était nécessaire de faire une version spécifique des sites Internet pour visualisation sur téléphone mobile

6

Avantages‣ version légère et bien adaptée aux

smartphones peu performants ‣ facilité de développement

Inconvénients‣ nécessité de gérer deux versions

en parallèle ‣ aucune exploitation des possibilités

natives des téléphones

2 - Vers une version unique des sites web : le responsive design• Les possibilités d'élasticité (grille fluide) et d'adaptation aux

devices (media queries) des feuilles de style CSS permettent de maintenir une version unique des sites web tout en s'adaptant au format d'affichage

7

Avantages‣ adaptation relativement simple (que

des hacks CSS) ‣ une seule version des sites web à

maintenir

Inconvénients‣ aucune exploitation des possibilités

natives des téléphones

3 - Un pas vers les fonctions natives : HTML5

• La version HTML5 propose, de manière plus ou moins aboutie, la possibilité d'accéder à certaines fonctions natives depuis son navigateur web

8

Avantages‣ possibilité de cumuler avec les

capacités de responsive design ‣ fonctions accessibles en quelques

balises

Inconvénients‣ toutes les fonctions ne sont pas

présentes ‣ compatibilité aléatoire suivant les

navigateurs

Du HTML à l'app mobile : un chemin semé d'embuches

9

Site HTML/CSS

Déclinaison site mobile

Site Responsive Site HTML5 App mobile

native

App hybride web/mobile

?

AppsSites

Progressive Webapps

L’enjeu des fonctions natives• Stockage offline

• Géolocalisation

• Gestuelles tactiles

• Bluetooth

• Accéléromètre, boussole…

• Notifications

• Caméra…

10

La barrière des appstore

• Google et Apple ont fait le choix du point d'entrée unique vers l'application : l'app store (ou playstore)

• Pour diverses raisons de contrôle qualité, de sécurité… et parfois de censure

• Cette barrière impose des critères techniques nombreux et peu simples à franchir

11

1ères solutions : Apache Cordova/Adobe PhoneGap

• Idée : proposer des passerelles entre les fonctions natives, et des pages conçues en HTML/CSS

• Naissance du concept d’Application Hybride

• Aujourd’hui intégralement en opensource et géré par l’Apache Foundation

12

Limitations de Cordova

• Ne propose pas de solution pour l’interface utilisateur (gestuelles tactiles, etc…)

• La publication vers les stores Google/Apple reste complexe

• A voir plus comme une série de librairies que comme un framework a part entière

13

Surcouche et structuration: la solution d'un framework

• Idée : compléter la philosophie (et les briques techniques) de Cordova par un véritable framework capable de :

• faciliter le développement

• industrialiser la publication sur les stores

• donner la possibilité de créer des modules optionnels

• ‘casser’ la logique de page au sens HTTP du terme

14

Côté Facebook : React• Framework développé en interne

• Destiné au développement des applications Facebook avant tout

• Essentiellement côté « front »

• Basé sur Javascript

• Fait appel à des composants natifs autant que possible

15

Autres frameworks• Onsen UI

• Intel XDK

• Sencha Touch

• Kendo UI

• Framework 7

16

• JQuery Mobile

• Mobile Angular UI

• Famo.us

• Monaca

• Trigger.IO

• Electron (pour applis desktop)

Ionic• Créé en 2013

• Repose entièrement sur Cordova pour la partie native

• Et sur AngularJS pour la cinématique des pages

• v2 sortie fin 2016

• TypeScript remplace Javascript

• Angular2 remplace AngularJS

17

Angular 2

Architecture d’Ionic2

Apache CordovaAngular 2

Ionic 2

HTML SCSS Typescript

NPM

NodeJS

Moteur HTML/CSS/JS Natif

App native Application

passerelle vers le monde natif

cinématique des écrans

framework

gestionnaire de paquets

environnement de développement

affichage in-app via un interpréteur web

Installation d’Ionic (1)

• Première étape : installation de NodeJS 6

• Inclut NPM (gestionnaire de paquet Javascript)

• https://nodejs.org/en/download/

19

Installation d’Ionic (2)• Installation d’Ionic et de Cordova

• On se repose sur le gestionnaire de paquets NPM

• Tout se passe en ligne de commande… comme ça va être le cas pour toute la suite :

• npm install -g ionic cordova

20

Première app Ionic• Génération du squelette :

• ionic start premierEssai super --v2

• On va dans le répertoire

• cd premierEssai

• Test dans un navigateur

• ionic serve -c --lab

21

Nom du template qui sert de modèle (blank, tabs, sidemenu, tutorial …)

ionic peut à la fois créer des apps ionic1 et ionic2

lancement avec console de debug et choix de

l’émulateur

Visualisation sur un téléphone

• Problème : on ne peut pas directement télécharger une app sur un mobile (il faut passer par la validation du constructeur)

• Contournement : l'app Ionic View qui permet de visualiser un prototype de son app publié au préalable sur les serveurs Ionic

22

Fonctionnement d'Ionic View

23

Poste de travail

Serveur Ionic

Smartphone

App Ionic View

ionic upload

X

synchro in-app

interdit

Nécessite la création d'un compte sur http://ionic.io

Dispo sur AppStore et GooglePlay

Installation d’Ionic (3)• Modules supplémentaires

• Pour chaque module supplémentaire, là aussi on utilisera npm :

• npm install ionic-native --save

• Les mises à jour se font elles aussi en ligne de commande :

• npm update -g ionic

24

Gestion des dépendances

Installation globale

Installation d’Ionic (4)• Environnement iOS

• Il est obligatoire d’être sur Mac !

• Installation de XCode via le Mac App Store

• Déclaration dans ionic :

• sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

• sudo npm install -g ios-deploy --unsafe-perm=true --allow-root

25

Installation d’Ionic (5)• Environnement Android

• Passe par l’installation de Java (JDK, pas le JRE) :

• http://www.oracle.com/technetwork/java/javase/downloads/index.html

• Installation d’Android Studio :

• https://developer.android.com/studio/index.html

• Installation des packages via le Open Android SDK Manager (‘android’ en ligne de commandes)

• Android Platform SDK for vXXX

• Android SDK build-tools

• Android Support Repository

• Créer un Android Virtual Device (AVD) pour définir un émulateur type qui servira par la suite

26

Génération de l'icône et du splash screen

• Les fichiers suivants doivent être stockés dans le répertoire /resources de l'application

• icon.png : taille de 192x192

• splash.png : taille de 2208x2208

• La génération de toutes les déclinaisons de ces images se fait ensuite par l'instruction suivante, à lancer avant le build :

ionic resources

27

Lancement de son application dans un environnement natif

• ionic platform add android

• ionic platform add ios

• ionic build ios

• ionic build android

28

Préparer un build iOS• Double-cliquer sur

• /platforms/ios/MonApp.xcodeproj

• Créer sur XCode un « Archive »

• Publier ensuite sur le compte (payant !) Developer Apple créé via

• https://developer.apple.com

• Gestion de la publication sur

• https://itunesconnect.apple.com

29

Préparer un build Android• Création d’une clé :

• keytool -genkey -v -keystore MonApp.keystore -alias MonApp -keyalg RSA -keysize 2048 -validity 10000

• Création du build (fichier .apk) prêt à être importé :

• ionic build android --release

• Création d’un compte puis publication sur

• https://play.google.com/apps/publish/

30

Structuration d’une app ionic

• /src : code source de l’application

• /resources : stockage de l’icône et du splashscreen

• /platforms : version compilée par plateforme

• config.xml : fichier principal de configuration de l’app

31

Structuration du répertoire /src

• /app : fichiers principaux de l’application

• /pages : les pages de l’application

• /assets : divers fichiers statiques (css, js, images…)

• /providers : les ‘providers’ (‘moteurs’) de l’application

• /theme : définition d’un thème pour l’application

• index.html : fichier de démarrage de l'app32

Création d’une nouvelle page

• Création des fichiers :

• ionic g page MonEssai

• J’obtiens un dossier /src/pages/mon-essai,

• et 3 fichiers :

• mon-essai.html : interface de la page

• mon-essai.scss : style de la page

• mon-essai.ts : fonctions de traitement en amont et en aval de la page (avec une classe qui s'appelle MonEssaiPage)

33

MonEssai

MonEssaiPage nom de la classe

mon-essai nom des fichiers

Déclaration d’une nouvelle page

• Cette déclaration se fait dans le fichier global /src/app/app.module.ts :

import { MonEssaiPage } from '../pages/mon-essai/mon-essai';

• Le nom « MonEssaiPage » doit également être mentionné dans les paragraphes :

• ‘declarations’

• ‘entryComponents’

34

Structure d'un fichier .ts• Chaque fichier .ts d'une page (ici : mon-essai.ts) est

avant tout une classeimport { Component } from '@angular/core'; import { NavController } from 'ionic-angular';

@Component({ selector: 'monEssai', templateUrl: 'mon-essai.html' }) export class MonEssaiPage { // attributs

// méthodes constructor(public navCtrl: NavController) { } } 35

Import de librairies et fichiers

externes utiles

Les attributs sont les variables utilisées

dans la classeLes

méthodes sont des fonctions utilisées dans

la classe

Le constructeur est la méthode appelée au

démarrage de la page

Divers paramétrages

Fin de la classe

Liens entre .ts et .html• Le fichier mon-essai.ts contient une classe (et

donc des attributs et méthodes) représentant la partie dynamique de la page

• Le fichier mon-essai.html contient la description des éléments visuels de la page

• Les deux communiquent intimement par le biais des mécanismes d’Angular

36

TS, HTML, et MVCOn est en fait ici très proche du pattern MVC bien connu des développeurs d'interface utilisateur

• Mais le contrôleur est ici géré de manière transparente par le framework Angular

37

Vuemon-essai.html

ContrôleurIonic/Angular

Modèlemon-essai.ts

Affichage d’une variable dans la page

• Prenons l’exemple d’un attribut de la classe (dans mon-essai.ts) :

export class MonEssaiPage { unAttribut: string="un contenu";

• On affiche ensuite l'attribut au milieu du code de la page mon-essai.html de la manière suivante :

<p>{{unAttribut}}</p>

• Nul besoin de préciser le nom de la classe ou de l’instance

• On verra plus tard que cette liaison est dynamique, et permet la mise à jour du contenu de cette variable

38

Aller d’une page à l’autre (1)• Pour aller à la nouvelle page, on commence par créer un

bouton dans le fichier .html de la page principale :<button ion-button>Cliquez ici</button>

• On rajoute ensuite une mention '(click)' qui permet d'indiquer le comportement à avoir lors d'un clic sur le bouton

<button ion-button (click)="boutonClic()">Cliquez ici</button>

39

Fonction qui sera appelée lors du 'clic'

Aller d’une page à l’autre (2)• On crée la fonction correspondante dans le fichier .ts de la page

principale:boutonClic() { this.navCtrl.push(MonEssaiPage); }

• Pour fonctionner, ce code a besoin au préalable de deux éléments :

• La page MonEssaiPage doit être importée pour être connueimport {MonEssaiPage} from '../mon-essai/mon-essai';

• Le contrôleur de navigation ‘navCtrl’ doit être connu et déclaré :import { NavController} from 'ionic-angular'; constructor(public navCtrl: NavController) {

40

Schéma récapitulatif

Cliquez ici

home.html

class HomePage { boutonClic() { this.navCtrl.push (MonEssaiPage); }

home.ts

{{unAttribut}}

mon-essai.html mon-essai.ts

class MonEssaiPage { unAttribut : string;

}

Démarrage de l'app

Le constructeur d'une classe de page

• Ce constructeur a des paramètres d'entrée qui fonctionnent de manière "magique" : il suffit de les mentionner pour qu'ils :

• soient renseignés avec des objets déjà initialisés

• remplissent un attribut du même nom (rendant l'objet accessible dans toute la classe)

• Cette 'magie' est en fait le pattern injection, géré par le framework

• Ces providers sont :

• Soit des contrôleurs standards d'ionic-angular (ex : NavController)

• soit déclarés dans app.module.ts (providers globaux à l'app)

• soit dans le bloc @Component de la page

42

Afficher des traces dans la console

• Lancer ionic serve avec le paramètre -c permet d'avoir une trace de la console dans le terminal, ce qui est bien pratique pour débugger

• Vous pouvez n'importe où dans le code afficher des éléments dans la console :

console.log("valeur de x :"+x);

• Vous pouvez également afficher des structures complexes avec JSON.stringify :

console.log("erreur :"+JSON.stringify(err));

43

Composants ionic• ionic2 est fourni avec de très très très nombreux

composants, pour gérer à peu près toute l’interface de son app mobile

• Nous allons voir sur la suite de ce cours quelques uns de ces composants, mais une bonne idée est de commencer par les découvrir en regardant la page :

• http://ionicframework.com/docs/v2/components/

44

Rafraichissement d'une page

• Pour proposer un rafraichissement d'une page, on passe par le composant <ion-refresher>, à positionner en tête de son <ion-content> :

<ion-refresher (ionRefresh)="doRefresh($event)"> <ion-refresher-content pullingIcon="arrow-dropdown" pullingText="Tirer pour mettre à jour" refreshingSpinner="circles" refreshingText="Mise à jour..."> </ion-refresher-content> </ion-refresher>

45

Récupérer la saisie d'un champ de saisie

• On commence par créer dans la classe (côté .ts, donc), un attribut nom qui récupérera le contenu

nom : string = "";

• Ensuite, dans la page (côté .html), on utilise le component ion-input avec la propriété ngModel qui va permettre de faire le lien avec l'attribut

<ion-input [(ngModel)]="nom"></input>

46

Créer une barre de navigation (1)

• On peut passer par le template ‘tabs’ lors de la création de son projet

• Mais il est également possible de construire manuellement sa barre de navigation :

• On commence par créer une ‘page’ qui ne contiendra que les données de la barre de navigation :

• ionic g page Tabs

• On crée ensuite deux pages qui compléteront Home en tant que pages pointées par la barre de navigation (pour l'exemple : Actus, Pratique)

47

Créer une barre de navigation (2)

• Cette page Tabs contient côté HTML la liste des entrées de la barre :

<ion-tabs> <ion-tab [root]="tab1Root" tabTitle="Home" tabIcon="home"></ion-tab> <ion-tab [root]="tab2Root" tabTitle="Actus" tabIcon="actus"></ion-tab> <ion-tab [root]="tab3Root" tabTitle="Pratique" tabIcon="pratique"></ion-tab> </ion-tabs>

• Le fichier .ts va permettre de lier à chaque entrée une page :import { HomePage } from '../home/home'; import { ActusPage } from '../actus/actus'; import { PratiquePage } from '../pratique/pratique';

export class TabsPage { tab1Root: any = HomePage; tab2Root: any = ActusPage; tab3Root: any = PratiquePage; 48

Créer une barre de navigation (3)

• Dernière étape, cette page Tabs doit être déclarée comme étant la page d’entrée de l’application, en remplacement de Home

• Cette opération se fait dans le fichier app.components.ts :

import { TabsPage } from '../pages/tabs/tabs'; export class MyApp { rootPage = TabsPage; // rootPage = HomePage; // ancienne page d'entrée

49

Créer un menu latéral

• On peut passer par le template ‘sidemenu’ lors de la création de son projet

• Mais il est également possible de construire manuellement son menu

50

API REST et JSON• Une API REST est un moyen de faire communiquer

un serveur et un client d’une manière souple, simple et légère, en se basant :

• Sur le protocole de transfert HTTP (compatible sur tous réseaux, léger, sécurisable) via ses diverses déclinaisons : GET, POST, PUT, DELETE

• Sur l’encodage JSON des trames, pour pouvoir transférer tout type de structure de données

51

JSON• Ce format est une alternative plus légère à XML pour structurer des

données

• donnée simple : "name" : "Jean Dupont"

• données multiples : "movies": ["titre1", "titre2"]

• structure complexe :{ "name":"paul rudd", "movies":[ "I Love You Man", "Role Models" ],}

52

Exemple d’API REST• Nous allons partir sur l’exemple complet en ligne

https://reqres.in

• Cet exemple permet à la fois de trouver des exemples de fonctionnement pour comprendre ce qu’est une API REST

• mais aussi de source pour pouvoir construire ses premiers projets sans se soucier de la partie serveur

• NB : le CMS WordPress est depuis sa version 4.7 un bon support pour diffuser facilement des données via une API REST

53

Exemple de requête REST simple

https://reqres.in/api/users/2

avec la méthode GET permet de récupérer les données du user 2

Données retournées :{ "data": { "id": 2, "first_name": "lucille", "last_name": "bluth", "avatar": "https://s3.amazonaws.com/jstein/128.jpg" }}

54

L’id est directement présent dans l’URL

Exemple de requête REST de liste

• https://reqres.in/api/users/ (sans préciser d’id user) permet de récupérer une liste

"page": "1", "per_page": 3, "total": 12, "total_pages": 4, "data": [ { "id": 4, "first_name": "eve", "last_name": "holt", "avatar": "https://s3.amazonaws.com/marcoramires/128.jpg" }, { "id": 5, "first_name": "gob", "last_name": "bluth", "avatar": "https://s3.amazonaws.com/stephenmoon/128.jpg" }, { "id": 6, "first_name": "tracey", "last_name": "bluth", "avatar": "https://s3.amazonaws.com/bigmancho/128.jpg" } ]} 55

Méthodes HTTP• Même si ces méthodes sont indépendantes des

traitements, on les utilise communément pour les usages suivants dans le cadre d’une API REST :

• GET : lecture de données

• POST : création de données

• PUT : mise à jour de données

• DELETE : suppression de données

56

Les codes d'erreur sont également mis à contribution :

• 200 : lecture ou traitement OK

• 201 : création OK

• 404 : aucune donnée

• 401 : connexion refusée

Lecture d’une API REST (1)

• On commence par créer un ‘provider’, classe réservée à un traitement qui n’est pas un affichage

• ionic g provider ApiTest

• Tant qu'on y est, on va également créer la page qui nous servira à afficher la liste des utilisateurs

• ionic g page ListUsers

57

Lecture d’une API REST (2)• Le provider contient le code de base pour appeler

l’API :import { Http } from '@angular/http'; export class ApiTest { baseurl: string; constructor(public http: Http) { this.baseurl = ‘https://reqres.in/api'; } getURL(url) { url=this.baseurl + url; return this.http.get(url).map(res => res.json()); }

58

L’adresse de l’API est importante car elle doit être

stockée en dur dans le code

Ce traitement est asynchrone ; on y reviendra

/providers/api-test.ts/pages/list-users/list-users.ts /pages/list-users/list-users.html

Lecture d’une API REST (3)

• On peut ensuite utiliser le provider dans une page pour peupler une liste

import {ApiTest} from '../../providers/api-test'; @Component({ providers: [ApiTest] }) export class UnePage { users: Array<any>;

constructor(public navCtrl: NavController, public apiTest:ApiTest) { }

59

toute variable passée en

entrée du constructeur est ensuite accessible

en tant qu’attribut

attribut qui stockera

la liste

Utilisation du provider

/providers/api-test.ts /pages/list-users/list-users.ts/pages/list-users/list-users.html

Lecture d’une API REST (4)

• On complète ensuite la classe d'une initialisation consistant à lire les données

ngOnInit() { this.apiTest.getURL('/users/').subscribe( data => { this.users = data.data; }, err => { console.log("erreur :"+JSON.stringify(err)); }, () => console.log('Load Complete') ); }

60

les données lues sont ensuite stockées dans

l'attribut users

Traitement asynchrone

/providers/api-test.ts /pages/list-users/list-users.ts/pages/list-users/list-users.html

"data": [ { "id": 4, … }, { "id": 5, … }, …]

Lecture d’une API REST (5)

• On gère ensuite l’affichage de la liste dans la partie HTML de la page

• <button> est un élément fixe, mais l'attribut *ngFor va provoquer sa répétition

<ion-list> <button ion-item *ngFor="let user of users"> {{user.first_name}}

</button> </ion-list>

61

/providers/api-test.ts /pages/list-users/list-users.ts /pages/list-users/list-users.html

"data": [ { "id": 4, "first_name": "eve", "last_name": "holt", "avatar": "…" },

Rendre les items de la liste cliquables (1)

• On va maintenant modifier nos <button> pour qu'ils soient cliquables

• chaque clic lance un appel à la méthode itemTapped(), en passant en paramètre le user courant

<button ion-item *ngFor="let user of users" (click)="itemTapped($event, user)">

… </button>

62

/providers/api-test.ts /pages/list-users/list-users.ts /pages/list-users/list-users.html

Rendre les items de la liste cliquables (2)

• Un clic sur un élément provoquera l’appel à une méthode de la classe

itemTapped(event, user) { this.navCtrl.push(UserPage, { param_user: user }); }

63

C'est l'objet user complet qui est envoyé en paramètre d’entrée de la

page UserPage

/providers/api-test.ts /pages/list-users/list-users.ts/pages/list-users/list-users.html

Rendre les items de la liste cliquables (3)

• On va ensuite créer une page User

• Cette page contiendra le code nécessaire pour récupérer le paramètre qu'on lui a fourni

user:any; constructor(public navCtrl:NavController, public navParams: NavParams) { this.user = navParams.get('param_user'); }

64

/providers/api-test.ts /pages/list-users/list-users.ts /pages/list-users/list-users.html /pages/user/user.ts/pages/user/user.html

Rendre les items de la liste cliquables (4)

• La page va ensuite pouvoir afficher le contenu à partir de l'objet user qu'on a reçu en paramètre, sans rechargement nécessaire

<ion-card> <ion-card-content> <ion-card-title>

Bonjour, {{user.first_name}} {{user.last_name}} ! </ion-card-title>

</ion-card-content> </ion-card>

65

/providers/api-test.ts /pages/list-users/list-users.ts /pages/list-users/list-users.html /pages/user/user.ts /pages/user/user.html

Schéma récapitulatifServeur

Héberge des API RESTHTTPapi-test.ts

provider de lecture de l'API

list-users.ts• Appel du

provider • Stockage

dans l'attribut 'users'

list-users.htmlboucle sur

'users'

user.tsStockage de 'user' en attribut

data

param_user : useritemTapped(user)

user.htmlaffiche 'user'

Créer un traitement asynchrone

• Contrairement à ce qui se passe avec un développement web classique, tout dans Ionic/Angular fonctionne de manière asynchrone :

• On commence par afficher la page

• On s'occupe ensuite d'afficher les éléments dynamiques au fur et à mesure de leur récupération

• L'objectif est de fluidifier au maximum la réactivité de l'application

67

Subscribe• Les appels aux API REST étaient asynchrones :

this.apiTest.getURL('/users/').subscribe( data => { this.users = data; }, err => { }, ); }

68

Traitement asynchrone

N'est exécuté qu'une fois la

lecture achevée

<ion-card *ngFor="let user of users"> … </ion-card> L'affichage

est lui aussi asynchrone

Créer ses propres traitements asynchrones

getMedia(id) { return Observable.create(s => { // traitement prenant du temps var retour = /* retour préparé */; s.next(retour); s.complete(); }, err => { console.log(JSON.stringify(err)); }, () => console.log('getMedia terminé') ); }

69

this.apiTest.getMedia(id).subscribe( data => { this.users = data; }, err => { }, ); }

s.next() permet d'envoyer des données en

retour de getMedia()

Afficher du contenu HTML• Dans certains cas (par exemple en récupérant un

article de Wordpress), l'API peut vous retourner du code HTML

• Pour que ce code soit interprété (et non pas affiché), il faut utiliser une balise particulière :

<p [innerHTML]="user.descriptif"></p>

70

Pas besoin de mettre des accolades

pour préciser qu'il s'agit d'un attribut

Gestion des styles

• Le look des pages s'effectue via des styles CSS situés :

• de manière globale, dans /src/app/app.scss

• pour chacune des pages, dans nom-page.scss

• Il est possible de lier un thème à son application

71

SCSS• Il s'agit d'une déclinaison du langage CSS, avec

quelques rajouts bien utiles

• Chaque code SCSS est ensuite transformé en CSS

• Par exemple :

72

table.hl { margin: 2em 0; td.ln { text-align: right; }}

li { font: { family: serif; weight: bold; size: 1.3em; }}

table.hl { margin: 2em 0;}table.hl td.ln { text-align: right;}

li { font-family: serif; font-weight: bold; font-size: 1.3em;}

L'héritage en SCSS• Permet de simplifier l'écriture de certains blocs

73

.error border: 1px #f00 background: #fdd

.error.intrusion font-size: 1.3em font-weight: bold

.badError @extend .error border-width: 3px

.error, .badError { border: 1px #f00; background: #fdd;}

.error.intrusion,

.badError.intrusion { font-size: 1.3em; font-weight: bold;}

.badError { border-width: 3px;}

Insertion d'animations• On peut utiliser la bibliothèque animate.css

https://daneden.github.io/animate.css/

1. Téléchargement et stockage dans /src/assets/css

2. Chargement dans /src/index.html <link href="assets/css/animate.css" rel="stylesheet">

3. Utilisation dans le code HTML des pages. Ex :<ion-card class="animated fadeInLeftBig">

74

Plugins natifs• Ces plugins sont la raison d'être même d'Ionic :

permettre de tirer le meilleur du hardware des smartphones tout en restant dans un contexte web

• C'est Cordova qui est en charge de la partie native, par toute une série de plugins développés dans les langages natifs des environnements (iOS, Android)

• Liste complète des plugins (plus de 2000 !) disponibles à l'adresse suivante :https://cordova.apache.org/plugins/

75

Prise de photo• On utilise le plugin natif cordova-plugin-camera :ionic plugin add cordova-plugin-camera

• La page dédiée à la prise de photo sera ainsi constituée :import {Camera} from 'ionic-native';

export class CapturePicPage { public base64Image: string;

}

• L'attribut base64Image permettra de stocker la dernière photo prise sous forme binaire

• On pourra bien sûr stocker ensuite cette photo en base de données

76

Interface de prise de photo• Dans cet exemple minimaliste, on se contente d'un bouton

pour lancer le capteur, et pour afficher la dernière photo prise :

<ion-card> <ion-card-content> <h1>Prise de photo</h1>

<button ion-button (click)="takePicture()">Prendre une photo</button>

<h2>Dernière photo prise :</h2> <img *ngIf="base64Image" [src]="base64Image" /> </ion-card-content> </ion-card>

77

Le "src" est ici à prendre au sens large

(donnée binaire, pas nom de fichier)

La balise ne sera présente que si l'attribut base64Image n'est pas

vide

Méthode de prise de photo• Dernière étape : créer la méthode takePicture() qui

sera appelée lors du clic sur le bouton :takePicture(){ Camera.getPicture({ destinationType: Camera.DestinationType.DATA_URL, targetWidth: 1000, targetHeight: 1000 }).then((data) => { this.base64Image = "data:image/jpeg;base64," + data; }, (err) => { console.log(err); }); }

78

Stockage local de données• On commence par créer un Provider qui centralisera

l'accès aux données. Il aura pour rôle :

• de stocker de manière centralisée les principales données de l'application pendant son fonctionnement

• d'accéder à la base de données pour stocker des données de manière persistante

• Attention, pour écrire les tests permettant de déterminer la source des données, il faudra en permanence penser aux traitements asynchrones

79

Créer un provider global• Pour stocker des données qui seront accessibles tout au long

du fonctionnement de l'application :

• Créer un provider doté d'attributs dans lesquels on stocke les données

• Déclarer ce provider directement dans le bloc @NgModule de app.module.ts

• On pourra ensuite créer dans ce même provider des méthodes d'accès à la base de données, pour apporter une pérennité aux données au delà de la présence en mémoire de l'application

Mettre en priorité les moteurs les plus performants

80

Différents styles de stockage

• Il existe plusieurs moteurs de stockage de données pour une app Ionic :

• SQLite (mini-SGBD embarqué sous forme de plugin natif)

• IndexedDB (mini-SGBD conçu par Mozilla)

• WebSQL (API vers un SGBD porté sur Chrome et Safari)

• localstorage (stockage de données key->value standardisé dans HTML5)

81

Installation

• Le seul élément essentiel est le module gérant le frontal d'accès au stockage de données

npm install --save @ionic/storage

• Vous pouvez également installer le plugin (natif) SQLite

cordova plugin add cordova-sqlite-storage --save

82

Configuration du module• Tout se passe dans app.module.tsimport { IonicStorageModule } from '@ionic/storage'; … @NgModule({ declarations: ..., imports: [ IonicStorageModule.forRoot({ name: '__mydb', driverOrder: ['indexeddb', 'sqlite', 'websql','localstorage'] }) ],

83

Mettre en priorité les moteurs les plus

performants

Utilisation de base• Le principe universel est celui dit "key/value" : on stocke

une valeur, indexée par une cléimport { Storage } from '@ionic/storage'; … constructor(……, public storage:Storage) { this.storage.ready().then(() => { // stockage d'une valeur this.storage.set('name', 'Jean David');

//Lecture d'une valeur par sa clé this.storage.get('session_ID').then((val) => { console.log('votre ID session :', val); }) });

84

Key Value

name Jean David

client 1

session_ID enGHumY%2C-2De-F-TDzNHVmE%2ChY5

Utilisation avec SQL• Lorsque le moteur de base de données le permet, on peut

utiliser des requêtes SQL (simplifiées) pour structurer de manière plus complexe ses données

import {SqlStorage, Storage} from '@ionic/storage'; export class HomePage { private storage: Storage; public constructor() { this.storage = new Storage(SqlStorage); this.storage.query("CREATE TABLE IF NOT EXISTS users

(id INTEGER PRIMARY KEY AUTOINCREMENT, first_name TEXT, last_name TEXT)");

}

85

Insertion de données avec SQL

• Les traitements sont asynchrones this.storage.query("INSERT INTO users (first_name, last_name) VALUES (?, ?)", ["JD", "Olek"]).then((data) => { console.log("ok!"); }, (error) => { console.log(error); });

86

Cette partie n'est exécutée qu'une fois l'insertion terminée

Lecture de données avec SQL

• Là aussi, la lecture est asynchrone let liste:Array<Object>;

this.storage.query("SELECT * FROM users").then((data) => { if(data.res.rows.length > 0) { liste = []; for(let i = 0; i < data.res.rows.length; i++) { liste.push({ "id": data.res.rows.item(i).id, "first_name": data.res.rows.item(i).first_name, "last_name": data.res.rows.item(i).last_name, }); } } }, (error) => { console.log(error); });

87

Géolocalisation• Une fois encore, on va utiliser un plugin natifionic plugin add cordova-plugin-geolocation

• La récupération des coordonnées est un simple traitement asynchroneimport { Geolocation } from 'ionic-native'; export class MaPage { latitude : number; longitude : number; … ionViewDidLoad() {

Geolocation.getCurrentPosition().then((position) => { this.latitude=position.coords.latitude; this.longitude=position.coords.longitude;

} }

 

88

On peut aussi imaginer faire plutôt un provider pour gérer la

localisation

Géoloc et Google Maps• Cette partie va être l'occasion de montrer l'usage

d'une librairie Javascript directement au sein d'une app Ionic

• Le chargement de la librairie Google Maps se fait directement dans le fichier index.html :

<script src="http://maps.google.com/maps/api/js"></script>

89

En production, il faut rajouter ?key=MACLE en

mentionnant une clé d'utilisateur

de Google Maps

Affichage de la map• L'affichage sera une simple zone avec un marqueur #map qui

permettra au traitement de remplir plus tard cette zone avec la carte

<ion-content> <div #map id="carte"></div> </ion-content>

• Du côté du fichier .ts, on utilise ViewChild et ElementRef pour pouvoir manipuler ce bloc #map plus tard

import { Component, ViewChild, ElementRef } from '@angular/core'; declare var google; export class HomePage { @ViewChild('map') mapElement: ElementRef; map: any;

90

.scroll-content { height: 100% } #carte { width: 100%; height: 100%; }

Le CSS permettra de s'assurer du bon

affichage de la carte

Génération de la map• Il nous reste encore à afficher la map. On le fait à la

suite de la géolocalisation ionViewDidLoad(){ … let mapOptions = { center: new google.maps.LatLng(this.latitude,this.longitude), zoom: 15, mapTypeId: google.maps.MapTypeId.ROADMAP }

this.map = new google.maps.Map( this.mapElement.nativeElement, mapOptions);

}

91

Coordonnées précédemment obtenues

par le plugin de géolocalisation

Pointage vers l'emplacement #map de la

vue