Atelier de programmation Android Cloud Firestore

1. Vue d'ensemble

Objectifs

Dans cet atelier de programmation, vous allez créer une application de recommandation de restaurants sur Android soutenue par Cloud Firestore. Vous apprendrez à :

  • Lire et écrire des données sur Firestore à partir d'une application Android
  • Écoutez les changements dans les données Firestore en temps réel
  • Utilisez l'authentification Firebase et les règles de sécurité pour sécuriser les données Firestore
  • Écrire des requêtes Firestore complexes

Conditions préalables

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

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

2. Créez un projet Firebase

  1. Connectez-vous à la console Firebase avec votre compte Google.
  2. Dans la console Firebase , cliquez sur Ajouter un projet .
  3. Comme indiqué dans la capture d'écran ci-dessous, saisissez un nom pour votre projet Firebase (par exemple, "Friendly Eats"), puis cliquez sur Continuer .

9d2f625aebcab6af.png

  1. Il vous sera peut-être demandé d'activer Google Analytics. Pour les besoins de cet atelier de programmation, votre sélection n'a pas d'importance.
  2. Après environ une minute, votre projet Firebase sera prêt. Cliquez sur Continuer .

3. Configurer l'exemple de projet

Téléchargez le code

Exécutez la commande suivante pour cloner l'exemple de code pour cet atelier de programmation. Cela créera un dossier appelé friendlyeats-android sur votre ordinateur :

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

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

Ajouter une configuration Firebase

  1. Dans la console Firebase , sélectionnez Présentation du projet dans le menu de gauche. Cliquez sur le bouton Android pour sélectionner la plateforme. Lorsque vous êtes invité à saisir un nom de package, utilisez com.google.firebase.example.fireeats

73d151ed16016421.png

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

Importer le projet

Ouvrez Android Studio. Cliquez sur Fichier > Nouveau > Importer un projet et 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 gratuit pour créer votre application.

Installer la CLI Firebase

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

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

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

Une fois que vous avez installé la CLI, l'exécution firebase --version devrait signaler une version 9.0.0 ou supérieure :

$ firebase --version
9.0.0

Se connecter

Exécutez firebase login pour connecter la CLI à votre compte Google. Cela ouvrira une nouvelle fenêtre de navigateur pour terminer le processus de connexion. Assurez-vous de choisir le même compte que vous avez utilisé lors de la création précédente de votre projet Firebase.

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

5. Exécutez 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écutez 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 comme celui-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 fonctionnant sur votre machine ! Assurez-vous de laisser cette commande en cours d'exécution pour le reste de l'atelier de programmation. Votre application Android devra se connecter aux émulateurs.

Connectez 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.

Sur la méthode create() de la classe FirestoreInitializer , examinez ce morceau 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 que nous nous connectons aux émulateurs uniquement lorsque notre application s'exécute en mode debug . Lorsque nous compilons 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. Tout au long de l'application, nous utiliserons FirebaseUtil.getFirestore() pour accéder à cette instance de FirebaseFirestore afin d'être sûrs de toujours nous connecter à l'émulateur Firestore lors de l'exécution en mode debug .

Exécutez l'application

Si vous avez correctement ajouté le fichier google-services.json , le projet devrait maintenant se compiler. Dans Android Studio, cliquez sur Créer > Reconstruire le projet et assurez-vous qu'il ne reste aucune erreur.

Dans Android Studio, exécutez l'application sur votre émulateur Android. Au début, un écran « Connexion » vous sera présenté. Vous pouvez utiliser n'importe quel e-mail et mot de passe pour vous connecter à l'application. Ce processus de connexion se connecte à l'émulateur d'authentification Firebase, donc aucune véritable information d'identification n'est transmise.

Ouvrez maintenant l'interface utilisateur des émulateurs en accédant à http://localhost:4000 dans votre navigateur Web. Cliquez ensuite sur l'onglet Authentification et vous devriez voir le compte que vous venez de créer :

Émulateur d'authentification Firebase

Une fois que vous avez terminé le processus de connexion, vous devriez voir l'écran d'accueil de l'application :

de06424023ffb4b9.png

