Codelab para Android de Cloud Firestore

1. Información general

Metas

En este laboratorio de código, creará una aplicación de recomendación de restaurantes en Android respaldada por Cloud Firestore. Aprenderá a:

  • Leer y escribir datos en Firestore desde una aplicación de Android
  • Escuche los cambios en los datos de Firestore en tiempo real
  • Use la autenticación de Firebase y las reglas de seguridad para proteger los datos de Firestore
  • Escribe consultas complejas de Firestore

Prerrequisitos

Antes de iniciar este laboratorio de código, asegúrese de tener:

  • Estudio Android 4.0 o superior
  • Un emulador de Android
  • Versión Node.js 10 o más alto
  • Versión 8 o superior de Java

2. Crea un proyecto de Firebase

  1. Inicia sesión en la consola de Firebase con su cuenta de Google.
  2. En la consola de Firebase , haga clic en Agregar proyecto.
  3. Como se muestra en la captura de pantalla a continuación, introduzca un nombre para el proyecto Firebase (por ejemplo, "Come friendly"), y haga clic en Continuar.

9d2f625aebcab6af.png

  1. Es posible que se le solicite que habilite Google Analytics, para los fines de este laboratorio de código, su selección no importa.
  2. Después de aproximadamente un minuto, su proyecto de Firebase estará listo. Haga clic en Continuar.

3. Configure el proyecto de muestra

Descarga el código

Ejecute el siguiente comando para clonar el código de muestra para este laboratorio de código. Esto creará una carpeta llamada friendlyeats-android en su máquina:

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

Si no tiene git en su máquina, también puede descargar el código directamente desde GitHub.

Importar el proyecto a Android Studio. Es probable que vea algunos errores de compilación o tal vez una advertencia sobre una falta google-services.json archivo. Corregiremos esto en la siguiente sección.

Agregar configuración de Firebase

  1. En la consola de Firebase , seleccione Visión general del proyecto en el panel de navegación izquierdo. Haga clic en el botón de Android para seleccionar la plataforma. Cuando se le pida un nombre de paquete de uso com.google.firebase.example.fireeats

73d151ed16016421.png

  1. Haga clic en Registro de aplicaciones y siga las instrucciones para descargar el google-services.json archivo y moverlo a la app/ carpeta del código de ejemplo. A continuación, haga clic en Siguiente.

4. Configura los emuladores de Firebase

En este laboratorio de programación que va a utilizar la Firebase emulador suite de emular a nivel local Nube Firestore y otros servicios de base de fuego. Esto proporciona un entorno de desarrollo local seguro, rápido y gratuito para crear su aplicación.

Instala Firebase CLI

En primer lugar tendrá que instalar el Firebase CLI . La forma más sencilla de hacerlo es utilizar npm :

npm install -g firebase-tools

Si usted no tiene npm o experimenta un error, lea las instrucciones de instalación para obtener un binario independiente para su plataforma.

Una vez que haya instalado la CLI, corriendo firebase --version debe reportar una versión de 9.0.0 o superior:

$ firebase --version
9.0.0

Iniciar sesión

Ejecutar firebase login para conectar la CLI a su cuenta de Google. Esto abrirá una nueva ventana del navegador para completar el proceso de inicio de sesión. Asegúrate de elegir la misma cuenta que usaste cuando creaste tu proyecto de Firebase anteriormente.

Desde dentro de la friendlyeats-android plazo carpeta firebase use --add para conectar su proyecto local a su proyecto Firebase. Siga las instrucciones para seleccionar el proyecto que ha creado anteriormente y si pedirá que elija un alias de entrar en default .

5. Ejecute la aplicación

Ahora es el momento de ejecutar Firebase Emulator Suite y la aplicación de Android FriendlyEats por primera vez.

Ejecuta los emuladores

En su terminal desde dentro de la friendlyeats-android plazo directorio de firebase emulators:start a poner en marcha la base del fuego emuladores. Debería ver registros como este:

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

