Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Progressive Web App
  3. Projet Fugu
Extrait - Progressive Web App Utilisez les standards du web pour développer vos applications mobiles
Extraits du livre
Progressive Web App Utilisez les standards du web pour développer vos applications mobiles Revenir à la page d'achat du livre

Projet Fugu

Introduction

Les standards du Web évoluent dans le but de toujours réduire l’écart avec le monde du développement natif. Il est loin le temps où on ne pouvait faire que des formulaires HTML avec un peu de dynamisation en JavaScript. De jour en jour, la plateforme web propose de nouvelles fonctionnalités allant de l’API Badging à l’API Web Share. Le nom de code choisi pour tous ces efforts en termes d’ajout de fonctionnalités sur la plateforme web est « Projet Fugu ».

L’équipe en charge du navigateur de Google Chrome a développé une application donnant une première idée sur les possibilités de ces nouvelles API. Vous trouverez des informations complémentaires sur la page dédiée à ce projet : https://research.google/pubs/pub48955/

La liste de ces nouvelles fonctionnalités étant conséquente, nous n’en présenterons qu’une partie dans ce chapitre. Nous aurions pu parler par exemple de WebNFC, WebAssembly, WebRTC, WebAuthn ou encore WebXR. Mais nous avons dû faire un choix.

Nous avons également fait le choix de décrire certaines fonctionnalités qui sont présentes depuis longtemps, mais que nous trouvons primordiales pour un usage sur mobile.

Nous allons aborder les API suivantes, en proposant pour chacune d’entre elles un exemple...

API Geolocation

Lors de l’utilisation d’une application via un appareil mobile, il peut être intéressant de récupérer les coordonnées GPS de l’utilisateur afin de dynamiser le contenu affiché ou d’améliorer l’expérience utilisateur.

Un standard HTML permet de récupérer ces informations. C’est l’API Geolocation.

Avant de l’utiliser, nous nous assurons que le navigateur la supporte en faisant une feature detection.

