Configurer, implémenter et vérifier Android App Links

1. Avant de commencer

Lorsqu'un utilisateur suit un lien profond, c'est dans l'objectif d'accéder au contenu de son choix. Les liens profonds comportent toutes les fonctionnalités pour aider les utilisateurs à atteindre cet objectif. Android gère les types de liens suivants :

  • Liens profonds : URI de tout schéma qui redirigent directement les utilisateurs vers une partie spécifique d'une application.
  • Liens Web : liens profonds avec les schémas HTTP et HTTPS.
  • Android App Links : liens Web avec les schémas HTTP et HTTPS qui contiennent l'attribut android:autoVerify.

Pour en savoir plus sur les liens profonds, les liens Web et Android App Links, consultez la documentation Android, et le cours d'initiation sur YouTube et Medium.

Si vous disposez déjà de tous les détails techniques, consultez l'implémentation rapide de l'article de blog connexe pour configurer rapidement la fonctionnalité.

Objectif de l'atelier de programmation

Il explique les bonnes pratiques pour configurer, implémenter et vérifier une application avec Android App Links.

Android App Links présente l'avantage d'être sécurisé, ce qui signifie que seules les applications autorisées peuvent gérer vos liens. L'OS Android doit vérifier les liens d'un site Web dont vous êtes propriétaire pour les qualifier d'Android App Links. Ce processus est appelé association de sites Web.

Cet atelier de programmation s'adresse aux développeurs avec un site Web et une application Android. Android App Links améliore l'expérience utilisateur en permettant l'intégration parfaite de votre application et de votre site Web.

Conditions préalables

Points abordés

  • Apprendre les bonnes pratiques de création des URL pour Android App Links.
  • Configurez tous les types de liens profonds dans une application Android.
  • Connaître les caractères génériques des chemins (path, pathPrefix, pathPattern, pathAdvancePattern).
  • Découvrir la procédure de validation Android App Links avec importation du fichier Google Digital Asset Links (DAL), la procédure de validation manuelle Android App Links, ainsi que le tableau de bord "Deep links" (Liens profonds) de la Play Console.
  • Développer une application avec plusieurs restaurants dans divers endroits.

Rendu final de l'application Web des restaurants. Rendu final de l'application Android des restaurants.

Ce dont vous aurez besoin

  • Android Studio Dolphin (2021.3.1) ou version ultérieure.
  • Un domaine pour héberger les fichiers Google Digital Asset Link (DAL). (En option : lisez cet article de blog pour vous préparer en quelques minutes.)
  • En option : un compte de développeurs Google Play Console. Vous disposez ainsi d'une autre approche pour déboguer votre configuration Android App Links.

2. Configurer le code

Créer une application Compose vide

Pour lancer un projet Compose, procédez comme suit :

  1. Dans Android Studio, sélectionnez File > New > New Project (Fichier > Nouveau > Nouveau projet).

New Project (Nouveau > Nouveau projet)." class="l10n-absolute-url-src" l10n-attrs-original-order="alt,style,src,srcset,sizes,class" l10n-encrypted-style="2dV7hbnGKYSuLgQu/MlX0k8zz2uYoEmRhrQeP6/mnhY=" sizes="(max-width: 840px) 100vw, 856px" src="https://developer.android.com/static/codelabs/android-app-links-introduction/img/3d30cedf28504241.png" srcset="/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_36.png 36w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_48.png 48w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_72.png 72w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_96.png 96w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_480.png 480w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_720.png 720w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_856.png 856w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_960.png 960w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_1440.png 1440w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_1920.png 1920w,/static/codelabs/android-app-links-introduction/img/3d30cedf28504241_2880.png 2880w" style="width: 378.00px" />

  1. Sélectionnez Empty Compose Activity (Activité Compose vide) dans les modèles disponibles.

Fenêtre modale "New project" (Nouveau projet) d'Android Studio avec "Empty Compose Activity" (Activité Compose vide) sélectionné.

  1. Cliquez sur Next (Suivant), configurez votre projet et appelez-le Deep Links Basics. Choisissez une version de Minimum SDK (SDK minimal) ayant au moins le niveau d'API 21, ce qui correspond au niveau d'API minimum accepté par Compose.

Fenêtre modale des paramètres du nouveau projet Android Studio avec les valeurs de menu et les options suivantes : "Deep Links Basics" pour "Name" (Nom) ; "com.devrel.deeplinksbasics" pour "Package Name" (Nom du package) ; "Save location" 'Emplacement d'enregistrement) sur la valeur par défaut ; "Kotlin" pour "Language" (Langage) ; "API 21" pour "Minimum SDK" (SDK minimal).

  1. Cliquez sur Finish (Terminer) et attendez que le projet soit généré.
  2. Démarrez l'application. Vérifiez que l'application s'exécute. Un écran vide avec un message Hello Android! doit s'afficher.

Écran vide l'application Android dans Compose comportant le texte "Hello Android".

Solution de l'atelier de programmation

Le code nécessaire à la solution de cet atelier de programmation est disponible sur GitHub :

git clone https://github.com/android/deep-links

Vous pouvez également télécharger le dépôt sous forme de fichier ZIP :

Accédez d'abord au répertoire deep-links-introduction. L'application doit se trouver dans le répertoire solution. Nous vous recommandons de suivre l'atelier de programmation étape par étape, à votre rythme, et de consulter la solution si vous le jugez nécessaire. Au cours de cet atelier de programmation, vous découvrirez des extraits de code que vous devrez ajouter au projet.

3. Vérifier la conception d'URL basée sur les liens profonds

Conception de l'API RESTful

Les liens sont essentiels au développement Web. Leur conception a fait l'objet d'une multitude d'itérations à l'origine de différents standards. Il peut valoir la peine d'étudier et d'appliquer ces standards de conception qui visent à simplifier l'utilisation et la gestion des liens de développement Web.

L'un de ces standards, REST (Representational State Transfer) et une architecture généralement utilisée pour concevoir les API des services Web. L'initiative OpenAPI standardise les API REST. Vous pouvez aussi utiliser REST pour concevoir les URL de vos liens profonds.

Notez que vous ne créez pas un service Web. Cette section se penche uniquement sur la conception d'URL.

Conception des URL

Examinez d'abord les URL obtenues sur votre site Web et déterminez ce qu'elles représentent dans l'application Android :

  • /restaurants recense tous les restaurants que vous gérez.
  • /restaurants/:restaurantName affiche les détails d'un restaurant.
  • /restaurants/:restaurantName/orders affiche les commandes d'un restaurant.
  • /restaurants/:restaurantName/orders/:orderNumber affiche une commande donnée d'un restaurant.
  • /restaurants/:restaurantName/orders/latest affiche la dernière commande d'un restaurant.

