Atelier de programmation Android sur Cloud Firestore

1. Présentation

Objectifs

Dans cet atelier de programmation, vous allez créer une application de recommandation de restaurants sur Android, soutenue par Cloud Firestore. Vous allez apprendre à effectuer les tâches suivantes :

  • Lire et écrire des données dans Firestore à partir d'une application Android
  • Écouter les modifications apportées aux données Firestore en temps réel
  • Utiliser Firebase Authentication et les règles de sécurité pour sécuriser des données Firestore
  • Écrire des requêtes Firestore complexes

Prérequis

Avant de commencer cet atelier de programmation, assurez-vous d'avoir :

  • Android Studio Flamingo ou version ultérieure
  • Un émulateur Android avec l'API 19 ou version ultérieure
  • Node.js version 16 ou ultérieure
  • Java version 17 ou ultérieure

2. Créer un projet Firebase

  1. Connectez-vous à la console Firebase à l'aide de votre compte Google.
  2. Cliquez sur le bouton pour créer un projet, puis saisissez un nom de projet (par exemple, FriendlyEats).
  3. Cliquez sur Continuer.
  4. Si vous y êtes invité, lisez et acceptez les Conditions d'utilisation de Firebase, puis cliquez sur Continuer.
  5. (Facultatif) Activez l'assistance IA dans la console Firebase (appelée "Gemini dans Firebase").
  6. Pour cet atelier de programmation, vous n'avez pas besoin de Google Analytics. Désactivez donc l'option Google Analytics.
  7. Cliquez sur Créer un projet, attendez que votre projet soit provisionné, puis cliquez sur Continuer.

3. Configurer l'exemple de projet

Télécharger le code

Exécutez la commande suivante pour cloner l'exemple de code de cet atelier de programmation. Un dossier nommé friendlyeats-android sera créé sur votre machine :

$ git clone https://github.com/firebase/friendlyeats-android

Si vous n'avez pas git sur votre ordinateur, vous pouvez également télécharger le code directement depuis GitHub.

Ajouter la configuration Firebase

  1. Dans la console Firebase, sélectionnez Vue d'ensemble du projet dans le menu de navigation de gauche. Cliquez sur le bouton Android pour sélectionner la plate-forme. Lorsque vous êtes invité à saisir un nom de package, utilisez com.google.firebase.example.fireeats.