if ("geolocation" in navigator) { 
  ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Une fois cette vérification réalisée, nous pouvons utiliser deux méthodes. L’appel à l’une de ces deux méthodes nécessite la validation de l’utilisateur via une demande de permission.

La première, getCurrentPosition permet de récupérer les coordonnées de l’utilisateur au moment de l’exécution de la fonction. Cette méthode accepte en paramètre une fonction qui sera exécutée lorsque la récupération des coordonnées, correspondant à un traitement asynchrone, sera terminée. Le paramètre de cette fonction contiendra les informations demandées.

Dans l’exemple...

API Screen Orientation

Il peut être nécessaire de connaître l’orientation d’un appareil (mode portrait ou mode paysage ou landscape, par exemple) afin de définir un fonctionnel spécifique. Pour ce faire, il existe l’objet screen.orientation.

Avant d’utiliser cette API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

if (screen.orientation) { 
    ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Cette propriété, screen.orientation , retourne un objet contenant une propriété type. Cette propriété accepte les quatre valeurs suivantes :

  • landscape-primary : quand la largeur est plus grande que la hauteur.

  • landscape-secondary : quand la largeur est plus grande que la hauteur, mais avec une rotation de 180 degrés.

  • portrait-primary : quand la hauteur est plus grande que la largeur.

  • portrait-secondary ...

API Badging

L’API Badging permet d’ajouter un badge sur l’icône d’une Progressive Web App afin d’indiquer à l’utilisateur qu’il doit y retourner car une activité a eu lieu. Cette activité peut être une réponse à un message, des nouveautés dans l’application, une promotion sur certains produits ou encore la réception d’un message de type push. C’est le concepteur de l’application qui doit décider quelle information il souhaite utiliser pour ajouter cet indicateur sur l’icône de l’application.

Pour le moment, cette API ne peut être appelée que depuis une page web, éventuellement en arrière-plan. Dans de futures versions, appeler cette API depuis un Service Worker sera bien évidemment possible.

Avant de l’utiliser, nous nous assurons que le navigateur la supporte en faisant une feature detection.

if (window.ExperimentalBadge) { 
  ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Depuis Chrome 79 (une autre version de cette API est disponible avec Chrome 78), nous devons manipuler l’objet ExperimentalBadge afin de définir le chiffre à afficher (méthode set) ou de réinitialiser ce chiffre (méthode clear).

Dans l’exemple ci-après nous...

API Contact Picker

Cette API permet de donner l’accès au carnet de contacts de l’utilisateur depuis une page web. Plus précisément, via un appel JavaScript, nous allons être capables d’ouvrir le composant natif de sélection des contacts. Une fois ce composant visible, l’utilisateur pourra sélectionner certains contacts et partager certaines données avec l’application.

Une contrainte de sécurité doit être respectée afin d’éviter que l’utilisateur partage trop d’informations sur ses contacts avec l’application web utilisée.

Avant d’utiliser cette API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

if(‘contacts' in navigator && ‘ContactsManager' in window) { 
     ... 
} else { 
   console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Afin de pouvoir sélectionner un ou plusieurs contacts via le composant natif de la plateforme, nous utilisons la méthode select. Cette méthode accepte deux paramètres :

  • Le premier correspond aux propriétés que nous souhaitons récupérer dans l’application.

  • Le deuxième paramètre correspond à des options spécifiques à cette méthode, par...

API Get Installed Related Apps

La méthode getInstalledRelatedApps permet de vérifier, depuis une Progressive Web App, si l’application native a également été installée par l’utilisateur. Grâce à cette méthode, nous pouvons par exemple inviter l’utilisateur à utiliser l’application native pour des fonctionnalités qui ne sont pas encore implémentées dans la Progressive Web App.

Pour cela, il faut tout d’abord faire le lien entre les deux applications. Côte Progressive Web App, nous allons définir ce lien dans le fichier Manifest décrit précédemment.

Dans l’exemple ci-après, nous indiquons que notre Progressive Web App est associée à une application native <package-name> publiée sur le Play Store (Android). Le <package-name> correspond à la chaîne de caractères permettant l’identification de manière unique de l’application dans le monde Android. 

{ 
  ... 
    "related_applications": [{ 
    "platform": "play", 
    "id": "<package-name>", 
    "url": "https://play.google.com/store/apps/details?id=
<package-name> 
  }], ...

API Wake Lock

L’API Wake Lock permet de s’assurer qu’un appareil ne se met pas en veille pendant l’utilisation de l’application. Cela peut être intéressant si nous développons un jeu par exemple, ou encore si l’utilisateur est en train de visionner une vidéo. Le fait de pouvoir utiliser cette API ne nous assure pas qu’elle sera fonctionnelle. En effet, le navigateur pourrait refuser notre demande pour différentes raisons, par exemple un niveau de batterie trop faible.

Pour faire une demande de wake lock, il suffit d’appeler la méthode wakeLock.request

Avant d’utiliser cette API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

 
if(‘wakeLock' in navigator) { 
   ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Cette méthode accepte un paramètre correspondant au type de lock que nous souhaitons demander. À l’heure actuelle, nous ne pouvons interagir qu’avec l’écran d’un appareil.

  if(‘wakeLock' in navigator) { 
   let wakeLock; 
   navigator.wakeLock.request('screen') 
    .then(lock => wakeLock = lock); 
  } 

Afin d’éviter d’abuser...

API Shape Detection

Dès que nous avons besoin de manipuler des images afin de détecter des visages, du texte ou encore un simple code QR, un développement côté serveur est souvent nécessaire, avec éventuellement des modèles de machine learning permettant de faire le traitement souhaité.

Ces fonctionnalités sont à présent disponibles dans nos applications web grâce à l’API Shape Detection. Les contenus cités précédemment peuvent être détectés sur une image via la manipulation de différents objets : BarcodeDetectorFaceDetector ou encore TextDetector.

Avant d’utiliser une API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

 if(‘FaceDetector' in window) { // ou TextDector ou BarcodeDetector 
  ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Nous instancions l’objet que nous souhaitons détecter. Sur cette instance, nous appelons la méthode detect en passant en paramètre l’image que nous souhaitons manipuler. L’image peut être un objet ImageBitmapSource, CanvasImageSource, Blob ou encore ImageData. Cette méthode retourne un tableau de tous les objets détectés dans l’image.

const image...

API Web Share

L’API Web Share permet de partager le contenu de notre application en utilisant le composant natif de partage d’un appareil. Pour cela, nous devons faire appel à une seule méthode, à laquelle nous allons passer en paramètre un objet permettant de décrire le contenu que nous souhaitons partager.

Avant de l’utiliser, nous nous assurons que le navigateur la supporte en faisant une feature detection.

 if(‘share' in navigator) { 
    ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
}  

La seule méthode à appeler est la méthode share. Dans l’exemple suivant, nous définissons les informations que nous souhaitons partager et qui seront utilisées par le composant natif du téléphone. Si aucune des propriétés listées ci-après n’est définies, la Promise est rejetée avec une erreur de type TypeError.

if(‘share' in navigator ) { 
  navigator.share({ 
    title : ‘Web Share API', 
    text : ‘Ceci est un article concernant la Web Share API', 
    url : ‘https://twitter.com/EmmanuelDemey' 
}) ; 
} 

Nous pouvons exécuter...

API Web Share Target

Nous venons d’expliquer comment, depuis notre application, nous pouvons partager de l’information vers l’extérieur. Ce mécanisme est en charge d’ouvrir le composant natif de partage d’un appareil.

Pouvons-nous faire l’inverse ? C’est-à-dire enregistrer notre application dans le système comme étant une application pouvant recevoir de l’information depuis ce même composant natif ? C’est effectivement possible grâce à l’API Web Share Target. L’application Unsplash a intégré cette API récemment afin de pouvoir facilement charger des images et éventuellement les traiter.

Nous allons ajouter la propriété share_target à notre fichier Manifest. Cette propriété permet d’enregistrer notre Progressive Web App comme étant une application pouvant recevoir de l’information, mais également de configurer son comportement quand l’utilisateur la sélectionne depuis le composant natif de votre système.

Dans l’exemple suivant, nous indiquons qu’une requête GET vers l’URL share-target/ doit être envoyée à notre application. Nous définissons également le mapping entre les données partagées par l’application externe et le nom des paramètres qui seront...

API SMS Receiver

Lorsqu’un utilisateur visite des sites web sur mobile et qu’il souhaite créer un nouveau compte, certains de ces sites envoient un SMS afin de faire une authentification en deux étapes. Lors de la réception de ce SMS, l’utilisateur est obligé de quitter le navigateur pour aller dans son application de messages afin de copier le code qu’il a reçu, pour ensuite revenir sur le site web et le coller. 

Via l’API SMS Receiver, nous pouvons donner l’opportunité à l’utilisateur de rester sur le site web et laisser le soin à l’application de récupérer le contenu du message reçu et d’en extraire, via une expression régulière, le code que le serveur a envoyé.

Avant d’utiliser cette API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

if(‘sms' in navigator) { 
   ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Dans l’exemple ci-après, si l’API SMS Receiver est disponible sur le navigateur utilisé, nous appelons la méthode receive pour attendre la réception d’un nouveau SMS. Une fois le SMS reçu, nous récupérons dans la propriété content le contenu du message envoyé....

API Payment Request

Une API est à notre disposition afin de faciliter le paiement sur un site d’e-commerce. Cette API ne sera pas en charge de faire le paiement à proprement parler, mais plutôt de récupérer les informations nécessaires, par exemple le nom de la personne, son numéro de carte de crédit, la date de validité du moyen de paiement… via l’utilisation d’un composant natif disponible dans le navigateur.

Avant d’utiliser cette API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

 
if(window.PaymentRequest) { 
   ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Pour présenter cette API, imaginons que sur notre Progressive Web App un bouton permet de valider le panier d’achats.

document.getElementById(‘validateBasket') 
  .addEventListener(‘click', () => { 
     ... 
  }) ; 

Si l’API n’est pas supportée par le navigateur, nous pouvons rediriger l’utilisateur vers une page dédiée à la validation du panier.

document.getElementById(‘validateBasket') 
  .addEventListener(‘click', () => { 
    if (!window.PaymentRequest) { 
      location.href = '/checkout'; 
      return; 
    } 
    ... 
   }) ; 

Si le navigateur supporte cette API, nous instancions un nouvel objet PaymentRequest et ensuite nous faisons appel à la méthode...

API Picture in Picture

Lors de l’utilisation d’un téléphone, l’une des contraintes est la taille de l’écran et le fait de switcher entre les différentes applications pour pouvoir les utiliser. Il serait intéressant par exemple d’interagir avec une application tout en gardant un œil sur une deuxième.

Cette problématique vient d’être résolue pour le visionnage de vidéos. Grâce à l’API Picture in Picture, il est à présent possible de visionner une vidéo grâce à un client flottant, tout en interagissant avec une deuxième application. Les navigateurs limitent le visionnage d’une seule vidéo par session utilisateur. Si une deuxième vidéo est lancée, cela arrêtera la première.

Avant d’utiliser cette API, nous nous assurons que le navigateur la supporte en faisant une feature detection.

if ('pictureInPictureEnabled' in document) { 
   ... 
} else { 
  console.log(‘Ce navigateur ne supporte pas cette API') ; 
} 

Si, par exemple, nous avons le code HTML suivant :

<video id="video" src="https://pwa.com/file.mp4"></video> 
 
<button id="pipButton" hidden> 
  Afficher via Picture in Picture 
</button>...

API Portal

À l’heure de la rédaction de cet ouvrage, nous avons deux solutions pour développer des applications :

  • Multiple Page Application (MPA) : cette solution historique correspond à des pages générées côté serveur, nécessitant un rafraîchissement lors d’une redirection.

  • Single Page Application (SPA) : ces applications sont développées en utilisant des frameworks JavaScript, comme Angular, React.js ou encore Vue.js. Ces solutions ne nécessitent pas de rafraîchissement complet lors d’une redirection. En effet, l’ensemble du système de navigation est géré côté navigateur. 

Lorsque nous souhaitons mettre en place une animation lors d’une redirection d’une page vers un autre, la solution est assez simple pour des Single Page Applications. Les frameworks et librairies du marché proposent même des solutions prêtes à être utilisées (par exemple, Angular Animations). Par contre, lorsque nous souhaitons le faire pour des Multiple Page Applications, cela est beaucoup plus compliqué.

Une spécification est en cours de création pour résoudre cette problématique. Nous allons mettre en place des Portals. Cette API nous permettra de faire une redirection d’une page à une autre, éventuellement pas du même domaine, tout en nous laissant la possibilité d’ajouter une animation, mais également de communiquer avec la page vers laquelle l’utilisateur souhaite être redirigé.

Avant...

Application fil rouge

Nous n’allons pas pouvoir mettre en place dans notre application toutes les API décrites dans ce chapitre. Nous allons nous limiter à seulement deux d’entre elles : l’API Web Share, afin de partager un projet GitHub sur les réseaux sociaux, et l’API Portal, afin de rediriger un utilisateur sur le site github.com lorsqu’il clique sur un projet.

Nous allons tout d’abord intégrer l’API Web Share. Cette API sera utilisée lorsque l’utilisateur cliquera sur un bouton que nous allons ajouter pour chaque projet. Afin de différencier ce nouveau bouton de celui permettant de mettre en favori, nous allons associer à ce dernier une classe CSS permettant de le sélectionner facilement. Dans la méthode generateUI, nous ajoutons la classe CSS favorite de cette façon.

<button class="favorite button" data-repo-id="${repo.id}"> 
   Favori 
</button> 

Une fois cette modification réalisée, nous pouvons restreindre, dans la méthode initClickHandler, les boutons sur lesquels le traitement est réalisé, afin d’éviter de sélectionner des boutons qui seront éventuellement ajoutés a posteriori. Pour cela, nous ajoutons un sélecteur basé sur la classe CSS précédemment ajoutée.

const favorisButton =  
document.querySelectorAll(".favorite[data-repo-id]"); 

Voilà, le terrain est enfin prêt pour implémenter l’API Web Share. Nous allons tout d’abord ajouter un nouveau bouton juste à côté de celui existant. Par défaut, ce bouton sera caché via l’ajout de l’attribut HTML hidden. En effet, nous voulons le rendre actif si et seulement si l’API Web Share est supportée.

<button class="favorite button" data-repo-id="${repo.id}"> 
    Favori 
</button> 
<button class="share button" data-repo-id="${repo.id}" hidden> 
    Share 
</button> 

Le code JavaScript associé à ce bouton est implémenté dans une nouvelle méthode nommée initWebShare. Cette méthode est appelée...