Application mobile hybride

 

Workshop - 22 avril 2020

Mathieu Castets

Application native

  • Performances
  • Fonctionnalités "natives"
  • Mises à jour des SDK
    • Nouvelles fonctionnalités
    • Corrections de bugs
  • Native look and feel / UX

Application native

  • Langages différents
    •     Objective-C / Swift
    •      Java / Kotlkin
  • SDK différents
  • IDE différents
    •      Xcode
    •      Android Studio

Application multiplateforme

Write once, run anywhere

  • Fin 2018
  • Google
  • Dart
  • Présence faible sur les stores
  • Écosystème indépendant
  • 2011
  • Microsoft
  • .NET / C#
  • ~8% du marché des app
  • Visual Studio Community
  • Accès limité aux bibliothèques open source
  • 2015
  • Telerik
  • JS / TS / Angular / Vue.js mais...
  • ... pas de DOM (XML seulement)
  • CSS limité
  • Popularité faible
  • 2015
  • Facebook
  • React / JSX / Virtual DOM
  • ~8 à 13% du marché des app
  • Native look and feel
  • Pas de HTML
  • "Learn once, write anywhere"

Équipes pluridisciplinaires web

  • HTML
  • CSS / SASS
  • JS / TS
  • Protocole HTTP
  • Frameworks (AngularJS / Angular)
  • Bibliothèques (npm / yarn)
  • Web app existante : réutilisation de code ?

Application hybride

Une application multiplateforme mais avec les technologies du web

  • 2008
  • Fondation Apache
  • Open source
  • WebView
  • config.xml
  • Fonctionnalités natives via plugins
  • 25 à 40% du marché des app

Fonctionnement

Un peu d'histoire

  • 2008 : Nitobi (CA) créé PhoneGap
  • 2011 : Adobe rachète Nitobi et PhoneGap
  • Code source transféré à la foundation Apache (open source) en "Cordova"
  • PhoneGap reste un produit commercial Adobe : une distribution de Cordova

👍

  • Langages / frameworks web
  • Communauté
  • Partage de code
  • Design
  • Outils de développement communs
  • Fonctionnalités "natives" via plugins Cordova

👎

  • Performances
  • (Fonctionnalités "natives" via plugins Cordova)
  • (Native look and feel)

Application hybride

Cordova + Framework JS

Fonctionnalités "natives" via plugins Cordova

La relève de Cordova

Le roi est mort, vive le roi !

  • 2019
  • Ionic
  • Open source
  • WebView
  • 20+ core plugins
  • iOS / Android / PWA / Electron
  • Rétrocompatibilité plugins Cordova
  • Philosophie différente

Cordova

  • 👴 12 ans
  • Open Source
  • WebView
  • 📚 3000+ plugins
  • 🛶 Communication JS
  • 👕 Communauté
  • 🌱 Mauvais support Browser
  • 🌍 CLI global
  • Abstraction "config.xml"

Capacitor

  • 👦 1 an
  • Open Source
  • WebView
  • 📕 20+ core plugins
  • 🛥 Interface TS
  • 👔 Ionic + communauté
  • 🌳 Built-in PWA & web support
  • 🏙️ CLI locale
  • Sources natives
  • Support Electron
  • Rétrocompatibilité Cordova
  • Live reload
  • Suppression event deviceready

Native look and feel

Ionic à la rescousse

Open source

  • Framework
  • Ionic Native
  • Capacitor
  • Ionic Animations
  • Ionicons
  • Stencil

Entreprise

  • Support
  • Revue de code
  • Audit de sécurité
  • IDE : Ionic Studio
  • CI/CD : Ionic AppFlow
  • Solutions clé en main

Ionic

  • 2013
  • 10 à 16% du marché des app
  • Angular / React / Vue
  • 100+ composants UI
  • Native look and feel
  • Mises à jour (plateform guidelines)
  • Animations
  • Navigation
  • Touch gestures
  • Standards du web
    • Web Component
    • Shadow DOM
    • Variables CSS

(framework)

Aperçu :

composants & patterns

ion-refresher

<ion-content>
  <ion-refresher slot="fixed" pullFactor="0.5" pullMin="100" pullMax="200">
    <ion-refresher-content
      pullingIcon="arrow-dropdown"
      pullingText="Pull to refresh"
      refreshingSpinner="circles"
      refreshingText="Refreshing...">
    </ion-refresher-content>
  </ion-refresher>