73d151ed16016421.png

  1. Cliquez sur Register App (Enregistrer l'application), puis suivez les instructions pour télécharger le fichier google-services.json et le déplacer dans le dossier app/ du code que vous venez de télécharger. Cliquez ensuite sur Next (Suivant).

Importer le projet

Ouvrez Android Studio. Cliquez sur File > New > Import Project (Fichier > Nouveau > Importer un projet), puis sélectionnez le dossier friendlyeats-android.

4. Configurer les émulateurs Firebase

Dans cet atelier de programmation, vous utiliserez la suite d'émulateurs Firebase pour émuler localement Cloud Firestore et d'autres services Firebase. Cela fournit un environnement de développement local sûr, rapide et sans frais pour créer votre application.

Installer la CLI Firebase

Vous devez d'abord installer la CLI Firebase. Si vous utilisez macOS ou Linux, vous pouvez exécuter la commande cURL suivante :

curl -sL https://firebase.tools | bash

Si vous utilisez Windows, consultez les instructions d'installation pour obtenir un fichier binaire autonome ou pour installer l'outil via npm.

Une fois la CLI installée, l'exécution de firebase --version devrait renvoyer une version 9.0.0 ou ultérieure :

$ firebase --version
9.0.0

Connexion

Exécutez firebase login pour associer l'interface de ligne de commande à votre compte Google. Une nouvelle fenêtre de navigateur s'ouvre pour vous permettre de terminer le processus de connexion. Veillez à choisir le même compte que celui que vous avez utilisé pour créer votre projet Firebase.

Depuis le dossier friendlyeats-android, exécutez firebase use --add pour associer votre projet local à votre projet Firebase. Suivez les instructions pour sélectionner le projet que vous avez créé précédemment. Si vous êtes invité à choisir un alias, saisissez default.

5. Exécuter l'application

Il est maintenant temps d'exécuter la suite d'émulateurs Firebase et l'application Android FriendlyEats pour la première fois.

Exécuter les émulateurs

Dans votre terminal, à partir du répertoire friendlyeats-android, exécutez firebase emulators:start pour démarrer les émulateurs Firebase. Vous devriez voir des journaux semblables à ceux-ci :

$ firebase emulators:start
i  emulators: Starting emulators: auth, firestore
i  firestore: Firestore Emulator logging to firestore-debug.log
i  ui: Emulator UI logging to ui-debug.log

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4000/firestore │
└────────────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

Vous disposez désormais d'un environnement de développement local complet sur votre ordinateur. Veillez à laisser cette commande s'exécuter pendant le reste de l'atelier de programmation, car votre application Android devra se connecter aux émulateurs.

Associer l'application aux émulateurs

Ouvrez les fichiers util/FirestoreInitializer.kt et util/AuthInitializer.kt dans Android Studio. Ces fichiers contiennent la logique permettant de connecter les SDK Firebase aux émulateurs locaux exécutés sur votre machine, au démarrage de l'application.

Dans la méthode create() de la classe FirestoreInitializer, examinez cet extrait de code :

    // Use emulators only in debug builds
    if (BuildConfig.DEBUG) {
        firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
    }

Nous utilisons BuildConfig pour nous assurer de ne nous connecter aux émulateurs que lorsque notre application s'exécute en mode debug. Lorsque nous compilerons l'application en mode release, cette condition sera fausse.

Nous pouvons voir qu'il utilise la méthode useEmulator(host, port) pour connecter le SDK Firebase à l'émulateur Firestore local. Dans toute l'application, nous utiliserons FirebaseUtil.getFirestore() pour accéder à cette instance de FirebaseFirestore afin de nous assurer que nous nous connectons toujours à l'émulateur Firestore lorsque nous exécutons en mode debug.

Exécuter l'application

Si vous avez correctement ajouté le fichier google-services.json, le projet devrait maintenant se compiler. Dans Android Studio, cliquez sur Build > Rebuild Project (Compiler > Recompiler le projet) et assurez-vous qu'il ne reste aucune erreur.

Dans Android Studio, exécutez l'application sur votre émulateur Android. Un écran de connexion s'affiche. Vous pouvez utiliser n'importe quelle adresse e-mail et n'importe quel mot de passe pour vous connecter à l'application. Ce processus de connexion se connecte à l'émulateur Firebase Authentication. Aucune véritable identifiant n'est donc transmis.

Ouvrez maintenant l'interface utilisateur des émulateurs en accédant à http://localhost:4000 dans votre navigateur Web. Cliquez ensuite sur l'onglet Authentication (Authentification). Le compte que vous venez de créer devrait s'afficher :

Émulateur Firebase Auth

Une fois le processus de connexion terminé, l'écran d'accueil de l'application devrait s'afficher :

de06424023ffb4b9.png

Nous allons bientôt ajouter des données pour remplir l'écran d'accueil.

6. Écrire des données dans Firestore

Dans cette section, nous allons écrire des données dans Firestore afin de remplir l'écran d'accueil actuellement vide.

Le principal objet de modèle dans notre application est un restaurant (voir model/Restaurant.kt). Les données Firestore sont divisées en documents, collections et sous-collections. Nous allons stocker chaque restaurant sous forme de document dans une collection de premier niveau appelée "restaurants". Pour en savoir plus sur le modèle de données Firestore, consultez la documentation sur les documents et les collections.

À des fins de démonstration, nous allons ajouter une fonctionnalité à l'application pour créer dix restaurants aléatoires lorsque nous cliquerons sur le bouton "Ajouter des éléments aléatoires" dans le menu à développer. Ouvrez le fichier MainFragment.kt et remplacez le contenu de la méthode onAddItemsClicked() par ce qui suit :

    private fun onAddItemsClicked() {
        val restaurantsRef = firestore.collection("restaurants")
        for (i in 0..9) {
            // Create random restaurant / ratings
            val randomRestaurant = RestaurantUtil.getRandom(requireContext())

            // Add restaurant
            restaurantsRef.add(randomRestaurant)
        }
    }

Voici quelques points importants à retenir concernant le code ci-dessus :

  • Nous avons commencé par obtenir une référence à la collection "restaurants". Les collections sont créées implicitement lorsque des documents sont ajoutés. Il n'était donc pas nécessaire de créer la collection avant d'écrire des données.
  • Les documents peuvent être créés à l'aide de classes de données Kotlin, que nous utilisons pour créer chaque document Restaurant.
  • La méthode add() ajoute un document à une collection avec un ID généré automatiquement. Nous n'avons donc pas eu besoin de spécifier un ID unique pour chaque restaurant.

Exécutez à nouveau l'application, puis cliquez sur le bouton "Add Random Items" (Ajouter des éléments aléatoires) dans le menu à trois points (en haut à droite) pour appeler le code que vous venez d'écrire :

95691e9b71ba55e3.png

Ouvrez maintenant l'interface utilisateur des émulateurs en accédant à http://localhost:4000 dans votre navigateur Web. Cliquez ensuite sur l'onglet Firestore. Les données que vous venez d'ajouter devraient s'afficher :

Émulateur Firebase Auth

Ces données sont 100 % locales sur votre appareil. En fait, votre projet réel ne contient même pas encore de base de données Firestore. Vous pouvez donc modifier et supprimer ces données sans risque.

Félicitations ! Vous venez d'écrire des données dans Firestore. À l'étape suivante, nous verrons comment afficher ces données dans l'application.

7. Afficher les données de Firestore

Dans cette étape, nous allons apprendre à récupérer des données depuis Firestore pour les afficher dans notre application. La première étape pour lire des données depuis Firestore consiste à créer un Query. Ouvrez le fichier MainFragment.kt et ajoutez le code suivant au début de la méthode onViewCreated() :

        // Firestore
        firestore = Firebase.firestore

        // Get the 50 highest rated restaurants
        query = firestore.collection("restaurants")
            .orderBy("avgRating", Query.Direction.DESCENDING)
            .limit(LIMIT.toLong())

Nous voulons maintenant écouter la requête pour obtenir tous les documents correspondants et être avertis des futures mises à jour en temps réel. Comme notre objectif final est de lier ces données à un RecyclerView, nous devons créer une classe RecyclerView.Adapter pour écouter les données.

Ouvrez la classe FirestoreAdapter, qui a déjà été partiellement implémentée. Commençons par faire en sorte que l'adaptateur implémente EventListener et définisse la fonction onEvent afin qu'il puisse recevoir les mises à jour d'une requête Firestore :

abstract class FirestoreAdapter<VH : RecyclerView.ViewHolder>(private var query: Query?) :
        RecyclerView.Adapter<VH>(),
        EventListener<QuerySnapshot> { // Add this implements
    
    // ...

    // Add this method
    override fun onEvent(documentSnapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {
        
        // Handle errors
        if (e != null) {
            Log.w(TAG, "onEvent:error", e)
            return
        }

        // Dispatch the event
        if (documentSnapshots != null) {
            for (change in documentSnapshots.documentChanges) {
                // snapshot of the changed document
                when (change.type) {
                    DocumentChange.Type.ADDED -> {
                        // TODO: handle document added
                    }
                    DocumentChange.Type.MODIFIED -> {
                        // TODO: handle document changed
                    }
                    DocumentChange.Type.REMOVED -> {
                        // TODO: handle document removed
                    }
                }
            }
        }

        onDataChanged()
    }
    
    // ...
}

Lors du chargement initial, l'écouteur recevra un événement ADDED pour chaque nouveau document. À mesure que l'ensemble de résultats de la requête change au fil du temps, l'écouteur reçoit davantage d'événements contenant les modifications. Terminons maintenant l'implémentation du listener. Commencez par ajouter trois nouvelles méthodes : onDocumentAdded, onDocumentModified et onDocumentRemoved :

    private fun onDocumentAdded(change: DocumentChange) {
        snapshots.add(change.newIndex, change.document)
        notifyItemInserted(change.newIndex)
    }

    private fun onDocumentModified(change: DocumentChange) {
        if (change.oldIndex == change.newIndex) {
            // Item changed but remained in same position
            snapshots[change.oldIndex] = change.document
            notifyItemChanged(change.oldIndex)
        } else {
            // Item changed and changed position
            snapshots.removeAt(change.oldIndex)
            snapshots.add(change.newIndex, change.document)
            notifyItemMoved(change.oldIndex, change.newIndex)
        }
    }

    private fun onDocumentRemoved(change: DocumentChange) {
        snapshots.removeAt(change.oldIndex)
        notifyItemRemoved(change.oldIndex)
    }

Appelez ensuite ces nouvelles méthodes à partir de onEvent :

    override fun onEvent(documentSnapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {

        // Handle errors
        if (e != null) {
            Log.w(TAG, "onEvent:error", e)
            return
        }

        // Dispatch the event
        if (documentSnapshots != null) {
            for (change in documentSnapshots.documentChanges) {
                // snapshot of the changed document
                when (change.type) {
                    DocumentChange.Type.ADDED -> {
                        onDocumentAdded(change) // Add this line
                    }
                    DocumentChange.Type.MODIFIED -> {
                        onDocumentModified(change) // Add this line
                    }
                    DocumentChange.Type.REMOVED -> {
                        onDocumentRemoved(change) // Add this line
                    }
                }
            }
        }

        onDataChanged()
    }

Enfin, implémentez la méthode startListening() pour associer l'écouteur :

    fun startListening() {
        if (registration == null) {
            registration = query.addSnapshotListener(this)
        }
    }

L'application est maintenant entièrement configurée pour lire les données de Firestore. Exécutez de nouveau l'application. Vous devriez voir les restaurants que vous avez ajoutés à l'étape précédente :

9e45f40faefce5d0.png

Revenez maintenant à l'interface utilisateur de l'émulateur dans votre navigateur et modifiez le nom d'un restaurant. Vous devriez voir la modification dans l'application presque instantanément.

8. Trier et filtrer les données

L'application affiche actuellement les restaurants les mieux notés de toute la collection, mais dans une véritable application de restaurant, l'utilisateur souhaiterait trier et filtrer les données. Par exemple, l'application doit pouvoir afficher "Meilleurs restaurants de fruits de mer à Philadelphie" ou "Pizzas les moins chères".

Cliquez sur la barre blanche en haut de l'application pour afficher une boîte de dialogue de filtres. Dans cette section, nous allons utiliser des requêtes Firestore pour faire fonctionner cette boîte de dialogue :

67898572a35672a5.png

Modifions la méthode onFilter() de MainFragment.kt. Cette méthode accepte un objet Filters, qui est un objet d'assistance que nous avons créé pour capturer la sortie de la boîte de dialogue des filtres. Nous allons modifier cette méthode pour construire une requête à partir des filtres :

    override fun onFilter(filters: Filters) {
        // Construct query basic query
        var query: Query = firestore.collection("restaurants")

        // Category (equality filter)
        if (filters.hasCategory()) {
            query = query.whereEqualTo(Restaurant.FIELD_CATEGORY, filters.category)
        }

        // City (equality filter)
        if (filters.hasCity()) {
            query = query.whereEqualTo(Restaurant.FIELD_CITY, filters.city)
        }

        // Price (equality filter)
        if (filters.hasPrice()) {
            query = query.whereEqualTo(Restaurant.FIELD_PRICE, filters.price)
        }

        // Sort by (orderBy with direction)
        if (filters.hasSortBy()) {
            query = query.orderBy(filters.sortBy.toString(), filters.sortDirection)
        }

        // Limit items
        query = query.limit(LIMIT.toLong())

        // Update the query
        adapter.setQuery(query)

        // Set header
        binding.textCurrentSearch.text = HtmlCompat.fromHtml(
            filters.getSearchDescription(requireContext()),
            HtmlCompat.FROM_HTML_MODE_LEGACY
        )
        binding.textCurrentSortBy.text = filters.getOrderDescription(requireContext())

        // Save filters
        viewModel.filters = filters
    }

Dans l'extrait ci-dessus, nous créons un objet Query en ajoutant des clauses where et orderBy pour correspondre aux filtres donnés.

Exécutez à nouveau l'application et sélectionnez le filtre suivant pour afficher les restaurants les plus populaires et les moins chers :

7a67a8a400c80c50.png

Vous devriez maintenant voir une liste filtrée de restaurants ne contenant que des options à bas prix :

a670188398c3c59.png

Si vous êtes arrivé jusqu'ici, vous avez créé une application de visualisation de recommandations de restaurants entièrement fonctionnelle sur Firestore. Vous pouvez désormais trier et filtrer les restaurants en temps réel. Dans les sections suivantes, nous allons ajouter des avis aux restaurants et des règles de sécurité à l'application.

9. Organiser les données dans des sous-collections

Dans cette section, nous allons ajouter des notes à l'application afin que les utilisateurs puissent évaluer leurs restaurants préférés (ou ceux qu'ils aiment le moins).

Collections et sous-collections

Jusqu'à présent, nous avons stocké toutes les données des restaurants dans une collection de premier niveau appelée "restaurants". Lorsqu'un utilisateur évalue un restaurant, nous souhaitons ajouter un nouvel objet Rating aux restaurants. Pour cette tâche, nous allons utiliser une sous-collection. Vous pouvez considérer une sous-collection comme une collection associée à un document. Chaque document de restaurant aura donc une sous-collection de notes contenant des documents de notes. Les sous-collections permettent d'organiser les données sans alourdir nos documents ni nécessiter de requêtes complexes.

Pour accéder à une sous-collection, appelez .collection() sur le document parent :

val subRef = firestore.collection("restaurants")
        .document("abc123")
        .collection("ratings")

Vous pouvez accéder à une sous-collection et l'interroger comme vous le feriez pour une collection de premier niveau. Il n'y a aucune limite de taille ni aucun changement de performances. Pour en savoir plus sur le modèle de données Firestore, cliquez ici.

Écrire des données dans une transaction

Pour ajouter un Rating à la sous-collection appropriée, il suffit d'appeler .add(). Toutefois, nous devons également mettre à jour la note moyenne et le nombre de notes de l'objet Restaurant pour refléter les nouvelles données. Si nous utilisons des opérations distinctes pour effectuer ces deux modifications, un certain nombre de conditions de concurrence peuvent entraîner des données obsolètes ou incorrectes.

Pour nous assurer que les notes sont ajoutées correctement, nous allons utiliser une transaction pour ajouter des notes à un restaurant. Cette transaction effectue plusieurs actions :

  • Lire la note actuelle du restaurant et calculer la nouvelle
  • Ajouter la note à la sous-collection
  • Mettre à jour la note moyenne et le nombre de notes du restaurant

Ouvrez RestaurantDetailFragment.kt et implémentez la fonction addRating :

    private fun addRating(restaurantRef: DocumentReference, rating: Rating): Task<Void> {
        // Create reference for new rating, for use inside the transaction
        val ratingRef = restaurantRef.collection("ratings").document()

        // In a transaction, add the new rating and update the aggregate totals
        return firestore.runTransaction { transaction ->
            val restaurant = transaction.get(restaurantRef).toObject<Restaurant>()
                ?: throw Exception("Restaurant not found at ${restaurantRef.path}")

            // Compute new number of ratings
            val newNumRatings = restaurant.numRatings + 1

            // Compute new average rating
            val oldRatingTotal = restaurant.avgRating * restaurant.numRatings
            val newAvgRating = (oldRatingTotal + rating.rating) / newNumRatings

            // Set new restaurant info
            restaurant.numRatings = newNumRatings
            restaurant.avgRating = newAvgRating

            // Commit to Firestore
            transaction.set(restaurantRef, restaurant)
            transaction.set(ratingRef, rating)

            null
        }
    }

La fonction addRating() renvoie un Task représentant l'intégralité de la transaction. Dans la fonction onRating(), des écouteurs sont ajoutés à la tâche pour répondre au résultat de la transaction.

Maintenant, exécutez à nouveau l'application et cliquez sur l'un des restaurants. L'écran d'informations sur le restaurant devrait s'afficher. Cliquez sur le bouton + pour commencer à ajouter un avis. Ajoutez un avis en sélectionnant un nombre d'étoiles et en saisissant du texte.

78fa16cdf8ef435a.png

Cliquez sur Envoyer pour lancer la transaction. Une fois la transaction terminée, votre avis s'affiche ci-dessous et le nombre d'avis sur le restaurant est mis à jour :

f9e670f40bd615b0.png

Félicitations ! Vous disposez désormais d'une application d'avis sur les restaurants, sociale, locale et mobile, basée sur Cloud Firestore. Il paraît qu'ils sont très populaires en ce moment.

10. Sécurisez vos données

Jusqu'à présent, nous n'avons pas abordé la sécurité de cette application. Comment savoir si les utilisateurs ne peuvent lire et écrire que leurs propres données ? Les bases de données Firestore sont sécurisées par un fichier de configuration appelé Règles de sécurité.

Ouvrez le fichier firestore.rules et remplacez son contenu par ce qui suit :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Determine if the value of the field "key" is the same
    // before and after the request.
    function isUnchanged(key) {
      return (key in resource.data)
        && (key in request.resource.data)
        && (resource.data[key] == request.resource.data[key]);
    }

    // Restaurants
    match /restaurants/{restaurantId} {
      // Any signed-in user can read
      allow read: if request.auth != null;

      // Any signed-in user can create
      // WARNING: this rule is for demo purposes only!
      allow create: if request.auth != null;

      // Updates are allowed if no fields are added and name is unchanged
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys())
                    && isUnchanged("name");

      // Deletes are not allowed.
      // Note: this is the default, there is no need to explicitly state this.
      allow delete: if false;

      // Ratings
      match /ratings/{ratingId} {
        // Any signed-in user can read
        allow read: if request.auth != null;

        // Any signed-in user can create if their uid matches the document
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;

        // Deletes and updates are not allowed (default)
        allow update, delete: if false;
      }
    }
  }
}