Pourquoi la conception de l'URL est-elle importante ?

Android comporte des filtres d'intent qui gèrent les actions d'un autre composant d'application et permettent d'intercepter les URL. Lorsque vous définissez un filtre d'intent pour qu'il intercepte un URL, vous devez suivre une structure qui repose sur des préfixes de chemin et des caractères génériques simples. Voici un exemple de structuration à partir d'un URL du site Web de votre restaurant :

https://example.com/pawtato-3140-Skinner-Hollow-Road

Même si l'URL spécifie votre restaurant et son emplacement, le chemin peut poser problème pour définir un filtre d'intent permettant à Android d'intercepter l'URL. En effet, votre application est basée sur plusieurs URL de restaurant comme les suivantes :

https://example.com/rawrbucha-2064-carriage-lane

https://example.com/pizzabus-1447-davis-avenue

Lorsque vous définissez un filtre d'intent avec un chemin et un caractère générique pour intercepter ces URL, vous pouvez utiliser un élément comme https://example.com/* qui, globalement, fonctionne. Pourtant, le problème n'est pas véritablement résolu, puisqu'il existe d'autres chemins vers différentes sections de votre site Web, comme les suivantes :

Livraison : https://example.com/deliveries

Administration : https://example.com/admin

Même si vous ne souhaitez pas qu'Android intercepte ces URL (certains d'entre eux pouvant être internes), le filtre d'intent https://example.com/* va les intercepter, y compris ceux qui n'existent pas. Lorsqu'un utilisateur clique sur l'une de ces URL, il s'ouvre dans le navigateur (versions > à Android 12) ou une boîte de dialogue de sélection d'application s'affiche (versions < à Android 12). Ce comportement n'est pas intentionnel avec une telle conception.

Android propose désormais des préfixes de chemin qui résolvent le problème, mais impliquent de revoir la conception de l'URL de :

https://example.com/*

en :

https://example.com/restaurants/*

L'ajout d'une structure d'imbrication hiérarchique permet de définir clairement les filtres d'intent. Android intercepte ainsi l'URL qui convient.

Bonnes pratiques pour la conception d'URL

Voici quelques bonnes pratiques inspirées d'OpenAPI à appliquer aux liens profonds :

  • Cibler la conception d'URL en fonction des entités commerciales exposées. Par exemple, la conception pour l'e-commerce concerne les clients et les commandes. La conception pour le voyage concerne les billets et les vols. La conception pour votre application et votre site Web de restaurants va concerner les restaurants et les commandes.
  • La plupart des méthodes HTTP (GET, POST, DELETE, PUT) sont des verbes qui décrivent la requête en cours, même si l'utilisation de verbes dans les URL pour les points de terminaison peut être nébuleuse.
  • Pour décrire les collections, utilisez le pluriel, comme dans /restaurants/:restaurantName. Cela simplifie la lecture et la gestion de l'URL. Voici un exemple avec chaque méthode HTTP :

GET /restaurants/pawtato

POST /restaurants

DELETE /restaurants

PUT /restaurants/pawtato

Chaque URL est plus facile à lire et à interpréter. Notez que cet atelier de programmation ne traite pas de la conception des API des services Web ni du fonctionnement de chaque méthode.

  • Utilisez l'imbrication logique pour grouper les URL qui contiennent des informations associées. Par exemple, l'URL d'un des restaurants peut avoir des commandes en cours de traitement :

/restaurants/1/orders

4. Vérifier l'élément de données

Le fichier AndroidManifest.xml est un élément essentiel d'Android. Il décrit les informations de l'application pour les outils de développement d'Android, l'OS Android et Google Play.

Pour les liens profonds, vous devez définir un filtre d'intent avec trois tags principaux : <action>, <category> et <data>. Cette section se concentre sur le tag <data>.

Un élément <data> indique à l'OS Android la structure URL d'un lien lorsqu'un utilisateur clique dessus. Le format et la structure URL que vous pouvez appliquer aux filtres d'intent sont les suivants :

<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>|<pathAdvancedPattern>|<pathSuffix>]

Android lit, analyse et fusionne l'ensemble des éléments <data> d'un filtre d'intent afin de prendre en compte toutes les variantes des attributs. Exemple :

AndroidManifest.xml

<intent-filter>
  ...
  <data android:scheme="http" />
  <data android:scheme="https" />
  <data android:host="example.com" />
  <data android:path="/restaurants" />
  <data android:pathPrefix="/restaurants/orders" />
</intent-filter>

Android va intercepter les URL suivants :

  • http://example.com/restaurants
  • https://example.com/restaurants
  • http://example.com/restaurants/orders/*
  • https://example.com/restaurants/orders/*

Attributs de chemin

path (avec API 1)

Cet attribut spécifie un chemin complet commençant par / qui est mis en correspondance avec le chemin complet de l'intent. Par exemple, android:path="/restaurants/pawtato" correspond uniquement au chemin de site Web /restaurants/pawtato. De ce fait, l'URL /restaurant/pawtato n'est pas mis en correspondance en raison du s manquant.

pathPrefix (avec API 1)

Cet attribut spécifie un chemin partiel mis en correspondance uniquement avec la partie initiale du chemin de l'intent. Par exemple :

android:pathPrefix="/restaurants" correspond aux chemins de restaurant suivants : /restaurants/pawtato, /restaurants/pizzabus, etc.

pathSuffix (avec API 31)

Cet attribut spécifie un chemin mis en correspondance exacte avec la partie finale du chemin de l'intent. Par exemple :

android:pathSuffix="tato" correspond à tous les chemins de restaurant qui se terminent par tato, comme /restaurants/pawtato et /restaurants/corgtato.

pathPattern (avec API 1)

Cet attribut spécifie un chemin complet mis en correspondance avec un chemin complet avec caractères génériques de l'intent :

  • Un astérisque (*) correspond à une séquence de zéro à plusieurs occurrences du caractère qui précède.
  • Un point suivi d'un astérisque (.*) représente une séquence de zéro à plusieurs caractères.

Exemples :

  • /restaurants/piz*abus : ce schéma correspond au restaurant "Pizzabus", mais il correspond aussi aux restaurants dont le nom comporte zéro à plusieurs caractères z, comme /restaurants/pizzabus, /restaurants/pizzzabus et /restaurants/pizabus.
  • /restaurants/.* : ce schéma correspond à tous les noms de restaurant avec le chemin /restaurants, comme /restaurants/pizzabus et /restaurants/pawtato, ainsi qu'à ceux que l'application ne connaît pas, comme /restaurants/wateriehall.

