Créer une application Android avec Firebase et Jetpack Compose

1. Introduction

Dernière mise à jour:16/11/2022

Créer une application Android avec Firebase et Jetpack Compose

Dans cet atelier de programmation, vous allez créer une application Android appelée Make It So. L'UI de cette application est entièrement créée avec Jetpack Compose, le kit d'outils moderne d'Android pour créer une UI native. Il est intuitif et nécessite moins de code que d'écrire des fichiers .xml et de les lier à des activités, des fragments ou des vues.

Pour comprendre comment Firebase et Jetpack Compose fonctionnent ensemble, vous devez d'abord comprendre l'architecture Android moderne. Une bonne architecture rend le système facile à comprendre, à développer et à gérer, car elle indique clairement comment les composants sont organisés et communiquent entre eux. Dans l'univers Android, l'architecture recommandée s'appelle Modèle-Vue-ViewModel. Le modèle représente la couche qui accède aux données dans l'application. La vue est la couche d'UI et ne doit rien savoir de la logique métier. C'est dans le ViewModel que la logique métier est appliquée, ce qui nécessite parfois que le ViewModel appelle la couche Model.

Nous vous recommandons vivement de lire cet article pour comprendre comment Model - View - ViewModel est appliqué à une application Android créée avec Jetpack Compose. Cela vous permettra de mieux comprendre le codebase et de réaliser plus facilement les étapes suivantes.

Objectifs de l'atelier

Make It So est une application de liste de tâches simple qui permet à l'utilisateur d'ajouter et de modifier des tâches, d'ajouter des indicateurs, des priorités et des dates limites, et de marquer les tâches comme terminées. Les images ci-dessous montrent les deux pages principales de cette application: la page de création de tâches et la page principale avec la liste des tâches créées.

Écran "Ajouter une tâche" de Make It So Écran d'accueil Make it So

Vous allez ajouter certaines fonctionnalités manquantes dans cette application:

  • Authentifier les utilisateurs avec une adresse e-mail et un mot de passe
  • Ajouter un écouteur à une collection Firestore et faire réagir l'UI aux modifications
  • Ajouter des traces personnalisées pour surveiller les performances d'un code spécifique dans l'application
  • Créer un bouton d'activation/de désactivation à l'aide de Remote Config et le lancer en plusieurs étapes

Points abordés

  • Utiliser Firebase Authentication, Performance Monitoring, Remote Config et Cloud Firestore dans une application Android moderne
  • Intégrer les API Firebase à une architecture MVVM
  • Refléter les modifications apportées avec les API Firebase dans une UI Compose

Prérequis

2. Obtenir l'application exemple et configurer Firebase

Obtenir le code de l'exemple d'application

Clonez le dépôt GitHub à partir de la ligne de commande :

git clone https://github.com/FirebaseExtended/make-it-so-android.git

Créer un projet Firebase

La première chose à faire est d'accéder à la console Firebase et de créer un projet Firebase en cliquant sur le bouton "+ Ajouter un projet", comme indiqué ci-dessous:

Console Firebase

Suivez les instructions à l'écran pour terminer de créer le projet.

Ajouter une application Android à votre projet Firebase

Dans votre projet Firebase, vous pouvez enregistrer différentes applications: pour Android, iOS, Web, Flutter et Unity.

Choisissez l'option Android, comme indiqué ci-dessous:

Présentation du projet Firebase

Ensuite, procédez comme suit :

  1. Saisissez com.example.makeitso comme nom de package et, éventuellement, un pseudo. Pour cet atelier de programmation, vous n'avez pas besoin d'ajouter le certificat de signature de débogage.
  2. Cliquez sur Suivant pour enregistrer votre application et accéder au fichier de configuration Firebase.
  3. Cliquez sur Télécharger google-services.json pour télécharger votre fichier de configuration et l'enregistrer dans le répertoire make-it-so-android/app.
  4. Cliquez sur Suivant. Étant donné que les SDK Firebase sont déjà inclus dans le fichier build.gradle de l'exemple de projet, cliquez sur Suivant pour passer à la section Étapes suivantes.
  5. Cliquez sur Accéder à la console pour terminer.

Pour que l'application Make it So fonctionne correctement, vous devez effectuer deux opérations dans la console avant de passer au code: activer les fournisseurs d'authentification et créer la base de données Firestore.

Configurer l'authentification

Commençons par activer l'authentification pour que les utilisateurs puissent se connecter à l'application:

  1. Dans le menu Build (Créer), sélectionnez Authentication (Authentification), puis cliquez sur Get Started (Commencer).
  2. Sur la fiche Mode de connexion, sélectionnez Adresse e-mail/Mot de passe, puis activez cette option.
  3. Cliquez ensuite sur Ajouter un fournisseur, puis sélectionnez et activez Anonyme.