Ces règles limitent l'accès afin de s'assurer que les clients n'apportent que des modifications sûres. Par exemple, les modifications apportées à un document "restaurant" ne peuvent modifier que les notes, pas le nom, ni aucune autre donnée immuable. La création de notes n'est possible que si l'ID utilisateur correspond à l'utilisateur connecté, ce qui évite tout spoofing.

Pour en savoir plus sur les règles de sécurité, consultez la documentation.

11. Conclusion

Vous avez créé une application complète sur Firestore. Vous avez découvert les fonctionnalités Firestore les plus importantes, y compris :

  • Documents et collections
  • Lire et écrire des données
  • Trier et filtrer avec des requêtes
  • Sous-collections
  • Transactions

En savoir plus

Pour en savoir plus sur Firestore, voici quelques bons points de départ :

L'application de restaurant de cet atelier de programmation est basée sur l'exemple d'application "Friendly Eats". Vous pouvez parcourir le code source de cette application ici.

(Facultatif) Déployer en production

Jusqu'à présent, cette application n'a utilisé que la suite d'émulateurs Firebase. Si vous souhaitez apprendre à déployer cette application dans un véritable projet Firebase, passez à l'étape suivante.

12. (Facultatif) Déployer votre application

Jusqu'à présent, cette application était entièrement locale. Toutes les données sont contenues dans la suite d'émulateurs Firebase. Dans cette section, vous allez apprendre à configurer votre projet Firebase pour que cette application fonctionne en production.

