AccueilClientsExpertisesBlogOpen SourceJobsContact

18 mars 2024

Embarquez vos sites Web dans une application React Native avec les WebViews

8 minutes de lecture

Embarquez vos sites Web dans une application React Native avec les WebViews

Dans cet article, nous allons explorer l'intégration d'un site web dans une application mobile avec React Native en utilisant les WebViews.

Chez Premier Octet, nous les utilisons dans plusieurs projets : elles sont des solutions efficaces pour conserver une grande partie de la logique métier côté web tout en profitant des fonctionnalités natives des applications mobiles.

En effet, ce type d'application a de nombreux avantages et permet de :

  • utiliser des composants natifs comme le caméra / vibreur ;
  • avoir une application disponible sur les stores à moindre coût ;
  • itérer progressivement sur l'application mobile ;
  • bénéficier des mises à jour automatiques du site web.

Si votre site web est déjà fonctionnel et responsive, il peut être intéressant de se tourner vers cette solution.

Qu'est-ce qu'une WebView ?

Une WebView est un composant qui permet d'afficher du contenu web dans une application mobile. Ici, nous allons l'exploiter dans le cadre d'une application React Native.

Et pourquoi pas une PWA ?

Les Progressive Web Apps (PWA) sont une solution pour rendre un site web accessible depuis un mobile. Cependant, elles ne permettent d'accéder qu'à une nombre limité de fonctionnalités natives, contrairement aux WebViews qui permettent d'accéder à toutes les fonctionnalités natives inhérentes à l'application mobile :

Tableau comparatif des fonctionnalités natives (non exhaustif)
Fonctionnalités nativesPWAWebView
Caméra
Géolocalisation
Notifications
Caméra (options avancées)
Accès aux contacts
Bluetooth, NFC
Enregistrement audio/vidéo
Empreinte digitale, reconnaissance faciale
Accéléromètre, gyroscope

Pour en savoir plus sur les PWA, nous vous invitons à consulter notre article sur le sujet : Les Progressive Web Apps.

Les pré-requis

Avant de se lancer dans la mise en place de notre WebView, il y a quelques prérequis à respecter.

  • Responsive Design du Site : Assurez-vous que votre site est responsive, c'est-à-dire qu'il s'adapte à toutes les tailles d'écrans.

  • Fonctionnalités Natives de la WebView : Votre WebView doit utiliser au moins une fonctionnalité native. Sinon, elle risque d'être refusée par les stores d'applications.

  • Application React Native : Mettez en place une application React Native si ce n'est pas déjà fait. Suivez le guide officiel pour cette installation.

Mise en place

Le composant WebView

Pour intégrer une WebView dans une application React Native, il suffit d'importer le composant WebView depuis react-native-webview et de l'utiliser dans notre application :

// Côté mobile
import React from 'react'
import { WebView } from 'react-native-webview'

const WebViewComponent = () => {
  return <WebView source={{ uri: 'https://www.premieroctet.com' }} />
}

Injection de script

Maintenant que notre WebView est fonctionnelle, nous pouvons lui injecter du code JavaScript. Il y a plusieurs manières de le faire :

  • la propriété injectedJavaScript permet d'injecter du code JavaScript au chargement de la WebView.
  • la propriété injectedJavaScriptBeforeContentLoaded permet d'injecter du code JavaScript avant le chargement du contenu de la WebView.
  • la méthode injectJavaScript permet d'injecter du code JavaScript à n'importe quel moment.

Ces propriétés et cette méthode sont très utiles pour communiquer entre le site web et l'application mobile. Elles prennent en paramètre le code JavaScript sous forme de chaîne de caractères, comme si vous écriviez ce code dans la console de votre navigateur.

La propriété injectedJavaScript est utile pour manipuler le DOM et ajouter des métadonnées à la page, pour la taille de l'écran par exemple :

// Côté mobile
const INJECTEDJAVASCRIPT = `const meta = document.createElement('meta'); meta.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0'); meta.setAttribute('name', 'viewport'); document.getElementsByTagName('head')[0].appendChild(meta); `