Bientôt, nous ajouterons des données pour remplir l'écran d'accueil.

6. Écrivez des données sur Firestore

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

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

À des fins de démonstration, nous ajouterons une fonctionnalité dans l'application pour créer dix restaurants aléatoires lorsque nous cliquons sur le bouton « Ajouter des éléments aléatoires » dans le menu de débordement. Ouvrez le fichier MainFragment.kt et remplacez le contenu de la méthode onAddItemsClicked() par :

    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)
        }
    }

Il y a quelques points importants à noter 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'est donc pas nécessaire de créer la collection avant d'écrire les données.
  • Les documents peuvent être créés à l'aide des 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 identifiant généré automatiquement, nous n'avons donc pas besoin de spécifier un identifiant unique pour chaque restaurant.

Maintenant, réexécutez l'application et cliquez sur le bouton « Ajouter des éléments aléatoires » dans le menu à débordement (dans le coin supérieur droit) 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 et vous devriez voir les données que vous venez d'ajouter :

Émulateur d'authentification Firebase

Ces données sont 100 % locales sur votre machine. En fait, votre vrai projet ne contient même pas encore de base de données Firestore ! Cela signifie que vous pouvez expérimenter en toute sécurité la modification et la suppression de ces données sans conséquence.

Félicitations, vous venez d'écrire des données sur Firestore ! Dans la prochaine étape, nous apprendrons comment afficher ces données dans l'application.

7. Afficher les données de Firestore

Dans cette étape, nous apprendrons comment récupérer des données de Firestore et les afficher dans notre application. La première étape pour lire les données de 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 souhaitons maintenant écouter la requête, afin d'obtenir tous les documents correspondants et d'être informés des futures mises à jour en temps réel. Étant donné que 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. Tout d'abord, faisons en sorte que l'adaptateur implémente EventListener et définissons 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'auditeur recevra davantage d'événements contenant les modifications. Finissons maintenant d'implémenter l'écouteur. Ajoutez d’abord 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 depuis 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 attacher l'écouteur :

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

L'application est désormais entièrement configurée pour lire les données de Firestore. Exécutez à nouveau l'application et 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 l'un des noms de restaurant. Vous devriez voir cela changer dans l’application presque instantanément !

8. Trier et filtrer les données

L'application affiche actuellement les restaurants les mieux notés de l'ensemble de la collection, mais dans une véritable application de restaurant, l'utilisateur souhaiterait trier et filtrer les données. Par exemple, l'application devrait pouvoir afficher « Les meilleurs restaurants de fruits de mer de Philadelphie » ou « Pizza la moins chère ».

Cliquer sur la barre blanche en haut de l'application fait apparaître une boîte de dialogue de filtres. Dans cette section, nous utiliserons les 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 changer 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 construisons un objet Query en attachant les 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 à bas prix les plus populaires :

7a67a8a400c80c50.png

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

a670188398c3c59.png

Si vous êtes arrivé jusqu'ici, vous avez maintenant 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 prochaines sections, nous ajouterons des avis sur les restaurants et ajouterons des règles de sécurité à l'application.

9. Organiser les données en sous-collections

Dans cette section, nous ajouterons des notes à l'application afin que les utilisateurs puissent évaluer leurs restaurants préférés (ou les moins préférés).

Collections et sous-collections

Jusqu'à présent, nous avons stocké toutes les données des restaurants dans une collection de niveau supérieur appelée « restaurants ». Lorsqu'un utilisateur évalue un restaurant, nous souhaitons ajouter un nouvel objet Rating aux restaurants. Pour cette tâche, nous utiliserons une sous-collection. Vous pouvez considérer une sous-collection comme une collection attachée à un document. Ainsi, chaque document de restaurant aura une sous-collection d'évaluations remplie de documents d'évaluation. Les sous-collections aident à organiser les données sans surcharger 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 et interroger une sous-collection comme avec une collection de niveau supérieur, il n'y a aucune limitation de taille ni changement de performances. Vous pouvez en savoir plus sur le modèle de données Firestore ici .

Écrire des données dans une transaction

