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 conçue avec Jetpack Compose, le kit d'outils moderne d'Android permettant de créer des interfaces utilisateur natives. Cette application est intuitive et nécessite moins de code que l'écriture de fichiers .xml et les liaisons avec 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. Le codebase sera ainsi plus facile à comprendre et les étapes suivantes seront plus faciles à effectuer.

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 "Make It So Home"

Vous allez ajouter certaines fonctionnalités qui ne sont pas disponibles dans cette application:

  • Authentifier les utilisateurs avec une adresse e-mail et un mot de passe
  • Ajouter un écouteur à une collection Firestore et faire en sorte que l'UI réagisse 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
  • Comment refléter les modifications apportées avec les API Firebase dans une interface utilisateur 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

Tout d'abord, accédez à la console Firebase et créez un projet Firebase en cliquant sur le bouton "+ Ajouter un projet", comme illustré ci-dessous:

Console Firebase

Suivez les étapes à l'écran pour terminer la création du 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.

Sélectionnez 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, il n'est pas nécessaire 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. Pour terminer, cliquez sur Accéder à la console.

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 (Compiler), sélectionnez Authentication (Authentification), puis cliquez sur Get Started (Commencer).
  2. Dans la fiche Méthode de connexion, sélectionnez Adresse e-mail/Mot de passe, puis activez-la.
  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 Créer, puis sélectionnez Base de données Firestore.
  2. Cliquez sur Créer une base de données.
  3. Laissez le champ ID de 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 un moment pour créer des règles de sécurité robustes pour la base de données Firestore.

  1. Ouvrez le tableau de bord Firestore et 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. Vous pouvez le faire à l'aide d'Android Emulator ou d'un véritable appareil Android.

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 aux utilisateurs d'accéder à leurs données sur d'autres appareils, ni même lors de sessions futures. Bien que l'authentification anonyme soit utile pour une intégration chaleureuse, vous devez toujours permettre aux utilisateurs de passer à un autre mode de connexion. Dans cet atelier de programmation, vous allez donc ajouter l'authentification par e-mail et 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 un identifiant de messagerie à l'API Firebase Authentication, puis associer les nouveaux identifiants au compte anonyme. Ouvrez le fichier AccountServiceImpl.kt dans Android Studio et modifiez la fonction linkAccount pour qu'elle se présente comme suit:

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 :

screen/settings/SettingsScreen.kt

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

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

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. Ensuite, cliquez sur l'option "Créer un compte" :

Écran des paramètres "Make It So" Écran d'inscription Make It So

Saisissez une adresse e-mail valide et un mot de passe sécurisé pour créer votre compte. Cela devrait fonctionner et vous devriez être redirigé vers la page des paramètres, où vous verrez deux nouvelles options: vous déconnecter et supprimer votre compte. Pour vérifier le compte créé dans le tableau de bord "Authentification" de la console Firebase, cliquez sur l'onglet "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 la section Make it so (Personnaliser). Une fois cet écouteur ajouté, vous recevrez toutes les mises à jour apportées à cette collection.

Il est temps de coder !

Mettez à jour 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'entre elles possède un champ nommé userId. Notez qu'un nouvel Flow sera émis si l'état de l'currentUser change (en vous déconnectant, par exemple).

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 ceci à TasksScreen composable function:

screen/tasks/TasksScreen.kt

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

Une fois que la fonction composable a accès à ces états, vous pouvez mettre à jour LazyColumn (qui correspond à la structure que vous utilisez pour afficher une liste à l'écran) pour qu'il se présente comme suit:

screen/tasks/TasksScreen.kt

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

Passons au test !

Pour vérifier que cela a fonctionné, ajoutez une tâche à l'aide de l'application (en cliquant sur le bouton "Add" (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 sont mauvaises 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 dans différents éléments de code dans Make it so (pour le rendre tel).

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 correspond au temps nécessaire à l'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 considérez comme 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 (Créer comme prévu), puis passez à la section suivante pour vérifier que tout a bien fonctionné comme prévu.

C'est l'heure de tester !

Après avoir 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 s'y affichent, et que vous pouvez voir le temps qu'il faut généralement pour exécuter ces morceaux de code.

6. Remote Config

Quelle fonctionnalité allez-vous ajouter ?

Il existe de nombreux cas d'utilisation de Remote Config, comme modifier l'apparence de votre application à distance ou configurer 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 !

Vous devez d'abord 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 comme indiqué dans 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 dès le début dans tous les écrans. Ce n'est pas une bonne expérience utilisateur si vous modifiez l'interface utilisateur ou le comportement de l'application par la suite, alors que l'utilisateur est en plein travail.

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 devez récupérer ces informations dans TasksViewModel.kt, en ajoutant ce qui suit à la fonction loadTaskOptions:

screen/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 contiendra 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 :

screen/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.

Passons au test !

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 la valeur est true, vous devriez voir trois options 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'interface utilisateur, et vous l'avez intégrée à l'architecture MVVM recommandée.

Complément d'informations

Documents de référence