Vous avez la ref ?

Pour utiliser des méthodes sur la WebView, il faut lui attribuer une référence. Pour cela, on utilise la méthode useRef de React :

// Côté mobile
import React, { useRef } from 'react'
import { WebView } from 'react-native-webview'

const WebViewComponent = () => {
  const webviewRef = useRef<WebView>(null)

  return <WebView ref={webviewRef} source={{ uri: 'https://www.premieroctet.com' }} />
}

C'est sur cette référence que nous pourrons notamment appeler la méthode injectJavaScript :

// Côté mobile
webviewRef.current?.injectJavaScript(`myscript`)

Voilà pour les communications WebView ⇒ Web, mais dans certains cas, il est nécessaire de communiquer dans l'autre sens, pour déclencher une action native depuis le site web par exemple.

La méthode postMessage

Vous avez peut-être déjà rencontré la méthode window.postMessage en JavaScript. Elle permet de communiquer entre une page web et un iframe, ou, dans notre cas, entre une page web et une WebView.

Lorsqu'une WebView accède à une page web, elle charge l'interface window avec la propriété ReactNativeWebView. C'est à travers cette propriété que nous allons déterminer, côté application, si la connection a été initiée depuis une WebView, et si oui, nous pourrons envoyer des messages à la WebView :

// Côté application
if (window.ReactNativeWebView) {
  window.ReactNativeWebView.postMessage('Hello from the web')
}

Côté WebView, on va utiliser l'event listener onMessage pour écouter les messages envoyés par l'application :

// Côté mobile
const onMessage = (event: WebViewMessageEvent) => {
  console.log(event.nativeEvent.data)
}

<WebView source={{ uri: 'https://www.premieroctet.com' }} onMessage={onMessage} />

Si vous utilisez des objets, n'oubliez pas d'utiliser stringify avant de les envoyer et parse après réception.

Communications

Communication WebView ↔︎ Web

Exposer des méthodes

Nous venons de voir comment faire communiquer notre WebView avec notre application web, et comment injecter du code JavaScript depuis une WebView. Cependant, il est parfois nécessaire d'utiliser de la logique JavaScript de l'application depuis la WebView.

Pour ce faire, nous allons surcharger l'interface window de l'application avec des méthodes que nous pourrons utiliser depuis la WebView directement depuis l'injection de JavaScript.

// Côté application
useEffect(() => {
  window.myFunction = () => {
    console.log('Hello from the web')
  }
}, [])
// Côté mobile
webviewRef.current?.injectJavaScript(`window.myFunction()`)

Pour des raisons de sécurité, il est important de vérifier dans ces méthodes que l'utilisateur possède bien les droits nécessaires pour effectuer l'action demandée. Voire que l'application est bien utilisée dans une WebView.

Notez que la WebView injecte simplement le JavaScript, il est n'est pas possible de récupérer de la valeur de retour de ces méthodes. Une bonne pratique est donc de veiller à ce que ces méthodes ne retournent pas de valeur, cela évite aussi de retourner des informations sensibles.

Si vous souhaitez toutefois récupérer des informations depuis la WebView, vous devez utiliser la méthode postMessage que nous avons vu précédemment.

Le résultat

Voilà le résultat que nous obtenons avec une configuration pointant vers le site de Premier Octet sur iPhone 15 :

WebView

Couplage

Comme nous avons pu le voir, l'application et la WebView peuvent communiquer entre elles, cela les rend très dépendantes l'une de l'autre, même si elles sont déployées séparément.

Gardez à l'esprit que votre site Web doit être fonctionnel de manière autonome, sans dépendre de l'application mobile ou des fonctionnalités natives de celle-ci.

L'application web donne le ton, elle doit être disponible en premier, et la WebView doit être vue comme un complément à cette application.

Le TypeScript dans tout ça ?

Si vous utilisez TypeScript, vous pouvez, côté application, définir les nouvelles méthodes de l'interface window que vous souhaitez utiliser dans la WebView et la propriété ReactNativeWebView pour éviter les erreurs de types.