Firebase Authentication

Dans la console Firebase, accédez à la section Authentification, puis cliquez sur Premiers pas. Accédez à l'onglet Mode de connexion, puis sélectionnez l'option Adresse e-mail/Mot de passe sous Fournisseurs natifs.

Activez le mode de connexion Adresse e-mail/Mot de passe, puis cliquez sur Enregistrer.

sign-in-providers.png

Firestore

Créer une base de données

Accédez à la section Base de données Firestore de la console, puis cliquez sur Créer une base de données :

  1. Lorsque vous êtes invité à choisir un mode pour les règles de sécurité, sélectionnez Mode Production. Nous mettrons à jour ces règles prochainement.
  2. Choisissez l'emplacement de la base de données que vous souhaitez utiliser pour votre application. Notez que le choix de l'emplacement de la base de données est définitif. Pour le modifier, vous devrez créer un projet. Pour en savoir plus sur le choix d'un emplacement de projet, consultez la documentation.

Déployer des règles

Pour déployer les règles de sécurité que vous avez écrites précédemment, exécutez la commande suivante dans le répertoire de l'atelier de programmation :

$ firebase deploy --only firestore:rules

Le contenu de firestore.rules sera alors déployé dans votre projet. Vous pouvez le vérifier en accédant à l'onglet Règles de la console.