¡Ahora tiene un entorno de desarrollo local completo ejecutándose en su máquina! Asegúrese de dejar este comando en ejecución durante el resto del laboratorio de código, su aplicación de Android deberá conectarse a los emuladores.

Conectar la aplicación a los emuladores

Abra el archivo FirebaseUtil.java en Android Studio. Este archivo contiene la lógica para conectar los SDK de Firebase a los emuladores locales que se ejecutan en su máquina.

En la parte superior del archivo, examine esta línea:

    /** Use emulators only in debug builds **/
    private static final boolean sUseEmulators = BuildConfig.DEBUG;

Estamos utilizando BuildConfig para asegurarse de que sólo se conectan a la emuladores cuando nuestra aplicación se está ejecutando en la debug de modo. Cuando se compila la aplicación en release modo de esta condición será falsa.

Ahora echa un vistazo a la getFirestore() método:

    public static FirebaseFirestore getFirestore() {
        if (FIRESTORE == null) {
            FIRESTORE = FirebaseFirestore.getInstance();

            // Connect to the Cloud Firestore emulator when appropriate. The host '10.0.2.2' is a
            // special IP address to let the Android emulator connect to 'localhost'.
            if (sUseEmulators) {
                FIRESTORE.useEmulator("10.0.2.2", 8080);
            }
        }

        return FIRESTORE;
    }

Podemos ver que se está utilizando la useEmulator(host, port) método para conectar el SDK Firebase al emulador locales Firestore. A lo largo de la aplicación vamos a utilizar FirebaseUtil.getFirestore() para acceder a esta instancia de FirebaseFirestore así que estamos seguros de que estamos siempre conecta con el emulador Firestore cuando se ejecuta en debug de modo.

Ejecutar la aplicación

Si ha agregado el google-services.json archivo correctamente, el proyecto ahora debe compilar. En Android Studio haga clic en Generar> Reconstruir proyecto y asegurarse de que no hay errores restantes.

En Android Studio Ejecutar la aplicación en el emulador de Android. Al principio se le presentará una pantalla de "Iniciar sesión". Puede utilizar cualquier correo electrónico y contraseña para iniciar sesión en la aplicación. Este proceso de inicio de sesión se conecta al emulador de Firebase Authentication, por lo que no se transmiten credenciales reales.

Ahora abre los emuladores de interfaz de usuario navegando a http: // localhost: 4000 en su navegador web. Luego haga clic en la ficha Autenticación y debería ver la cuenta que acaba de crear:

Emulador de autenticación de Firebase

Una vez que haya completado el proceso de inicio de sesión, debería ver la pantalla de inicio de la aplicación:

de06424023ffb4b9.png

Pronto agregaremos algunos datos para poblar la pantalla de inicio.

6. Escribe datos en Firestore

En esta sección, escribiremos algunos datos en Firestore para que podamos completar la pantalla de inicio actualmente vacía.

El modelo de objeto principal de nuestra aplicación es un restaurante (ver model/Restaurant.java ). Los datos de Firestore se dividen en documentos, colecciones y subcolecciones. Vamos a almacenar cada restaurante como un documento en una colección de nivel superior llamado "restaurants" . Para obtener más información sobre el modelo de datos Firestore, leer acerca de documentos y colecciones en la documentación .

Para fines de demostración, agregaremos funcionalidad en la aplicación para crear diez restaurantes aleatorios cuando hagamos clic en el botón "Agregar elementos aleatorios" en el menú adicional. Abra el archivo MainActivity.java y relleno en el onAddItemsClicked() método:

    private void onAddItemsClicked() {
        // Get a reference to the restaurants collection
        CollectionReference restaurants = mFirestore.collection("restaurants");

        for (int i = 0; i < 10; i++) {
            // Get a random Restaurant POJO
            Restaurant restaurant = RestaurantUtil.getRandom(this);

            // Add a new document to the restaurants collection
            restaurants.add(restaurant);
        }
    }