// Côté application (déclaration de types)
declare global {
  interface Window {
    myFunction: () => void
    ReactNativeWebView?: {
      postMessage: (message: string) => void
    }
  }
}

Cependant, côté WebView, l'injection de JavaScript se fait sous forme de chaîne de caractères, il n'est donc pas possible de vérifier le type du code injecté. Il est donc important de bien vérifier le code injecté avant de l'envoyer.

Pro-tips

Gestion de la mémoire sur iOS

Les WebViews sur iOS utilisent un processus séparé du reste de l'application mobile. Elles ne font donc pas partie du total de RAM de l'application, par conséquent elles peuvent être sorties de la mémoire si celle-ci est saturée quand l'application est en arrière plan. Cela cause une coupure de la WebView mais pas de l'application, il est donc important de bien gérer les rechargements de la WebView. La documentation de react-native-webview propose des solutions pour ces cas particuliers et assez compliqué à reproduire.

La documentation préconise donc d'utiliser la propriété onContentProcessDidTerminate pour détecter ces coupures et recharger la WebView.

// Côté mobile
<WebView
  source={{ uri: 'https://www.premieroctet.com' }}
  onContentProcessDidTerminate={() => {
    webviewRef.current?.reload()
  }}
/>

Bonus : Améliorer la navigation

Sur les navigateurs mobiles on a souvent l'habitude de pouvoir revenir en arrière en glissant de la gauche vers la droite pour iOS ou en appuyant sur le bouton retour pour Android. Il est possible de reproduire ce comportement dans une WebView, on vous montre comment.

Android

Sur Android on va utiliser le BackHandler de React Native pour intercepter le bouton retour et faire un retour en arrière dans la WebView.

// Côté mobile
import { BackHandler } from 'react-native'
import { WebView } from 'react-native-webview'

const WebViewComponent = () => {
  const webviewRef = useRef<WebView>(null)

  useEffect(() => {
    const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
      webviewRef.current?.goBack()
      return true
    })

    return () => backHandler.remove()
  }, [])

  return <WebView ref={webviewRef} source={{ uri: 'https://www.premieroctet.com' }} />
}

iOS

Sur iOS, on va utiliser la propriété allowsBackForwardNavigationGestures pour activer la navigation par glissement.

// Côté mobile
<WebView source={{ uri: 'https://www.premieroctet.com' }} allowsBackForwardNavigationGestures />

Expo

Si vous avez l'habitude de travailler avec Expo, sachez que react-native-webview est supporté par Expo, vous pouvez donc l'utiliser sans problème. C'est d'ailleur dans ce contexte que nous avons le plus souvent utilisé les WebViews chez Premier Octet.

Pour finir

Les WebViews sont des solutions efficaces pour intégrer un site web dans une application mobile. Elles ouvrent le champ des possibles en permettant de profiter des fonctionnalités natives des applications mobiles tout en conservant une grande partie de la logique métier côté web.

L’objectif principal des applications utilisant des WebViews ne doit pas être dépendant fonctionnalités natives. Le site Web doit pouvoir fonctionner de manière autonome. Dans le cas contraire, il est préférable de développer une application mobile native.

Il ne faut, toutefois, pas perdre à l'esprit que les WebViews sont soumises à des restrictions, notamment l'utilisation d'au moins une fonctionnalité native, et qu'elles ne sont pas adaptées à tous les cas d'utilisation.

Si vous souhaitez en savoir plus sur les WebViews, nous vous invitons à consulter la documentation officielle de react-native-webview.

Et si vous avez des questions ou des retours d'expérience à partager, n'hésitez pas à nous en faire part sur Twitter.

Enfin, si cette approche vous a intéressé et que vous avez un projet qui nécessite l'utilisation de WebViews, n'hésitez pas à nous contacter, nous serons ravis de vous accompagner dans sa mise en place et de répondre à vos questions.

Source

18 avenue Parmentier
75011 Paris
+33 1 43 57 39 11
hello@premieroctet.com

Suivez nos aventures

GitHub
Twitter
Flux RSS

Naviguez à vue