L'ajout d'une Rating à la sous-collection appropriée nécessite uniquement l'appel de .add() , mais 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, il existe un certain nombre de conditions de concurrence qui pourraient entraîner des données obsolètes ou incorrectes.

Pour garantir que les notes sont ajoutées correctement, nous utiliserons une transaction pour ajouter des notes à un restaurant. Cette transaction effectuera quelques actions :

  • Lisez la note actuelle du restaurant et calculez 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 une 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, lancez à nouveau l'application et cliquez sur l'un des restaurants, ce qui devrait faire apparaître l'écran de détail du restaurant. Cliquez sur le bouton + pour commencer à ajouter un avis. Ajoutez un avis en sélectionnant un certain nombre d'étoiles et en saisissant du texte.

78fa16cdf8ef435a.png

Cliquez sur Soumettre pour lancer la transaction. Une fois la transaction terminée, vous verrez votre avis affiché ci-dessous et une mise à jour du nombre d'avis du restaurant :

f9e670f40bd615b0.png

Bravo! Vous disposez désormais d'une application sociale, locale et mobile d'évaluation de restaurants construite sur Cloud Firestore. J'ai entendu dire que ceux-ci sont très populaires ces jours-ci.

10. Sécurisez vos données

Jusqu'à présent, nous n'avons pas pris en compte la sécurité de cette application. Comment savons-nous que les utilisateurs ne peuvent lire et écrire que leurs propres données correctes ? Les bases de données Firestore sont sécurisées par un fichier de configuration appelé Security Rules .

Ouvrez le fichier firestore.rules , vous devriez voir ce qui suit :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      //
      // WARNING: These rules are insecure! We will replace them with
      // more secure rules later in the codelab
      //
      allow read, write: if request.auth != null;
    }
  }
}

Modifions ces règles pour empêcher les accès ou modifications indésirables aux données, ouvrons le fichier firestore.rules et remplaçons le 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 restreignent l'accès pour garantir que les clients effectuent uniquement des modifications sécurisées. Par exemple, les mises à jour d'un document de restaurant ne peuvent modifier que les notes, pas le nom ou toute autre donnée immuable. Les évaluations ne peuvent être créées que si l'ID utilisateur correspond à l'utilisateur connecté, ce qui empêche l'usurpation d'identité.

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

11. Conclusion

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

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

Apprendre encore plus

Pour continuer à en apprendre davantage sur Firestore, voici quelques bons points de départ :

L'application de restaurant de cet atelier de programmation était 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 Firebase Emulator. Si vous souhaitez savoir comment déployer cette application sur un véritable projet Firebase, passez à l'étape suivante.

12. (Facultatif) Déployez votre application

Jusqu'à présent, cette application était entièrement locale, toutes les données sont contenues dans Firebase Emulator Suite. Dans cette section, vous apprendrez comment configurer votre projet Firebase pour que cette application fonctionne en production.

Authentification Firebase

Dans la console Firebase, accédez à la section Authentification et cliquez sur Commencer . Accédez à l'onglet Méthode de connexion et sélectionnez l'option E-mail/Mot de passe parmi les fournisseurs natifs .

Activez la méthode de connexion par e-mail/mot de passe et cliquez sur Enregistrer .

fournisseurs de connexion.png

Firestore

Créer une base de données

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

  1. Lorsque nous vous demanderons quelles sont les règles de sécurité, choisissez de démarrer en mode production , nous mettrons bientôt à jour ces règles.
  2. Choisissez l'emplacement de la base de données que vous souhaitez utiliser pour votre application. Notez que la sélection d'un emplacement de base de données est une décision permanente et pour le modifier, vous devrez créer un nouveau projet. Pour plus d'informations sur le choix d'un emplacement de projet, consultez la documentation .

Règles de déploiement

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

Cela déploiera le contenu de firestore.rules sur votre projet, ce que vous pourrez confirmer en accédant à l'onglet Règles de la console.

Déployer des index

L'application FriendlyEats propose un tri et un filtrage complexes qui nécessitent un certain nombre d'index composés personnalisés. Ceux-ci peuvent être créés 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 se connecter 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 soit :

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

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