Hay algunas cosas importantes a tener en cuenta sobre el código anterior:

  • Empezamos por conseguir una referencia a la "restaurants" colección. Las colecciones se crean implícitamente cuando se agregan documentos, por lo que no era necesario crear la colección antes de escribir datos.
  • Los documentos se pueden crear utilizando POJO, que usamos para crear cada documento de restaurante.
  • El add() método añade un documento a una colección con una identificación generada automáticamente, así que no es necesario especificar un identificador único para cada restaurante.

Ahora ejecute la aplicación nuevamente y haga clic en el botón "Agregar elementos aleatorios" en el menú adicional para invocar el código que acaba de escribir:

95691e9b71ba55e3.png

Ahora abre los emuladores de interfaz de usuario navegando a http: // localhost: 4000 en su navegador web. Luego haga clic en la pestaña Firestore y debería ver los datos que acaba de agregar:

Emulador de autenticación de Firebase

Estos datos son 100% locales para su máquina. De hecho, ¡tu proyecto real ni siquiera contiene una base de datos de Firestore todavía! Esto significa que es seguro experimentar modificando y eliminando estos datos sin consecuencias.

¡Felicitaciones, acaba de escribir datos en Firestore! En el siguiente paso, aprenderemos cómo mostrar estos datos en la aplicación.

7. Mostrar datos de Firestore

En este paso, aprenderemos cómo recuperar datos de Firestore y mostrarlos en nuestra aplicación. El primer paso para la lectura de datos de Firestore es crear una Query . Modificar el onCreate() método:

        mFirestore = FirebaseUtil.getFirestore();

        // Get the 50 highest rated restaurants
        mQuery = mFirestore.collection("restaurants")
                .orderBy("avgRating", Query.Direction.DESCENDING)
                .limit(LIMIT);

Ahora queremos escuchar la consulta, de modo que obtengamos todos los documentos coincidentes y se nos notifique de futuras actualizaciones en tiempo real. Debido a que nuestro objetivo final es vincular estos datos a un RecyclerView , tenemos que crear un RecyclerView.Adapter clase para escuchar a los datos.

Abra la FirestoreAdapter clase, que se ha aplicado parcialmente ya. En primer lugar, vamos a hacer el adaptador implementar EventListener y definir el onEvent función para que pueda recibir cambios a una consulta Firestore:

public abstract class FirestoreAdapter<VH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<VH>
        implements EventListener<QuerySnapshot> { // Add this "implements"

    // ...

    // Add this method
    @Override
    public void onEvent(QuerySnapshot documentSnapshots,
                        FirebaseFirestoreException e) {

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

        // Dispatch the event
        for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
            // Snapshot of the changed document
            DocumentSnapshot snapshot = change.getDocument();

            switch (change.getType()) {
                case ADDED:
                    // TODO: handle document added
                    break;
                case MODIFIED:
                    // TODO: handle document modified
                    break;
                case REMOVED:
                    // TODO: handle document removed
                    break;
            }
        }

        onDataChanged();
    }

  // ...
}

En la carga inicial del oyente recibirá una ADDED evento para cada nuevo documento. A medida que el conjunto de resultados de la consulta cambia con el tiempo, el oyente recibirá más eventos que contengan los cambios. Ahora terminemos de implementar el oyente. Primero se debe agregar tres nuevos métodos: onDocumentAdded , onDocumentModified , y en onDocumentRemoved :

    protected void onDocumentAdded(DocumentChange change) {
        mSnapshots.add(change.getNewIndex(), change.getDocument());
        notifyItemInserted(change.getNewIndex());
    }

    protected void onDocumentModified(DocumentChange change) {
        if (change.getOldIndex() == change.getNewIndex()) {
            // Item changed but remained in same position
            mSnapshots.set(change.getOldIndex(), change.getDocument());
            notifyItemChanged(change.getOldIndex());
        } else {
            // Item changed and changed position
            mSnapshots.remove(change.getOldIndex());
            mSnapshots.add(change.getNewIndex(), change.getDocument());
            notifyItemMoved(change.getOldIndex(), change.getNewIndex());
        }
    }

    protected void onDocumentRemoved(DocumentChange change) {
        mSnapshots.remove(change.getOldIndex());
        notifyItemRemoved(change.getOldIndex());
    }