pathAdvancePattern (avec API 31)

Cet attribut spécifie un chemin complet mis en correspondance avec un chemin complet avec un schéma de type "expression régulière" :

  • Un point (.) correspond à n'importe quel caractère.
  • Un ensemble entre crochets ([...]) correspond à une plage de caractères. Il est également compatible avec le modificateur not (^).
  • Un astérisque (*) correspond à zéro à plusieurs occurrences du caractère qui précède.
  • Un plus (+) correspond à une ou plusieurs occurrences du caractère qui précède.
  • Les accolades ({...}) représentent le nombre de correspondances potentielles d'un schéma.

Cet attribut peut être considéré comme une extension de pathPattern. Il offre une mise en correspondance plus flexible des URL, par exemple :

  • /restaurants/[a-zA-Z]*/orders/[0-9]{3} correspond à n'importe quelle commande de restaurant comportant jusqu'à trois chiffres.
  • /restaurants/[a-zA-Z]*/orders/latest correspond à la dernière commande de n'importe quel restaurant l'application.

5. Créer des liens profonds et des liens Web

Les liens profonds avec schémas personnalisés sont les plus génériques. Leur implémentation est la plus facile, mais présente certains inconvénients. Les sites Web ne peuvent pas ouvrir ce type de liens. Toute application qui spécifie être compatible avec un schéma dans son fichier peut ouvrir le lien correspondant.

Vous pouvez utiliser n'importe quel schéma avec l'élément <data>. Par exemple, l'atelier de programmation utilise l'URL food://restaurants/keybabs.

  1. Dans Android Studio, ajoutez le filtre d'intent suivant dans le fichier manifeste :

AndroidManifest.xml

<activity ... >
  <intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="food"/>
    <data android:path="/restaurants/keybabs"/>
  </intent-filter>
</activity>
  1. Pour vérifier que votre application peut ouvrir les liens avec schémas personnalisés, réalisez une capture de l'écran d'accueil et ajoutez les éléments suivants à l'activité principale :

MainActivity.kt

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Receive the intent action and data
        val action: String? = intent?.action;
        val data: Uri? = intent?.data;

        setContent {
            DeepLinksBasicsTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    // Add a Column to print a message per line
                    Column {
                        // Print it on the home screen
                        Greeting("Android")
                        Text(text = "Action: $action")
                        Text(text = "Data: $data")
                    }
                }
            }
        }
    }
}
  1. Pour tester la réception de l'intent, utilisez l'Android Debug Bridge (adb) avec la commande suivante :
adb shell am start -W -a android.intent.action.VIEW -d "food://restaurants/keybabs"

La commande démarre un intent avec l'action VIEW (AFFICHER) et utilise l'URL fournie comme donnée. Lorsque vous exécutez cette commande, l'application lance et reçoit l'intent. Remarquez les modifications qui apparaissent dans les sections de texte de l'écran principal. La première affiche le message Hello Android!, la deuxième affiche l'action pour laquelle l'intent a été appelé, et la troisième affiche l'URL pour lequel l'intent a été appelé.

Dans l'image suivante, notez que la commande adb mentionnée s'est exécutée dans la section inférieure d'Android Studio. À droite, l'application affiche les informations de l'intent dans l'écran d'accueil, ce qui signifie qu'il a bien été reçu. Le plein écran Android Studio comporte les onglets ouverts suivants : "Code view" (Vue Code), "Emulator" (Émulateur) et "Terminal" (Terminal). "Code view" (Vue Code) affiche le fichier MainActivity.kt de base. "Emulator" (Émulateur) affiche le champ de texte du lien profond, confirmant qu'il a bien été reçu. "Terminal" (Terminal) affiche la commande adb dont nous venons de parler dans l'atelier de programmation.

Les liens Web sont des liens profonds qui utilisent l'http et l'https plutôt que les schémas personnalisés.

Pour implémenter un lien Web, utilisez le chemin /restaurants/keybabs/order/latest.html, qui représente la dernière commande reçue par le restaurant.

  1. Adaptez le fichier manifeste en utilisant le filtre d'intent existant.

AndroidManifest.xml

<intent-filter>
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:scheme="food"/>
  <data android:path="/restaurants/keybabs"/>

  <!-- Web link configuration -->
  <data android:scheme="http"/>
  <data android:scheme="https"/>
  <data android:host="sabs-deeplinks-test.web.app"/>
  <data android:path="/restaurants/keybabs/order/latest.html"/>
</intent-filter>

Les chemins étant partagés (/restaurants/keybabs), une bonne pratique consiste à les conserver dans le même filtre d'intent. Cela permet de simplifier l'implémentation et la lecture du fichier manifeste.

  1. Avant de tester le lien Web, redémarrez l'application pour appliquer les modifications.
  2. Utilisez la même commande adb pour lancer l'intent, mais dans ce cas, mettez à jour l'URL.
adb shell am start -W -a android.intent.action.VIEW -d "https://sabs-deeplinks-test.web.app/restaurants/keybabs/orders/latest.html"

Dans la capture d'écran, notez que l'intent a été reçu et que le navigateur Web est ouvert pour afficher le site Web (fonctionnalité des versions à partir d'Android 12). Vue complète d'Android Studio avec les onglets suivants : "Code view" (Vue Code) affiche le fichier AndroidManifest.xml représentant le filtre d'intent en question. "Emulator" (Émulateur) affiche la page Web ouverte grâce aux liens Web pointant vers l'application Web des restaurants. "Terminal" (Terminal) affiche la commande adb pour les liens Web.

6. Configurer Android App Links

Ces liens offrent une expérience utilisateur parfaitement fluide. Ainsi, lorsque l'utilisateur clique sur un lien, il est assuré d'accéder à l'application sans qu'une boîte de dialogue de sélection d'application ne s'ouvre. Implémenté avec Android 6.0, Android App Links propose des liens profonds très spécifiques. Ces liens Web utilisent le schéma http/https et l'attribut android:autoVerify, qui font de l'application le gestionnaire par défaut de tous les liens correspondants. Deux étapes principales permettent d'implémenter Android App Links :

  1. Mettre à jour le fichier manifeste avec le filtre d'intent qui convient.
  2. Ajouter l'association de sites Web à des fins de validation.

Mettre à jour le fichier manifeste

  1. Pour accepter Android App Links, dans le fichier manifeste, remplacez l'ancienne configuration par ce qui suit :

AndroidManifest.xml

<!-- Replace deep link and web link configuration with this -->
<!-- Please update the host with your own domain -->
<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:scheme="https"/>
  <data android:host="example.com"/>
  <data android:pathPrefix="/restaurants"/>
</intent-filter>

Ce filtre d'intent ajoute l'attribut android:autoVerify et le définit sur "True" (Vrai). Cela permet à l'OS Android de vérifier le domaine lorsque l'application est installée et à chaque nouvelle mise à jour.

Association de sites Web

Pour vérifier un élément Android App Links, créez une association entre l'application et le site Web. Un fichier JSON Google Digital Asset Links (DAL) doit être publié sur le site Web pour que la validation soit effective.

Google DAL est un protocole et une API qui définissent les instructions vérifiables concernant les autres applications et sites Web. Dans cet atelier de programmation, vous allez créer une instruction concernant l'application Android dans le fichier assetlinks.json. Par exemple :

assetlinks.json

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.devrel.deeplinksbasics",
    "sha256_cert_fingerprints":
   ["B0:4E:29:05:4E:AB:44:C6:9A:CB:D5:89:A3:A8:1C:FF:09:6B:45:00:C5:FD:D1:3E:3E:12:C5:F3:FB:BD:BA:D3"]
  }
}]