Déployer des index

L'application FriendlyEats dispose d'un système de tri et de filtrage complexe qui nécessite un certain nombre d'index composites personnalisés. Vous pouvez les créer manuellement dans la console Firebase, mais il est plus simple d'écrire leurs définitions dans le fichier firestore.indexes.json et de les déployer à l'aide de la CLI Firebase.

Si vous ouvrez le fichier firestore.indexes.json, vous verrez que les index requis ont déjà été fournis :

{
  "indexes": [
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "city", "mode": "ASCENDING" },
        { "fieldPath": "avgRating", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "category", "mode": "ASCENDING" },
        { "fieldPath": "avgRating", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "price", "mode": "ASCENDING" },
        { "fieldPath": "avgRating", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "city", "mode": "ASCENDING" },
        { "fieldPath": "numRatings", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "category", "mode": "ASCENDING" },
        { "fieldPath": "numRatings", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "price", "mode": "ASCENDING" },
        { "fieldPath": "numRatings", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "city", "mode": "ASCENDING" },
        { "fieldPath": "price", "mode": "ASCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "fields": [
        { "fieldPath": "category", "mode": "ASCENDING" },
        { "fieldPath": "price", "mode": "ASCENDING" }
      ]
    }
  ],
  "fieldOverrides": []
}

Pour déployer ces index, exécutez la commande suivante :

$ firebase deploy --only firestore:indexes

Notez que la création d'index n'est pas instantanée. Vous pouvez suivre la progression dans la console Firebase.

Configurer l'application

Dans les fichiers util/FirestoreInitializer.kt et util/AuthInitializer.kt, nous avons configuré le SDK Firebase pour qu'il se connecte aux émulateurs en mode débogage :

    override fun create(context: Context): FirebaseFirestore {
        val firestore = Firebase.firestore
        // Use emulators only in debug builds
        if (BuildConfig.DEBUG) {
            firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
        }
        return firestore
    }

Si vous souhaitez tester votre application avec votre véritable projet Firebase, vous pouvez :

  1. Créez l'application en mode Release et exécutez-la sur un appareil.
  2. Remplacez temporairement BuildConfig.DEBUG par false et exécutez à nouveau l'application.

Notez que vous devrez peut-être vous déconnecter de l'application et vous reconnecter pour vous connecter correctement à la production.