A continuación, llamar a estos nuevos métodos de onEvent :

    @Override
    public void onEvent(QuerySnapshot documentSnapshots,
                        FirebaseFirestoreException e) {

        // ...

        // Dispatch the event
        for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
            // Snapshot of the changed document
            DocumentSnapshot snapshot = change.getDocument();

            switch (change.getType()) {
                case ADDED:
                    onDocumentAdded(change); // Add this line
                    break;
                case MODIFIED:
                    onDocumentModified(change); // Add this line
                    break;
                case REMOVED:
                    onDocumentRemoved(change); // Add this line
                    break;
            }
        }

        onDataChanged();
    }

Finalmente aplicar la startListening() método para fijar el oyente:

    public void startListening() {
        if (mQuery != null && mRegistration == null) {
            mRegistration = mQuery.addSnapshotListener(this);
        }
    }

Ahora la aplicación está completamente configurada para leer datos de Firestore. Ejecutar la aplicación de nuevo y debería ver los restaurantes que agregó en el paso anterior:

9e45f40faefce5d0.png

Ahora regrese a la interfaz de usuario del emulador en su navegador y edite uno de los nombres de los restaurantes. ¡Debería verlo cambiar en la aplicación casi al instante!

8. Ordenar y filtrar datos

Actualmente, la aplicación muestra los restaurantes mejor calificados en toda la colección, pero en una aplicación de restaurante real, el usuario querría ordenar y filtrar los datos. Por ejemplo, la aplicación debería poder mostrar "Los mejores restaurantes de mariscos en Filadelfia" o "La pizza menos cara".

Al hacer clic en la barra blanca en la parte superior de la aplicación, aparece un cuadro de diálogo de filtros. En esta sección usaremos consultas de Firestore para que este diálogo funcione:

67898572a35672a5.png

Vamos a editar el onFilter() método de MainActivity.java . Este método acepta un Filters objeto que es un objeto de ayuda que hemos creado para capturar el resultado del diálogo de filtros. Cambiaremos este método para construir una consulta a partir de los filtros:

    @Override
    public void onFilter(Filters filters) {
        // Construct query basic query
        Query query = mFirestore.collection("restaurants");

        // Category (equality filter)
        if (filters.hasCategory()) {
            query = query.whereEqualTo("category", filters.getCategory());
        }

        // City (equality filter)
        if (filters.hasCity()) {
            query = query.whereEqualTo("city", filters.getCity());
        }

        // Price (equality filter)
        if (filters.hasPrice()) {
            query = query.whereEqualTo("price", filters.getPrice());
        }

        // Sort by (orderBy with direction)
        if (filters.hasSortBy()) {
            query = query.orderBy(filters.getSortBy(), filters.getSortDirection());
        }

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

        // Update the query
        mQuery = query;
        mAdapter.setQuery(query);

        // Set header
        mCurrentSearchView.setText(Html.fromHtml(filters.getSearchDescription(this)));
        mCurrentSortByView.setText(filters.getOrderDescription(this));

        // Save filters
        mViewModel.setFilters(filters);
    }

En el fragmento anterior construimos una Query objeto uniendo where y orderBy cláusulas para que coincida con los filtros indicados.

Ejecutar la aplicación de nuevo y seleccione el filtro siguiente para mostrar los restaurantes de bajo precio más populares:

7a67a8a400c80c50.png

Ahora debería ver una lista filtrada de restaurantes que contiene solo opciones de bajo precio:

a670188398c3c59.png

Si ha llegado hasta aquí, ¡ahora ha creado una aplicación de visualización de recomendaciones de restaurantes en pleno funcionamiento en Firestore! Ahora puede ordenar y filtrar restaurantes en tiempo real. En las siguientes secciones, publicaremos reseñas y seguridad en la aplicación.

9. Organice los datos en subcolecciones

En esta sección, agregaremos calificaciones a la aplicación para que los usuarios puedan revisar sus restaurantes favoritos (o menos favoritos).