Même si l'exemple n'affiche qu'un seul élément, ce fichier peut conserver toute une liste d'instructions. Chaque instruction doit comporter les champs suivants :

  • Relation : décrit une ou plusieurs relations déclarées à propos de la cible
  • Target (Cible) : désigne le composant visé par l'instruction. Il peut s'agir de l'une des deux cibles disponibles, web ou android_app

La propriété target de l'instruction Android comporte les champs suivants :

  • namespace : android_app pour toutes les applications Android
  • package_name : nom de package complet (com.devrel.deeplinksbasics)
  • sha256_cert_fingerprints : empreinte du certificat de l'application. Vous allez apprendre à générer ce certificat dans la section suivante

Empreinte du certificat

Plusieurs méthodes permettent d'obtenir l'empreinte du certificat. Cet atelier de programmation emploie deux méthodes. La première pour créer la release de débogage de l'application et la seconde pour publier l'app sur le Google Play Store.

Configuration du débogage

La première fois qu'Android Studio exécute votre projet, il signe votre application avec un certificat de débogage. Ce certificat se trouve dans $HOME/.android/debug.keystore. Vous pouvez utiliser une commande Gradle pour obtenir l'empreinte du certificat SHA-256. Pour cela, procédez comme suit :

  1. Appuyez deux fois sur Control pour afficher le menu Run anything (Tout exécuter). S'il n'apparaît pas, accédez au menu Gradle de la barre latérale de droite et cliquez sur l'icône Gradle.

Onglet du menu Gradle d'Android Studio avec icône Gradle sélectionnée.

  1. Saisissez gradle signingReport, puis appuyez sur Enter. La commande s'exécute dans la console et affiche des informations sur l'empreinte pour la variante de l'application de débogage.

La fenêtre "Terminal" (Terminal) affiche les résultats du rapport de signature Gradle.

  1. Pour terminer l'association de sites Web, copiez l'empreinte du certificat SHA-256, mettez à jour le fichier JSON et importez-le sur votre site Web, dans https://<domain>/.well-know/assetlinks.json. Cet article de blog sur Android App Links vous explique comment configurer cette fonctionnalité.
  2. Si l'application s'exécute toujours, appuyez sur Stop (Arrêter) pour l'arrêter.
  3. Pour relancer la procédure de validation, supprimez l'application du simulateur. Dans le simulateur, cliquez de manière prolongée sur l'icône de l'application Deep Links Basics et sélectionnez App Info (Infos sur l'appli). Cliquez sur Uninstall (Désinstaller), puis sur Confirm (Confirmer) dans la fenêtre modale. Exécutez ensuite l'application afin qu'Android Studio puisse vérifier l'association.

f112e0d252c5eb48.gif

  1. Assurez-vous d'avoir sélectionné la configuration d'exécution App (Application). Dans le cas contraire, le rapport de signature Gradle s'exécute à nouveau. Menu des configurations d'exécution Android Studio avec la configuration "App" (Application) sélectionnée.
  2. Redémarrez l'application et lancez l'intent avec l'URL Android App Links :
adb shell am start -W -a android.intent.action.VIEW -d "https://sabs-deeplinks-test.web.app/restaurants/"
  1. Notez que l'application se lance et que l'intent apparaît sur l'écran d'accueil.

Écran d'accueil d'Android Emulator dont les champs de texte indiquent qu'Android App Links a bien été implémenté.

Félicitations, vous avez créé votre premier élément Android App Links !

Configuration de release

Pour importer votre application avec Android App Links dans le Play Store, vous devez utiliser un build avec une empreinte de certificat appropriée. Pour le générer et l'importer, procédez comme suit :

  1. Dans le menu principal d'Android Studio, cliquez sur Build > Generate Signed Bundle/APK (Compiler > Générer un app Bundle/APK signé).
  2. Dans la boîte de dialogue suivante, sélectionnez Android App Bundle pour "Play App Signing" (Signature d'application Play) ou APK si vous le déployez directement sur un appareil.
  3. Dans la boîte de dialogue suivante, cliquez sur Create new (Créer) sous Key Store Path (Chemin du keystore). Une nouvelle fenêtre s'ouvre.
  4. Sélectionnez un chemin pour votre keystore et appelez-le basics-keystore.jks.
  5. Créez et confirmez le mot de passe du keystore.
  6. Conservez l'alias par défaut de la clé.
  7. Vérifiez que le mot de passe et la confirmation sont identiques à ceux du keystore. Ils doivent correspondre.
  8. Renseignez les informations sur le certificat et cliquez sur OK.

Fenêtre modale "New Key Store" (Nouveau keystore) avec les valeurs et les éléments de menu suivants : répertoire sélectionné dans "Key Store Path" (Chemin du keystore), mot de passe défini dans "Password" (Mot de passe) et "confirm" (Confirmation), "key0" dans "Alias", répétition du mot de passe dans "Password" (Mot de passe) et "confirm" (Confirmation), valeur par défaut dans "Validity" (Validité), "Sabs sabs" dans "First and Last Name" (Nom et prénom), "Android" dans "Organizational Unit" (Unité organisationnelle), "MyOrg" dans "Organization" (Organisation), "MyCity" dans "City or Locality" (Ville ou localité), "MyState" dans "State or Province" (Région ou département), et "US" pour "Country Code" (Code pays).

  1. Assurez-vous d'avoir coché l'option d'exportation des clés chiffrées pour "Play App Signing" (Signature d'application Play) et cliquez sur Next (Suivant).