Configurer Cloud Firestore

Configurez ensuite Firestore. Vous utiliserez Firestore pour stocker les tâches d'un utilisateur connecté. Chaque utilisateur dispose de son propre document dans une collection de la base de données.

  1. Dans le panneau de gauche de la console Firebase, développez Build (Compilation), puis sélectionnez Firestore database (Base de données Firestore).
  2. Cliquez sur Créer une base de données.
  3. Laissez le champ Database ID (ID de la base de données) défini sur (default).
  4. Sélectionnez un emplacement pour votre base de données, puis cliquez sur Suivant.
    Pour une application réelle, choisissez un emplacement proche de vos utilisateurs.
  5. Cliquez sur Démarrer en mode test. Lisez la clause de non-responsabilité concernant les règles de sécurité.
    Dans les étapes suivantes de cette section, vous allez ajouter des règles de sécurité pour protéger vos données. Ne distribuez pas ni n'exposez pas publiquement une application sans ajouter de règles de sécurité à votre base de données.
  6. Cliquez sur Créer.

Prenons le temps de créer des règles de sécurité robustes pour la base de données Firestore.

  1. Ouvrez le tableau de bord Firestore, puis accédez à l'onglet Règles.
  2. Modifiez les règles de sécurité de sorte qu'elles se présentent comme suit:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
    }
  }
}

Ces règles indiquent essentiellement que tout utilisateur connecté à l'application peut créer un document pour lui-même dans n'importe quelle collection. Une fois le document créé, seul l'utilisateur qui l'a créé pourra le consulter, le mettre à jour ou le supprimer.

Exécuter l'application