Colecciones y subcolecciones

Hasta ahora, hemos almacenado todos los datos de restaurantes en una colección de alto nivel llamada "restaurantes". Cuando un usuario a calificado de un restaurante que queremos añadir un nuevo Rating de objetos a los restaurantes. Para esta tarea usaremos una subcolección. Puede pensar en una subcolección como una colección que se adjunta a un documento. Por lo tanto, cada documento de restaurante tendrá una subcolección de calificaciones llena de documentos de calificación. Las subcolecciones ayudan a organizar los datos sin sobrecargar nuestros documentos ni requerir consultas complejas.

Para acceder a una subcolección, llamada .collection() en el documento de nivel superior:

CollectionReference subRef = mFirestore.collection("restaurants")
        .document("abc123")
        .collection("ratings");

Puede acceder y consultar una subcolección al igual que con una colección de nivel superior, no hay limitaciones de tamaño ni cambios de rendimiento. Puede leer más sobre el modelo de datos Firestore aquí .

Escribir datos en una transacción

Adición de una Rating a la subcolección adecuada sólo requiere llamar .add() , pero también tenemos que actualizar el Restaurant calificación y el número de calificaciones promedio de objeto para reflejar los nuevos datos. Si utilizamos operaciones independientes para realizar estos dos cambios, hay una serie de condiciones de carrera que podrían resultar en datos obsoletos o incorrectos.

Para garantizar que las calificaciones se agreguen correctamente, utilizaremos una transacción para agregar calificaciones a un restaurante. Esta transacción realizará algunas acciones:

  • Lea la calificación actual del restaurante y calcule la nueva
  • Agregue la calificación a la subcolección
  • Actualizar la calificación promedio del restaurante y el número de calificaciones

Abrir RestaurantDetailActivity.java e implementar el addRating función:

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

        // In a transaction, add the new rating and update the aggregate totals
        return mFirestore.runTransaction(new Transaction.Function<Void>() {
            @Override
            public Void apply(Transaction transaction)
                    throws FirebaseFirestoreException {

                Restaurant restaurant = transaction.get(restaurantRef)
                        .toObject(Restaurant.class);

                // Compute new number of ratings
                int newNumRatings = restaurant.getNumRatings() + 1;

                // Compute new average rating
                double oldRatingTotal = restaurant.getAvgRating() *
                        restaurant.getNumRatings();
                double newAvgRating = (oldRatingTotal + rating.getRating()) /
                        newNumRatings;

                // Set new restaurant info
                restaurant.setNumRatings(newNumRatings);
                restaurant.setAvgRating(newAvgRating);

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

                return null;
            }
        });
    }

El addRating() función devuelve una Task que representa toda la transacción. En el onRating() oyentes de función se añaden a la tarea de responder al resultado de la transacción.

Ahora Ejecutar la aplicación de nuevo y haga clic en uno de los restaurantes, lo que debería hacer que aparezca la pantalla del restaurante detalle. Haga clic en el botón + para empezar a añadir un comentario. Agregue una reseña seleccionando varias estrellas e ingresando un texto.

78fa16cdf8ef435a.png

Golpear Enviar dará inicio a la transacción. Cuando se complete la transacción, verá su reseña a continuación y una actualización del recuento de reseñas del restaurante:

f9e670f40bd615b0.png

¡Felicitaciones! Ahora tiene una aplicación de revisión de restaurantes local, social y móvil construida en Cloud Firestore. Escuché que esos son muy populares en estos días.

10. Asegure sus datos

Hasta ahora no hemos considerado la seguridad de esta aplicación. ¿Cómo sabemos que los usuarios solo pueden leer y escribir los datos propios correctos? FireStore datbases se aseguran mediante un archivo de configuración llamado Reglas de Seguridad .

Abra la firestore.rules archivo, debería ver lo siguiente:

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

Cambio de dejar que estas reglas para evitar que los datos no deseados acesss o cambios, abra la firestore.rules archivo y reemplazar el contenido con lo siguiente:

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