Fenêtre modale "Generate Sign Bundle or APK" (Générer un app Bundle/APK signé) avec les valeurs et les éléments de menu suivants : valeur par défaut dans "Module", chemin généré dans "Key Store Path" (Chemin du keystore), mot de passe précédemment généré dans "Key store password" (Mot de passe du keystore), "key0" dans "Key alias" (Alias de la clé), mot de passe précédemment généré dans "Key password" (Mot de passe de la clé), case cochée pour "Export encrypted key for enrolling published apps in Google Play App Signing"(Exporter la clé chiffrée pour enregistrer les applications publiées dans la Signature d'application Play) et valeur par défaut dans "Encrypted key export path" (Chemin d'exportation de la clé chiffrée).

  1. Dans cette boîte de dialogue, sélectionnez la variante de build et cliquez sur Finish (Terminer). Vous pouvez maintenant importer vos applications dans le Google Play Store et utiliser la signature d'application Play.

Signature d'application Play

Avec la signature d'application Play, Google vous permet de gérer et de protéger la clé de signature de vos applications. Il vous suffit d'importer l'app bundle signé que vous avez obtenu à l'étape précédente.

Pour récupérer l'empreinte du certificat du fichier assetlinks.json et disposer d'Android App Links dans le build de variante de version, procédez comme suit :

  1. Dans la Google Play Console, cliquez sur Create app (Créer une application).
  2. Pour le nom de l'application, saisissez Deep Links Basics.
  3. Sélectionnez App (Application) et Free (Sans frais) pour les deux options suivantes. Menu "Create app" (Créer une application) avec les valeurs suivantes à jour : "Deep Links Basics" dans "App name" (Nom de l'application), "App" sélectionné pour "App or game" (Application ou jeu), "Free" sélectionné pour "free or paid" (Application sans frais ou payante), et case cochée pour accepter les deux déclarations.
  4. Acceptez les Declarations (Déclarations) et cliquez sur Create app (Créer l'application).
  5. Pour importer l'app bundle et pouvoir tester Android App Links, sélectionnez Testing > Internal testing (Tests > Tests internes).
  6. Cliquez sur Create new release (Créer une version).

Section "Internal testing" (Tests internes) de la Play Console qui affiche le bouton "Create new release" (Créer une version).

  1. Dans la section suivante, cliquez sur Upload (Importer), puis sélectionnez l'app bundle généré lors la dernière section. Vous trouverez le fichier app-release.aab sous Deep Links Basics > App > Release (Deep Links Basics > Application > Version). Cliquez sur Open (Ouvrir) et attendez que l'app bundle soit importé.
  2. Une fois importé, ne modifiez pas les autres champs pour le moment. Cliquez sur Save (Enregistrer).

Section "Internal testing release" (Version de test interne) de la Play Console avec l'application Deep Links Basics importée. Les valeurs par défaut sont renseignées.

  1. Pour préparer la section suivante, cliquez sur Review release (Examiner la version). Dans l'écran suivant, cliquez sur Start rollout to Internal testing (Lancer le déploiement du test interne). Ignorer les mises en garde (cet atelier de programmation ne traite pas de la publication sur le Play Store).
  2. Cliquez sur Rollout (Déployer) dans la fenêtre modale.
  3. Pour récupérer l'empreinte du certificat SHA-256 créée par la signature d'application Play, accédez à l'onglet Deep links (Liens profonds) du menu de gauche et observez le tableau de bord "Deep links" (Liens profonds).

Tableau de bord "Deep links" (Liens profonds) de la Play Console, qui affiche toutes les informations sur les liens profonds récemment importés.

  1. Dans la section Domains (Domaines), cliquez sur le domaine du site Web. Notez que la Google Play Console indique que vous n'avez pas validé le domaine associé à votre application (association de sites Web).
  2. Dans la section Fix Domain Issues (Résoudre les problèmes de domaine), cliquez sur la flèche Show More (Plus).
  3. Dans cet écran, la Google Play Console vous indique comment mettre à jour le fichier assetlinks.json avec l'empreinte du certificat. Copiez l'extrait de code et mettez à jour le fichier assetlinks.json.

Section de vérification des domaines du tableau de bord "Deep links" (Liens profonds) qui indique comment mettre à jour le domaine avec l'empreinte du certificat qui convient.

  1. Une fois le fichier assetlinks.json à jour, cliquez sur Recheck verification (Recontrôler la vérification). Si la vérification ne s'est pas encore lancée, attendez cinq minutes que le service de vérification détecte les modifications.
  2. Si vous actualisez le tableau de bord Deep links (Liens profonds), vous constatez que les erreurs de vérification ont disparu.

Vérification de l'application importée

Vous savez déjà vérifier une application qui se trouve dans le simulateur. Vous devez maintenant vérifier l'application importée dans le Play Store.

Pour installer l'application dans l'émulateur et s'assurer qu'Android App Links a bien été vérifié, procédez comme suit :

  1. Dans la barre latérale de gauche, cliquez sur Releases Overview (Vue d'ensemble des releases) et sélectionnez la release que vous venez d'importer. il doit s'agir de la release 1 (1.0).
  2. Cliquez sur Release details (Détails de la release) (flèche droite bleue) pour accéder aux détails de la release.
  3. Cliquez de nouveau sur la flèche droite bleue pour obtenir les informations sur l'app bundle.
  4. Dans cette fenêtre modale, sélectionnez l'onglet Downloads (Téléchargements), puis cliquez sur Download (Télécharger) pour le composant Signed, universal APK (APK standard signé).
  5. Avant d'installer l'app bundle dans le simulateur, supprimez la précédente application installée par Android Studio.
  6. Dans le simulateur, cliquez de manière prolongée sur l'icône de l'application Deep Links Basics et sélectionnez App Info (Infos sur l'appli). Cliquez sur Uninstall (Désinstaller), puis sur Confirm (Confirmer) dans la fenêtre modale.

f112e0d252c5eb48.gif

  1. Pour installer l'app bundle téléchargé, glissez-déposez le fichier 1.apk téléchargé dans l'écran du simulateur et attendez qu'il soit installé.

8967dac36ae545ee.gif

  1. Pour réaliser le test de validation, ouvrez Terminal dans Android Studio et exécutez la procédure de validation à l'aide des deux commandes suivantes :
adb shell pm verify-app-links --re-verify com.devrel.deeplinksbasics
adb shell pm get-app-links com.devrel.deeplinksbasics
  1. À l'issue de la commande get-app-links, un message verified doit s'afficher dans la console. Si vous obtenez un message legacy_failure, vérifiez que l'empreinte du certificat correspond à celle que vous avez importée pour le site Web. Si les empreintes correspondent et que le message de vérification n'apparaît toujours pas, essayez de répéter les étapes 6, 7 et 8.

Sortie sur la console.

7. Implémenter Android App Links

Maintenant que tout est configuré, vous pouvez implémenter l'implication.

Utilisez Jetpack Compose pour l'implémentation. Pour en savoir plus sur Jetpack Compose, consultez Build better apps faster with Jetpack Compose (Créez de meilleures applications plus rapidement avec Jetpack Compose).

Dépendances de code

Pour intégrer et mettre à jour les quelques dépendances dont vous avez besoin pour ce projet, procédez comme suit :

  • Ajoutez ce qui suit aux fichiers Gradle Module et Project suivants :

build.gradle (Projet)

buildscript {
  ...
  dependencies {
    classpath "com.google.dagger:hilt-android-gradle-plugin:2.43"
  }
}

build.gradle (Module)

plugins {
  ...
  id 'kotlin-kapt'
  id 'dagger.hilt.android.plugin'
}
...
dependencies {
  ...
  implementation 'androidx.compose.material:material:1.2.1'
  ...
  implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
  implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
  implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
  implementation "com.google.dagger:hilt-android:2.43"
  kapt "com.google.dagger:hilt-compiler:2.43"
}

Le fichier ZIP Project comporte un répertoire avec 10 images libres de droits que vous pouvez utiliser pour chaque restaurant. Vous pouvez les utiliser librement ou intégrer vos propres images.

Pour ajouter le point d'entrée principal d'HiltAndroidApp, procédez comme suit :

  • Créez une classe ou un fichier appelé DeepLinksBasicsApplication.kt, puis mettez à jour le nom de l'application dans le fichier manifeste.

DeepLinksBasicsApplication.kt

package com.devrel.deeplinksbasics

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class DeepLinksBasicsApplication : Application() {}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- Update name property -->
    <application
        android:name=".DeepLinksBasicsApplication"
        ...

Données

Vous devez créer une couche de données pour les restaurants avec une classe Restaurant, un dépôt et une source de données locale. Vous devez créer un package data qui doit contenir tous ces éléments. Pour ce faire, procédez comme suit :

  1. Dans le fichier Restaurant.kt, créez une classe Restaurant avec l'extrait de code suivant :

Restaurant.kt

package com.devrel.deeplinksbasics.data

import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable

@Immutable
data class Restaurant(
    val id: Int = -1,
    val name: String = "",
    val address: String = "",
    val type: String = "",
    val website: String = "",
    @DrawableRes val drawable: Int = -1
)
  1. Dans le fichier RestaurantLocalDataSource.kt, ajoutez plusieurs restaurants à la classe de sources de données. N'oubliez pas de mettre à jour les données associées à votre domaine. Reportez-vous à l'extrait de code suivant :

RestaurantLocalDataSource.kt

package com.devrel.deeplinksbasics.data

import com.devrel.deeplinksbasics.R
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class RestaurantLocalDataSource @Inject constructor() {
    val restaurantList = listOf(
        Restaurant(
            id = 1,
            name = "Pawtato",
            address = "3140 Skinner Hollow Road, Medford, Oregon 97501",
            type = "Potato and gnochi",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/pawtato/",
            drawable = R.drawable.restaurant1,
        ),
        Restaurant(
            id = 2,
            name = "Rawrbucha",
            address = "2064 Carriage Lane, Mansfield, Ohio 44907",
            type = "Kombucha",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/rawrbucha/",
            drawable = R.drawable.restaurant2,
        ),
        Restaurant(
            id = 3,
            name = "Pizzabus",
            address = "1447 Davis Avenue, Petaluma, California 94952",
            type = "Pizza",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/pizzabus/",
            drawable = R.drawable.restaurant3,
        ),
        Restaurant(
            id = 4,
            name = "Keybabs",
            address = "3708 Pinnickinnick Street, Perth Amboy, New Jersey 08861",
            type = "Kebabs",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/keybabs/",
            drawable = R.drawable.restaurant4,
        ),
        Restaurant(
            id = 5,
            name = "BBQ",
            address = "998 Newton Street, Saint Cloud, Minnesota 56301",
            type = "BBQ",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/bbq/",
            drawable = R.drawable.restaurant5,
        ),
        Restaurant(
            id = 6,
            name = "Salades",
            address = "4522 Rockford Mountain Lane, Oshkosh, Wisconsin 54901",
            type = "salads",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/salades/",
            drawable = R.drawable.restaurant6,
        ),
        Restaurant(
            id = 7,
            name = "Gyros and moar",
            address = "1993 Bird Spring Lane, Houston, Texas 77077",
            type = "Gyro",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/gyrosAndMoar/",
            drawable = R.drawable.restaurant7,
        ),
        Restaurant(
            id = 8,
            name = "Peruvian ceviche",
            address = "2125 Deer Ridge Drive, Newark, New Jersey 07102",
            type = "seafood",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/peruvianCeviche/",
            drawable = R.drawable.restaurant8,
        ),
        Restaurant(
            id = 9,
            name = "Vegan burgers",
            address = "594 Warner Street, Casper, Wyoming 82601",
            type = "vegan",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/veganBurgers/",
            drawable = R.drawable.restaurant9,
        ),
        Restaurant(
            id = 10,
            name = "Taquitos",
            address = "1654 Hart Country Lane, Blue Ridge, Georgia 30513",
            type = "mexican",
            // TODO: Update with your own domain
            website = "https://your.own.domain/restaurants/taquitos/",
            drawable = R.drawable.restaurant10,
        ),
    )
}
  1. Pensez à importer les images dans votre projet.
  2. Puis, dans le fichier RestaurantRepository.kt, ajoutez le dépôt Restaurant avec une fonction permettant d'obtenir un restaurant grâce à son nom, comme dans l'extrait de code suivant :

RestaurantRepository.kt

package com.devrel.deeplinksbasics.data

import javax.inject.Inject

class RestaurantRepository @Inject constructor(
    private val restaurantLocalDataSource: RestaurantLocalDataSource
){
    val restaurants: List<Restaurant> = restaurantLocalDataSource.restaurantList

    // Method to obtain a restaurant object by its name
    fun getRestaurantByName(name: String): Restaurant ? {
        return restaurantLocalDataSource.restaurantList.find {
            val processedName = it.name.filterNot { it.isWhitespace() }.lowercase()
            val nameToTest = name.filterNot { it.isWhitespace() }.lowercase()
            nameToTest == processedName
        }
    }
}

ViewModel

Pour pouvoir sélectionner un restaurant avec l'application et Android App Links, vous devez créer un ViewModel qui modifie la valeur du restaurant sélectionné. Procédez comme suit :

  • Dans le fichier RestaurantViewModel.kt, ajoutez l'extrait de code suivant :

RestaurantViewModel.kt

package com.devrel.deeplinksbasics.ui.restaurant

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.devrel.deeplinksbasics.data.Restaurant
import com.devrel.deeplinksbasics.data.RestaurantRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class RestaurantViewModel @Inject constructor(
    private val restaurantRepository: RestaurantRepository,
) : ViewModel() {
    // restaurants and selected restaurant could be used as one UIState stream
    // which will scale better when exposing more data.
    // Since there are only these two, it is okay to expose them as separate streams
    val restaurants: List<Restaurant> = restaurantRepository.restaurants

    private val _selectedRestaurant = MutableStateFlow<Restaurant?>(value = null)
    val selectedRestaurant: StateFlow<Restaurant?>
        get() = _selectedRestaurant

    // Method to update the current restaurant selection
    fun updateSelectedRestaurantByName(name: String) {
        viewModelScope.launch {
            val selectedRestaurant: Restaurant? = restaurantRepository.getRestaurantByName(name)
            if (selectedRestaurant != null) {
                _selectedRestaurant.value = selectedRestaurant
            }
        }
    }
}

Compose

Maintenant que vous disposez de la logique du ViewModel et des couches de données, vous pouvez ajouter une couche d'interface utilisateur (UI). La bibliothèque Jetpack Compose permet cela en quelques étapes. Pour cette application, vous souhaitez afficher vos restaurants sous la forme d'une grille de cartes. L'utilisateur peut cliquer sur chaque carte pour accéder aux informations du restaurant. Vous devez utiliser trois fonctions composables principales et un composant de navigation qui amène au restaurant en question.

Émulateur Android affichant l'application des restaurants terminée.

Pour ajouter une couche d'UI, procédez comme suit :

  1. Commencez par la fonction composable qui affiche les informations de chaque restaurant. Dans le fichier RestaurantCardDetails.kt, ajoutez l'extrait de code suivant :

RestaurantCardDetails.kt

package com.devrel.deeplinksbasics.ui

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.devrel.deeplinksbasics.data.Restaurant

@Composable
fun RestaurantCardDetails (
    restaurant: Restaurant,
    onBack: () -> Unit,
) {
    BackHandler() {
       onBack()
    }
    Scaffold(
        topBar = {
            TopAppBar(
                backgroundColor = Color.Transparent,
                elevation = 0.dp,
            ) {
                Row(
                    horizontalArrangement = Arrangement.Start,
                    modifier = Modifier.padding(start = 8.dp)
                ) {
                    Icon(
                        imageVector = Icons.Default.ArrowBack,
                        contentDescription = "Arrow Back",
                       modifier = Modifier.clickable {
                            onBack()
                        }
                    )
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(text = restaurant.name)
                }
            }
        }
    ) { paddingValues ->
        Card(
            modifier = Modifier
                .padding(paddingValues)
                .fillMaxWidth(),
            elevation = 2.dp,
            shape = RoundedCornerShape(corner = CornerSize(8.dp))
        ) {
            Column(
                modifier = Modifier
                    .padding(16.dp)
                    .fillMaxWidth()
            ) {
                Text(text = restaurant.name, style = MaterialTheme.typography.h6)
                Text(text = restaurant.type, style = MaterialTheme.typography.caption)
                Text(text = restaurant.address, style = MaterialTheme.typography.caption)
                SelectionContainer {
                    Text(text = restaurant.website, style = MaterialTheme.typography.caption)
                }
                Image(painter = painterResource(id = restaurant.drawable), contentDescription = "${restaurant.name}")
            }
        }
    }
}
  1. Puis, implémentez la cellule de grille et la grille. Dans le fichier RastaurantCell.kt, ajoutez l'extrait de code suivant :

RestaurantCell.kt

package com.devrel.deeplinksbasics.ui

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.devrel.deeplinksbasics.data.Restaurant

@Composable
fun RestaurantCell(
    restaurant: Restaurant
){
    Card(
        modifier = Modifier
            .padding(horizontal = 8.dp, vertical = 8.dp)
            .fillMaxWidth(),
        elevation = 2.dp,
        shape = RoundedCornerShape(corner = CornerSize(8.dp))
    ) {
        Column(
            modifier = Modifier
                .padding(16.dp)
                .fillMaxWidth()
        ) {
            Text(text = restaurant.name, style = MaterialTheme.typography.h6)
            Text(text = restaurant.address, style = MaterialTheme.typography.caption)
            Image(painter = painterResource(id = restaurant.drawable), contentDescription = "${restaurant.name}")
        }
    }
}
  1. Dans le fichier RestaurantGrid.kt, ajoutez l'extrait de code suivant :

RestaurantGrid.kt

package com.devrel.deeplinksbasics.ui

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.devrel.deeplinksbasics.data.Restaurant

@Composable
fun RestaurantGrid(
    restaurants: List<Restaurant>,
    onRestaurantSelected: (String) -> Unit,
    navigateToRestaurant: (String) -> Unit,
) {
    Scaffold(topBar = {
        TopAppBar(
            backgroundColor = Color.Transparent,
            elevation = 0.dp,
        ) {
            Text(text = "Restaurants", fontWeight = FontWeight.Bold)
        }
    }) { paddingValues ->
        LazyVerticalGrid(
            columns = GridCells.Adaptive(minSize = 200.dp),
            modifier = Modifier.padding(paddingValues)
        ) {
            items(items = restaurants) { restaurant ->
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .clickable(onClick = {
                            onRestaurantSelected(restaurant.name)
                            navigateToRestaurant(restaurant.name)
                        })
                ) {
                    RestaurantCell(restaurant)
                }
            }
        }
    }
}
  1. Vous devez ensuite implémenter l'état de l'application et la logique de navigation, puis mettre à jour MainActivity.kt. Cela permet d'accéder à un restaurant donné lorsque l'utilisateur clique sur la carte correspondante. Dans le fichier RestaurantAppState.kt, ajoutez l'extrait de code suivant :

RestaurantAppState.kt

package com.devrel.deeplinksbasics.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController

sealed class Screen(val route: String) {
   object Grid : Screen("restaurants")
   object Name : Screen("restaurants/{name}") {
       fun createRoute(name: String) = "restaurants/$name"
   }
}

@Composable
fun rememberRestaurantAppState(
    navController: NavHostController = rememberNavController(),
) = remember(navController) {
    RestaurantAppState(navController)
}

class RestaurantAppState(
    val navController: NavHostController,
) {
    fun navigateToRestaurant(restaurantName: String) {
        navController.navigate(Screen.Name.createRoute(restaurantName))
    }

    fun navigateBack() {
        navController.popBackStack()
    }
}
  1. Pour la navigation, vous devez créer le NavHost et utiliser les itinéraires des composables pour arriver à chaque restaurant. Dans le fichier RestaurantApp.kt, ajoutez l'extrait de code suivant :

RestaurantApp.kt

package com.devrel.deeplinksbasics.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.devrel.deeplinksbasics.ui.restaurant.RestaurantViewModel

@Composable
fun RestaurantApp(
   viewModel: RestaurantViewModel = viewModel(),
   appState: RestaurantAppState = rememberRestaurantAppState(),
) {
    val selectedRestaurant by viewModel.selectedRestaurant.collectAsState()
    val onRestaurantSelected: (String) -> Unit = { viewModel.updateSelectedRestaurantByName(it) }

    NavHost(
        navController = appState.navController,
        startDestination = Screen.Grid.route,
    ) {
        // Default route that points to the restaurant grid
        composable(Screen.Grid.route) {
            RestaurantGrid(
                restaurants = viewModel.restaurants,
                onRestaurantSelected = onRestaurantSelected,
                navigateToRestaurant = { restaurantName ->
                    appState.navigateToRestaurant(restaurantName)
                },
            )
        }
        // Route for the navigation to a particular restaurant when a user clicks on it
        composable(Screen.Name.route) {
            RestaurantCardDetails(restaurant = selectedRestaurant!!, onBack = appState::navigateBack)
        }
    }
}
  1. Vous êtes maintenant prêt à mettre à jour MainActivity.kt avec l'instance d'application. Remplacez le fichier par le code suivant :

MainActivity .kt

package com.devrel.deeplinksbasics

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.ui.Modifier
import com.devrel.deeplinksbasics.ui.RestaurantApp
import com.devrel.deeplinksbasics.ui.theme.DeepLinksBasicsTheme
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            DeepLinksBasicsTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    RestaurantApp()
                }
            }
        }
    }
}
  1. Exécutez l'application pour naviguer dans la grille et sélectionner un restaurant donné. Lorsque vous sélectionnez un restaurant, vous constatez que l'application affiche le restaurant en question et ses informations.