Vous êtes maintenant prêt à exécuter l'application. Ouvrez le dossier make-it-so-android/start dans Android Studio et exécutez l'application (cela peut être fait à l'aide d'un émulateur Android ou d'un appareil Android réel).

3. Firebase Authentication

Quelle fonctionnalité allez-vous ajouter ?

Dans l'état actuel de l'application exemple Make It So, un utilisateur peut commencer à utiliser l'application sans avoir à se connecter au préalable. Pour ce faire, il utilise l'authentification anonyme. Toutefois, les comptes anonymes ne permettent pas à l'utilisateur d'accéder à ses données sur d'autres appareils ni même lors de futures sessions. Bien que l'authentification anonyme soit utile pour une intégration chaleureuse, vous devez toujours permettre aux utilisateurs de passer à un autre type de connexion. Dans cet atelier de programmation, vous allez ajouter l'authentification par e-mail et par mot de passe à l'application Make It So.

C'est l'heure de coder !

Dès que l'utilisateur crée un compte en saisissant une adresse e-mail et un mot de passe, vous devez demander à l'API Firebase Authentication des identifiants par e-mail, puis associer les nouveaux identifiants au compte anonyme. Ouvrez le fichier AccountServiceImpl.kt dans Android Studio et mettez à jour la fonction linkAccount pour qu'elle ressemble à ceci:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

Ouvrez maintenant SignUpViewModel.kt et appelez la fonction linkAccount du service dans le bloc launchCatching de la fonction onSignUpClick:

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

Il tente d'abord de s'authentifier. Si l'appel aboutit, il passe à l'écran suivant (SettingsScreen). Comme vous exécutez ces appels dans un bloc launchCatching, si une erreur se produit sur la première ligne, l'exception sera détectée et gérée, et la deuxième ligne ne sera pas atteinte du tout.

Dès que l'SettingsScreen est à nouveau ouverte, vous devez vous assurer que les options Se connecter et Créer un compte ont disparu, car l'utilisateur est déjà authentifié. Pour ce faire, faisons en sorte que SettingsViewModel écoute l'état de l'utilisateur actuel (disponible dans AccountService.kt) pour vérifier si le compte est anonyme ou non. Pour ce faire, modifiez la uiState dans SettingsViewModel.kt pour qu'elle se présente comme suit:

screens/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

La dernière chose que vous devez faire est de mettre à jour le uiState dans SettingsScreen.kt pour collecter les états émis par le SettingsViewModel:

screens/settings/SettingsScreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

Désormais, chaque fois que l'utilisateur change, le SettingsScreen se recompose pour afficher les options en fonction de son nouvel état d'authentification.

C'est l'heure de tester !

Exécutez Make it So, puis accédez aux paramètres en cliquant sur l'icône en forme de roue dentée en haut à droite de l'écran. Cliquez ensuite sur l'option "Créer un compte" :

Écran des paramètres de Make It So Écran de connexion de Make It So

Saisissez une adresse e-mail valide et un mot de passe sécurisé pour créer votre compte. Vous devriez être redirigé vers la page des paramètres, où vous verrez deux nouvelles options: vous déconnecter et supprimer votre compte. Vous pouvez vérifier le nouveau compte créé dans le tableau de bord "Authentication" (Authentification) de la console Firebase en cliquant sur l'onglet "Users" (Utilisateurs).

4. Cloud Firestore

Quelle fonctionnalité allez-vous ajouter ?

Pour Cloud Firestore, vous allez ajouter un écouteur à la collection Firestore qui stocke les documents représentant les tâches affichées dans Make it So. Une fois cet écouteur ajouté, vous recevrez toutes les mises à jour apportées à cette collection.

C'est l'heure de coder !

Modifiez le Flow disponible dans StorageServiceImpl.kt pour qu'il se présente comme suit:

model/service/impl/StorageServiceImpl.kt

override val tasks: Flow<List<Task>>
    get() =
      auth.currentUser.flatMapLatest { user ->
        firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
      }

Ce code ajoute un écouteur à la collection de tâches en fonction de user.id. Chaque tâche est représentée par un document dans une collection nommée tasks, et chacune d'elles possède un champ nommé userId. Notez qu'un nouvel Flow sera émis si l'état de l'currentUser change (par exemple, en vous déconnectant).

Vous devez maintenant faire en sorte que Flow dans TasksViewModel.kt soit identique à celui du service:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

La dernière étape consiste à faire en sorte que le composable function dans TasksScreens.kt, qui représente l'UI, soit conscient de ce flux et le collecte en tant qu'état. Chaque fois que l'état change, la fonction composable se recompose automatiquement et affiche l'état le plus récent à l'utilisateur. Ajoutez ce code au fichier TasksScreen composable function:

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

Une fois que la fonction composable a accès à ces états, vous pouvez modifier LazyColumn (la structure que vous utilisez pour afficher une liste à l'écran) pour qu'elle ressemble à ceci:

screens/tasks/TasksScreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

C'est l'heure de tester !

Pour vérifier que cela fonctionne, ajoutez une tâche à l'aide de l'application (en cliquant sur le bouton "Ajouter" en bas à droite de l'écran). Une fois la tâche créée, elle devrait apparaître dans la collection Firestore de la console Firestore. Si vous vous connectez à Make it So sur d'autres appareils avec le même compte, vous pourrez modifier vos tâches et les voir mises à jour en temps réel sur tous les appareils.

5. Performance Monitoring

Quelle fonctionnalité allez-vous ajouter ?

Les performances sont un élément très important auquel vous devez prêter attention, car les utilisateurs sont très susceptibles d'abandonner votre application si ses performances ne sont pas bonnes et qu'elle prend trop de temps à effectuer une tâche simple. C'est pourquoi il est parfois utile de collecter des métriques sur un parcours spécifique d'un utilisateur dans votre application. Pour vous aider, Firebase Performance Monitoring propose des traces personnalisées. Suivez les étapes suivantes pour ajouter des traces personnalisées et mesurer les performances de différents éléments de code dans Make it So.

C'est l'heure de coder !

Si vous ouvrez le fichier Performance.kt, vous verrez une fonction intégrée appelée "trace". Cette fonction appelle l'API Performance Monitoring pour créer une trace personnalisée, en transmettant le nom de la trace en tant que paramètre. L'autre paramètre que vous voyez est le bloc de code que vous souhaitez surveiller. La métrique par défaut collectée pour chaque trace est le temps nécessaire à son exécution complète:

model/service/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

Vous pouvez choisir les parties du codebase que vous jugez importantes à mesurer et y ajouter des traces personnalisées. Voici un exemple d'ajout d'une trace personnalisée à la fonction linkAccount que vous avez vue précédemment (dans AccountServiceImpl.kt) dans cet atelier de programmation:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String): Unit =
  trace(LINK_ACCOUNT_TRACE) {
      val credential = EmailAuthProvider.getCredential(email, password)
      auth.currentUser!!.linkWithCredential(credential).await()
  }

Maintenant, à vous de jouer ! Ajoutez des traces personnalisées à l'application Make it So, puis passez à la section suivante pour vérifier si tout fonctionne comme prévu.

C'est l'heure de tester !

Une fois que vous avez ajouté les traces personnalisées, exécutez l'application et assurez-vous d'utiliser les fonctionnalités que vous souhaitez mesurer plusieurs fois. Accédez ensuite à la console Firebase, puis au tableau de bord des performances. En bas de l'écran, vous trouverez trois onglets: Demandes réseau, Traces personnalisées et Affichage de l'écran.

Accédez à l'onglet Traces personnalisées et vérifiez que les traces que vous avez ajoutées au codebase y sont affichées, et que vous pouvez voir le temps qu'il faut généralement pour exécuter ces éléments de code.

6. Remote Config

Quelle fonctionnalité allez-vous ajouter ?

Remote Config offre de nombreux cas d'utilisation, de la modification à distance de l'apparence de votre application à la configuration de différents comportements pour différents segments d'utilisateurs. Dans cet atelier de programmation, vous allez utiliser Remote Config pour créer un bouton d'activation/de désactivation qui affichera ou masquera la nouvelle fonctionnalité de modification de la tâche dans l'application Make it So.

C'est l'heure de coder !

La première chose à faire est de créer la configuration dans la console Firebase. Pour ce faire, accédez au tableau de bord Remote Config, puis cliquez sur le bouton Ajouter un paramètre. Remplissez les champs en suivant l'image ci-dessous:

Boîte de dialogue &quot;Créer un paramètre&quot; de Remote Config

Une fois tous les champs remplis, vous pouvez cliquer sur le bouton Enregistrer, puis sur Publier. Maintenant que le paramètre est créé et disponible pour votre codebase, vous devez ajouter le code qui récupérera les nouvelles valeurs dans votre application. Ouvrez le fichier ConfigurationServiceImpl.kt et mettez à jour l'implémentation de ces deux fonctions:

model/service/impl/ConfigurationServiceImpl.kt

override suspend fun fetchConfiguration(): Boolean {
  return remoteConfig.fetchAndActivate().await()
}

override val isShowTaskEditButtonConfig: Boolean
  get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()

La première fonction extrait les valeurs du serveur et est appelée dès le démarrage de l'application, dans SplashViewModel.kt. C'est le meilleur moyen de s'assurer que les valeurs les plus récentes seront disponibles sur tous les écrans dès le début. Ce n'est pas une bonne expérience utilisateur si vous modifiez l'UI ou le comportement de l'application plus tard, alors que l'utilisateur est en train de faire quelque chose.

La deuxième fonction renvoie la valeur booléenne publiée pour le paramètre que vous venez de créer dans la console. Vous devrez ensuite récupérer ces informations dans TasksViewModel.kt en ajoutant ce qui suit à la fonction loadTaskOptions:

screens/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

Vous récupérez la valeur de la première ligne et l'utilisez pour charger les options de menu des éléments de tâche de la deuxième ligne. Si la valeur est false, cela signifie que le menu ne contient pas l'option de modification. Maintenant que vous disposez de la liste des options, vous devez vous assurer que l'UI les affiche correctement. Lorsque vous créez une application avec Jetpack Compose, vous devez rechercher le composable function qui déclare l'apparence de l'UI du TasksScreen. Ouvrez donc le fichier TasksScreen.kt et mettez à jour LazyColum pour qu'il pointe vers les options disponibles dans TasksViewModel.kt:

screens/tasks/TasksScreen.kt

val options by viewModel.options

LazyColumn {
  items(tasks.value, key = { it.id }) { taskItem ->
    TaskItem(
      options = options,
      [...]
    )
  }
}

TaskItem est un autre composable function qui déclare l'apparence de l'UI d'une seule tâche. Chaque tâche est associée à un menu d'options qui s'affiche lorsque l'utilisateur clique sur l'icône à trois points à la fin de la tâche.

C'est l'heure de tester !

Vous êtes maintenant prêt à exécuter l'application. Vérifiez que la valeur que vous avez publiée à l'aide de la console Firebase correspond au comportement de l'application:

  • Si l'icône est false, vous ne devriez voir que deux options lorsque vous cliquez sur l'icône à trois points.
  • Si l'icône est true, trois options s'affichent lorsque vous cliquez sur l'icône à trois points.

Essayez de modifier la valeur plusieurs fois dans la console et de redémarrer l'application. C'est aussi simple que cela de lancer de nouvelles fonctionnalités dans votre application à l'aide de Remote Config.

7. Félicitations

Félicitations, vous avez créé une application Android avec Firebase et Jetpack Compose !

Vous avez ajouté Firebase Authentication, Performance Monitoring, Remote Config et Cloud Firestore à une application Android entièrement conçue avec Jetpack Compose pour l'UI, et vous l'avez adaptée à l'architecture MVVM recommandée.

Complément d'informations

Documents de référence