Estas reglas restringen el acceso para garantizar que los clientes solo realicen cambios seguros. Por ejemplo, las actualizaciones de un documento de restaurante solo pueden cambiar las calificaciones, no el nombre o cualquier otro dato inmutable. Las calificaciones solo se pueden crear si el ID de usuario coincide con el usuario que inició sesión, lo que evita la suplantación de identidad.

Para leer más sobre las reglas de seguridad, visite la documentación .

11. Conclusión

Ahora ha creado una aplicación con todas las funciones en la parte superior de Firestore. Aprendió sobre las funciones más importantes de Firestore, que incluyen:

  • Documentos y colecciones
  • Leer y escribir datos
  • Ordenar y filtrar con consultas
  • Subcolecciones
  • Actas

Aprende más

Para seguir aprendiendo sobre Firestore, estos son algunos buenos lugares para comenzar:

La aplicación de restaurante en este codelab se basó en la aplicación de ejemplo "Friendly Eats". Puede examinar el código fuente para esa aplicación aquí .

Opcional: implementar en producción

Hasta ahora, esta aplicación solo ha utilizado Firebase Emulator Suite. Si desea aprender cómo implementar esta aplicación en un proyecto de Firebase real, continúe con el siguiente paso.

12. (Opcional) Implemente su aplicación

Hasta ahora, esta aplicación ha sido completamente local, todos los datos están contenidos en Firebase Emulator Suite. En esta sección, aprenderá a configurar su proyecto de Firebase para que esta aplicación funcione en producción.

Autenticación de Firebase

En la base del fuego CONSLE vaya a la sección Autenticación y vaya a la sesión en la ficha Proveedores .

Habilite el método de inicio de sesión por correo electrónico:

334ef7f6ff4da4ce.png

Firestore

Crear base de datos

Vaya a la sección de Firestore de la consola y haga clic en Crear base de datos:

  1. Cuando se le solicite sobre Reglas de seguridad de optar por iniciar en modo bloqueado, vamos a actualizar las reglas pronto.
  2. Elija la ubicación de la base de datos que le gustaría usar para su aplicación. Tenga en cuenta que la selección de una ubicación de base de datos es una decisión permanente y cambiarla, tendrá que crear un nuevo proyecto. Para obtener más información sobre la elección de una ubicación del proyecto, consulte la documentación .

Implementar reglas

Para implementar las reglas de seguridad que escribió anteriormente, ejecute el siguiente comando en el directorio de codelab:

$ firebase deploy --only firestore:rules

Esto desplegará el contenido de firestore.rules a su proyecto, que se puede confirmar mediante la navegación a la pestaña Reglas en la consola.

Implementar índices

La aplicación FriendlyEats tiene una clasificación y un filtrado complejos que requieren una serie de índices compuestos personalizados. Estos pueden ser creados a mano en la consola Firebase pero es más simple de escribir sus definiciones en el firestore.indexes.json archivo y desplegarlas usando la base del fuego CLI.

Si abre la firestore.indexes.json archivo verá que ya se dispone de los índices requeridos:

{
  "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": []
}

Para implementar estos índices, ejecute el siguiente comando:

$ firebase deploy --only firestore:indexes

Tenga en cuenta que la creación de índices no es instantánea, puede monitorear el progreso en la consola de Firebase.

Configurar la aplicación

En el FirebaseUtil clase hemos configurado el SDK Firebase para conectarse a los emuladores, cuando en el modo de depuración:

public class FirebaseUtil {

    /** Use emulators only in debug builds **/
    private static final boolean sUseEmulators = BuildConfig.DEBUG;

    // ...
}

Si desea probar su aplicación con su proyecto de Firebase real, puede:

  1. Cree la aplicación en modo de lanzamiento y ejecútela en un dispositivo.
  2. Cambio temporal de sUseEmulators a false y ejecutar la aplicación de nuevo.

Tenga en cuenta que puede que tenga que cerrar la sesión de la aplicación y acceder de nuevo con el fin de conectar correctamente a la producción.