fecffce863113fd5.gif

Ajoutez maintenant Android App Links à la grille et à chaque restaurant. La section AndroidManifest.xml de la grille se trouve déjà dans /restaurants. Fait intéressant, vous pouvez utiliser la même pour chaque restaurant. Il vous suffit d'ajouter une nouvelle configuration d'itinéraire à la logique. Pour ce faire, procédez comme suit :

  1. Mettre à jour le fichier manifeste avec le filtre d'intent pour recevoir /restaurants sous la forme d'un chemin. Pensez à intégrer votre domaine en tant qu'hôte. Dans le fichier AndroidManifest.xml, ajoutez l'extrait de code suivant :

AndroidManifest.xml

...
<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:scheme="http"/>
  <data android:scheme="https"/>
  <data android:host="your.own.domain"/>
  <data android:pathPrefix="/restaurants"/>
</intent-filter>
  1. Dans le fichier RestaurantApp.kt, ajoutez l'extrait de code suivant :

RestaurantApp.kt

...
import androidx.navigation.NavType
import androidx.navigation.navArgument
import androidx.navigation.navDeepLink

fun RestaurantApp(...){
  NavHost(...){
    ...
    //  Route for the navigation to a particular restaurant when a user clicks on it
    //  and for an incoming deep link
    // Update with your own domain
        composable(Screen.Name.route,
            deepLinks = listOf(
                navDeepLink { uriPattern = "https://your.own.domain/restaurants/{name}" }
            ),
            arguments = listOf(
                navArgument("name") {
                    type = NavType.StringType
                }
            )
        ) { entry ->
            val restaurantName = entry.arguments?.getString("name")
            if (restaurantName != null) {
                LaunchedEffect(restaurantName) {
                    viewModel.updateSelectedRestaurantByName(restaurantName)
                }
            }
            selectedRestaurant?.let {
                RestaurantCardDetails(
                    restaurant = it,
                    onBack = appState::navigateBack
                )
            }
        }
  }
}