</ion-content>

ion-skeleton-text

skeleton screens are perceived as being shorter in duration when compared against a blank screen and a spinner

<ion-item *ngIf="data">
  <h3>
    {{ data.heading }}
  </h3>
  <p>
    {{ data.body }}
  </p>
</ion-item>

<ion-item *ngIf="!data">
  <h3>
    <ion-skeleton-text animated style="width: 50%"></ion-skeleton-text>
  </h3>
  <p>
    <ion-skeleton-text animated style="width: 80%"></ion-skeleton-text>
  </p>
</ion-item>

ion-infinite-scroll

<ion-content>
  <ion-list>
  	...
  </ion-list>

  <ion-infinite-scroll threshold="100px" (ionInfinite)="loadData($event)">
    <ion-infinite-scroll-content
      loadingSpinner="bubbles"
      loadingText="Loading more data...">
    </ion-infinite-scroll-content>
  </ion-infinite-scroll>
</ion-content>

ion-img

lazily load an image when ever the tag is in the viewport

<ion-list>
  <ion-item *ngFor="let item of items">
    <ion-thumbnail slot="start">
      <ion-img [src]="item.src"></ion-img>
    </ion-thumbnail>
    <ion-label>{{item.text}}</ion-label>
  </ion-item>
</ion-list>

Ionic Native

  • TypeScript wrapper
  • 200+ plugins

Exemple

import { ScreenOrientation } from '@ionic-native/screen-orientation/ngx';

constructor(private screenOrientation: ScreenOrientation) { }

...

// set to landscape
this.screenOrientation.lock(this.screenOrientation.ORIENTATIONS.LANDSCAPE);

// allow user rotate
this.screenOrientation.unlock();

// detect orientation changes
this.screenOrientation.onChange()
	.subscribe(() => console.log(`Orientation changed to ${this.screenOrientation.type}`));

$ cordova plugin add cordova-plugin-screen-orientation
$ npm install @ionic-native/screen-orientation

Installation

Usage

Application hybride moderne

Application hybride, un monde idéal ?

Apparition de nouvelles problématiques

ll ne faut pas crier victoire trop tôt.

First Meaningful Paint

  • 📶 Connectivité limitée
  • ⚠️ Serveur down
  • 🐢 Assets distants
  • 🔥 Exceptions
  • Appels réseaux strictement nécessaires
  • Payload serveur optimisée
  • Splash screen
  • Assets locales
  • Gestion des exceptions
  • Retry policy

👎

👍

Stockage local

🌱 Local Storage

🌿 @ionic/storage

  • Taille limitée
  • Non persistent
  • Clé / valeur
  • Basé sur LocalForage

🌳 @ionic-native/sqlite

$ cordova plugin add cordova-sqlite-storage
$ yarn add @ionic/storage
$ cordova plugin add cordova-sqlite-storage
$ yarn add @ionic-native/sqlite
  • Moteur de BDD
  • Transactions, tables, ...

Cookies 🤯

CORS

Cross-Origin Resource Sharing

http://localhost

ionic://localhost

 https://api.example.com

XMLHttpRequest cannot load https://api.example.com.
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'ionic://localhost' is therefore not allowed access. 

Deux solutions

  • Accès serveur requis
  • Simple
  • Aucune action serveur
  • Complexifie les devs et tests
Access-Control-Allow-Origin: origin | *
$ cordova plugin add cordova-plugin-advanced-http
$ yarn add @ionic-native/http

CSP

Content Security Policy

ionic://localhost

⚠️ frame-ancestors * ne s'appliquent pas aux custom schemes comme ionic://

Content-Security-Policy "default-src * 'unsafe-inline'; frame-ancestors *; img-src * data:";

Solution sur payment.example.com

Content-Security-Policy "default-src * 'unsafe-inline'; frame-ancestors * ionic:; img-src * data:";
<iframe src="https://payment.example.com"></iframe>
Refused to load https://payment.example.com because it does not appear in the frame-ancestors directive of the Content Security Policy.

APIs externes

  • Danger sur l'exposition des clés d'API
  • Header "Referer" absent : protection caduque
  • Préférer une solution native si possible

Build et release

Fastlane - App automation done right

Sources

Questions ?

Made with Slides.com