En arrière-plan, le NavHost correspond aux données Uri de l'intent Android avec les itinéraires composables. Si un itinéraire correspond, le composable s'affiche.

Le composant composable peut accepter un paramètre deepLinks, qui comporte une liste des URI envoyés par le filtre d'intent. Dans cet atelier de programmation, vous devez ajouter l'URL du site Web créé et définir le paramètre d'ID pour recevoir l'information et envoyer l'utilisateur vers le restaurant en question.

  1. Pour vous assurer que la logique d'application envoie l'utilisateur vers le restaurant après avoir cliqué sur un élément Android App Links, utilisez adb :
adb shell am start -W -a android.intent.action.VIEW -d "https://sabs-deeplinks-test.web.app/restaurants/gyrosAndMoar"

Notez que l'application affiche le restaurant en question.

Application des restaurants Android Emulator affichant l'écran du restaurant "gyros and moar".

8. Vérifier le tableau de bord de la Play Console

Vous avez déjà examiné le tableau de bord "Deep links" (Liens profonds). Ce tableau de bord fournit toutes les informations nécessaires pour garantir que vos liens profonds fonctionnent correctement. Vous pouvez même connaître la version de l'application ! Il indique les domaines, les liens et les liens personnalisés ajoutés au fichier manifeste. Il précise même quelles informations du fichier assetlinks.json mettre à jour en cas de problème.

Tableau de bord "Deep links" (Liens profonds) de la Play Console avec un élément Android App Links verifié.

9. Conclusion

Félicitations, vous venez de créer votre première application Android App Links !

Vous connaissez désormais la procédure de conception, de configuration, de création et de test Android App Links. Cette procédure comporte de nombreux aspects. Cet atelier de programmation réunit toutes les informations correspondantes, afin que vous puissiez réussir votre développement d'OS Android.

Vous savez maintenant quelles sont les étapes clés pour qu'Android App Links fonctionne.

Complément d'informations

Documents de référence