1. Visão geral
Metas
Neste codelab, você vai criar um app de recomendação de restaurantes no Android com suporte do Cloud Firestore. Você aprenderá o seguinte:
- Ler e gravar dados no Firestore usando um app Android
- Detectar mudanças nos dados do Firestore em tempo real
- Usar o Firebase Authentication e as regras de segurança para proteger os dados do Firestore
- Gravar consultas complexas do Firestore
Pré-requisitos
Antes de iniciar este codelab, confira se você tem:
- Android Studio Flamingo ou uma versão mais recente
- Um Android Emulator com a API 19 ou mais recente.
- Node.js versão 16 ou mais recente
- Java versão 17 ou mais recente
2. Criar um projeto do Firebase
- Faça login no Console do Firebase com sua Conta do Google.
- No Console do Firebase, clique em Adicionar projeto.
- Conforme mostrado na captura de tela abaixo, insira um nome para seu projeto do Firebase (por exemplo, "Friendly Eats") e clique em Continuar.
- Talvez seja necessário ativar o Google Analytics. Neste codelab, sua seleção não importa.
- Depois de aproximadamente um minuto, o projeto do Firebase estará pronto. Clique em Continuar.
3. Configurar o projeto de amostra
Fazer o download do código
Execute o comando a seguir para clonar o exemplo de código para este codelab. Isso vai criar uma pasta chamada friendlyeats-android
na sua máquina:
$ git clone https://github.com/firebase/friendlyeats-android
Se você não tiver o git na sua máquina, também poderá fazer o download do código diretamente do GitHub.
Adicionar a configuração do Firebase
- No Console do Firebase, selecione Visão geral do projeto no painel de navegação à esquerda. Clique no botão Android para selecionar a plataforma. Quando um nome de pacote for solicitado, use
com.google.firebase.example.fireeats
.
- Clique em Register App e siga as instruções para fazer o download do arquivo
google-services.json
e mova-o para a pastaapp/
do código que você acabou de baixar. Depois, clique em Avançar.
Importar o projeto
Abra o Android Studio. Clique em File > New > Import Project e selecione a pasta friendlyeats-android.
4. Configurar os emuladores do Firebase
Neste codelab, você vai usar o Pacote do emulador do Firebase para emular localmente o Cloud Firestore e outros serviços do Firebase. Isso oferece um ambiente de desenvolvimento local seguro, rápido e sem custos financeiros para criar seu app.
Instalar a CLI do Firebase
Primeiro, você precisa instalar a CLI do Firebase. Se você estiver usando macOS ou Linux, execute o seguinte comando cURL:
curl -sL https://firebase.tools | bash
Se você estiver usando o Windows, leia as instruções de instalação para conseguir um binário independente ou instalar pelo npm
.
Depois de instalar a CLI, executar firebase --version
informará uma versão de 9.0.0
ou mais recente:
$ firebase --version 9.0.0
Fazer login
Execute firebase login
para conectar a CLI à sua Conta do Google. Uma nova janela do navegador será aberta para concluir o processo de login. Escolha a mesma conta que você usou para criar seu projeto do Firebase anteriormente.
Vincular seu projeto
Na pasta friendlyeats-android
, execute firebase use --add
para conectar seu projeto local ao projeto do Firebase. Siga as instruções para selecionar o projeto criado anteriormente e, se for solicitado que escolha um alias, digite default
.
5. Execute o aplicativo
Agora é hora de executar o Pacote de emuladores do Firebase e o app Android do FriendlyEats pela primeira vez.
Executar os emuladores
No terminal, no diretório friendlyeats-android
, execute firebase emulators:start
para iniciar os emuladores do Firebase. Você vai encontrar registros como estes:
$ 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.
Agora você tem um ambiente de desenvolvimento local completo em execução na sua máquina. Deixe esse comando em execução durante o resto do codelab. O app Android vai precisar se conectar aos emuladores.
Conectar app aos emuladores
Abra os arquivos util/FirestoreInitializer.kt
e util/AuthInitializer.kt
no Android Studio. Esses arquivos contêm a lógica para conectar os SDKs do Firebase aos emuladores locais em execução na sua máquina, após a inicialização do aplicativo.
No método create()
da classe FirestoreInitializer
, examine este código:
// Use emulators only in debug builds
if (BuildConfig.DEBUG) {
firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
}
Estamos usando o BuildConfig
para garantir que só nos conectemos aos emuladores quando nosso app estiver em execução no modo debug
. Quando compilamos o app no modo release
, essa condição é falsa.
É possível ver que ele usa o método useEmulator(host, port)
para conectar o SDK do Firebase ao emulador local do Firestore. No app, vamos usar FirebaseUtil.getFirestore()
para acessar essa instância de FirebaseFirestore
, garantindo que sempre nos conectamos ao emulador do Firestore ao executar no modo debug
.
Execute o aplicativo
Se você adicionou o arquivo google-services.json
corretamente, o projeto será compilado. No Android Studio, clique em Build > Rebuild Project e verifique se não há mais erros.
No Android Studio, execute o app no Android Emulator. No início, você vai encontrar uma tela de "Login". Você pode usar qualquer e-mail e senha para fazer login no app. Esse processo de login está se conectando ao emulador do Firebase Authentication, então nenhuma credencial real está sendo transmitida.
Acesse http://localhost:4000 no navegador da Web para abrir a interface dos emuladores. Em seguida, clique na guia Autenticação para ver a conta que acabou de criar:
Depois de concluir o processo de login, a tela inicial do app vai aparecer:
Em breve, adicionaremos alguns dados para preencher a tela inicial.
6. Gravar dados no Firestore
Nesta seção, vamos gravar alguns dados no Firestore para que possamos preencher a tela inicial vazia.
O principal objeto de modelo no nosso app é um restaurante (consulte model/Restaurant.kt
). Os dados do Firestore são divididos em documentos, coleções e subcoleções. Armazenaremos cada restaurante como um documento em uma coleção de nível superior chamada "restaurants"
. Para saber mais sobre o modelo de dados do Firestore, leia sobre documentos e coleções na documentação.
Para fins de demonstração, vamos adicionar a funcionalidade no app para criar 10 restaurantes aleatórios quando clicarmos no botão "Add Random Items" (Adicionar itens aleatórios). no menu flutuante. Abra o arquivo MainFragment.kt
e substitua o conteúdo no método onAddItemsClicked()
por:
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)
}
}
Há algumas coisas importantes a serem observadas sobre o código acima:
- Começamos acessando uma referência à coleção
"restaurants"
. As coleções são criadas implicitamente quando documentos são adicionados. Por isso, não foi necessário criar a coleção antes de gravar dados. - Os documentos podem ser criados usando classes de dados Kotlin, que usamos para criar cada documento de restaurante.
- O método
add()
adiciona um documento a uma coleção com um ID gerado automaticamente. Por isso, não foi necessário especificar um ID exclusivo para cada restaurante.
Agora, execute o app novamente e clique no botão "Add Random Items" (Adicionar itens aleatórios). no menu flutuante (no canto superior direito) para invocar o código que você acabou de escrever:
Acesse http://localhost:4000 no navegador da Web para abrir a interface dos emuladores. Clique na guia Firestore para ver os dados que você acabou de adicionar:
Esses dados são 100% locais para sua máquina. Na verdade, seu projeto real ainda nem tem um banco de dados do Firestore. Isso significa que é seguro modificar e excluir esses dados sem consequências.
Parabéns, você acabou de gravar dados no Firestore. Na próxima etapa, vamos aprender a mostrar esses dados no app.
7. Mostrar dados do Firestore
Nesta etapa, vamos aprender a recuperar dados do Firestore e exibir no app. A primeira etapa para ler dados do Firestore é criar um Query
. Abra o arquivo MainFragment.kt
e adicione o seguinte código ao início do método onViewCreated()
:
// Firestore
firestore = Firebase.firestore
// Get the 50 highest rated restaurants
query = firestore.collection("restaurants")
.orderBy("avgRating", Query.Direction.DESCENDING)
.limit(LIMIT.toLong())
Agora queremos ouvir a consulta para receber todos os documentos correspondentes e ser notificados sobre futuras atualizações em tempo real. Como nosso objetivo final é vincular esses dados a um RecyclerView
, precisamos criar uma classe RecyclerView.Adapter
para ouvir os dados.
Abra a classe FirestoreAdapter
, que já foi parcialmente implementada. Primeiro, vamos fazer o adaptador implementar EventListener
e definir a função onEvent
para que ele possa receber atualizações em uma consulta do 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()
}
// ...
}
No carregamento inicial, o listener vai receber um evento ADDED
para cada novo documento. À medida que o conjunto de resultados da consulta muda ao longo do tempo, o listener recebe mais eventos que contêm as alterações. Agora vamos concluir a implementação do listener. Primeiro, adicione três novos métodos: onDocumentAdded
, onDocumentModified
e 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)
}
Em seguida, chame estes novos métodos 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()
}
Por fim, implemente o método startListening()
para anexar o listener:
fun startListening() {
if (registration == null) {
registration = query.addSnapshotListener(this)
}
}
Agora o app está totalmente configurado para ler dados do Firestore. Execute o app novamente para ver os restaurantes adicionados na etapa anterior:
Volte para a interface do emulador no navegador e edite um dos nomes de restaurante. A mudança vai aparecer no app quase instantaneamente.
8. Classificar e filtrar dados
No momento, o app mostra os restaurantes com as melhores avaliações em toda a coleção, mas em um app de restaurante real, o usuário quer classificar e filtrar os dados. Por exemplo, o app precisa mostrar "Melhores restaurantes de frutos do mar em Filadélfia" ou "Pizza mais barata".
Clicar na barra branca na parte de cima do app mostra uma caixa de diálogo de filtros. Nesta seção, vamos usar consultas do Firestore para fazer com que essa caixa de diálogo funcione:
Vamos editar o método onFilter()
da MainFragment.kt
. Esse método aceita um objeto Filters
, que é um objeto auxiliar criado para capturar a saída da caixa de diálogo de filtros. Vamos mudar esse método para criar uma consulta com base nos filtros:
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
}
No snippet acima, criamos um objeto Query
anexando cláusulas where
e orderBy
para corresponder aos filtros fornecidos.
Execute o app novamente e selecione o filtro abaixo para mostrar os restaurantes de baixo preço mais conhecidos:
Agora você verá uma lista filtrada de restaurantes com apenas opções de preço baixo:
Se você chegou até aqui, já criou um app de visualização de recomendações de restaurantes totalmente funcional no Firestore. Agora é possível classificar e filtrar restaurantes em tempo real. Nas próximas seções, vamos adicionar avaliações aos restaurantes e regras de segurança ao app.
9. Organizar dados em subcoleções
Nesta seção, adicionaremos classificações ao aplicativo para que os usuários possam avaliar seus restaurantes favoritos (ou menos).
Coleções e subcoleções
Até agora, armazenamos todos os dados do restaurante em uma coleção de nível superior chamada "restaurantes". Quando um usuário avalia um restaurante, queremos adicionar um novo objeto Rating
aos restaurantes. Para esta tarefa, usaremos uma subcoleção. Pense em uma subcoleção como uma coleção anexada a um documento. Assim, cada documento de restaurante terá uma subcoleção de classificações cheia de documentos de classificação. As subcoleções ajudam a organizar dados sem aumentar o tamanho dos documentos ou exigir consultas complexas.
Para acessar uma subcoleção, chame .collection()
no documento pai:
val subRef = firestore.collection("restaurants")
.document("abc123")
.collection("ratings")
É possível acessar e consultar uma subcoleção, assim como em uma coleção de nível superior, sem limitações de tamanho ou alterações de desempenho. Leia mais sobre o modelo de dados do Firestore aqui.
Como gravar dados em uma transação
Para adicionar um Rating
à subcoleção adequada, é necessário chamar apenas .add()
. No entanto, também precisamos atualizar a classificação média e o número de avaliações do objeto Restaurant
para refletir os novos dados. Se usarmos operações separadas para fazer essas duas alterações, haverá várias condições de corrida que podem resultar em dados desatualizados ou incorretos.
Para garantir que as classificações sejam adicionadas corretamente, usaremos uma transação para adicionar avaliações a um restaurante. Essa transação vai realizar algumas ações:
- Leia a classificação atual do restaurante e calcule a nova
- Adicionar a classificação à subcoleção
- Atualizar a classificação média e o número de avaliações do restaurante
Abra RestaurantDetailFragment.kt
e implemente a função 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
}
}
A função addRating()
retorna um Task
que representa toda a transação. Na função onRating()
, os listeners são adicionados à tarefa para responder ao resultado da transação.
Agora, execute o app novamente e clique em um dos restaurantes, o que abrirá a tela de detalhes do restaurante. Clique no botão + para começar a adicionar um comentário. Adicione uma avaliação escolhendo um número de estrelas e digitando um texto.
Clicar em Enviar inicia a transação. Quando a transação for concluída, sua avaliação vai aparecer abaixo e a contagem de avaliações do restaurante será atualizada:
Parabéns! Agora você tem um aplicativo de avaliação de restaurantes social, local e móvel criado no Cloud Firestore. Ouvi dizer que eles são muito populares hoje em dia.
10. Proteger seus dados
Até agora, não consideramos a segurança do aplicativo. Como sabemos que os usuários só podem ler e gravar os próprios dados? Os bancos de dados do Firestore são protegidos por um arquivo de configuração chamado Regras de segurança.
Abra o arquivo firestore.rules
. Você verá o seguinte:
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;
}
}
}
Vamos mudar essas regras para evitar acessos ou alterações de dados indesejados. Abra o arquivo firestore.rules
e substitua o conteúdo por este:
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;
}
}
}
}
Essas regras restringem o acesso para garantir que os clientes só façam mudanças seguras. Por exemplo, atualizações no documento de um restaurante só podem mudar as avaliações, não o nome ou outros dados imutáveis. As notas só poderão ser criadas se o ID do usuário for o do usuário conectado, o que evita o spoofing.
Para saber mais sobre as regras de segurança, acesse a documentação.
11. Conclusão
Agora você criou um app completo com o Firestore. Você aprendeu sobre os recursos mais importantes do Firestore, incluindo:
- Documentos e coleções
- Ler e gravar dados
- Classificar e filtrar com consultas
- Subcoleções
- Transações
Saiba mais
Para continuar aprendendo sobre o Firestore, confira estes recursos:
O app de restaurantes deste codelab foi baseado no projeto "Friendly Eats" aplicativo de exemplo. Você pode navegar pelo código-fonte desse app aqui.
Opcional: implantar na produção
Até agora, esse app só usou o Pacote do emulador do Firebase. Se você quiser aprender a implantar esse app em um projeto real do Firebase, siga para a próxima etapa.
12. Implantar o app (opcional)
Até agora, o app foi totalmente local. Todos os dados estão no Pacote de emuladores do Firebase. Nesta seção, você vai aprender a configurar seu projeto do Firebase para que o app funcione na produção.
Firebase Authentication
No console do Firebase, acesse a seção Autenticação e clique em Começar. Acesse a guia Método de login e selecione a opção E-mail/senha em Provedores nativos.
Ative o método de login E-mail/senha e clique em Salvar.
Firestore
Criar banco de dados
Navegue até a seção Banco de dados do Firestore no console e clique em Criar banco de dados:
- Quando você escolher iniciar as regras de segurança no Modo de produção, vamos atualizar essas regras em breve.
- Escolha o local do banco de dados que você quer usar para o app. A seleção de um local de banco de dados é uma decisão permanente, e para mudá-la, você terá que criar um novo projeto. Para mais informações sobre como escolher um local de projeto, consulte a documentação.
Implantar regras
Para implantar as regras de segurança que você criou, execute o seguinte comando no diretório do codelab:
$ firebase deploy --only firestore:rules
Isso implantará o conteúdo de firestore.rules
no seu projeto. Para confirmar, acesse a guia Regras no console.
Implantar índices
O app FriendlyEats tem classificação e filtragem complexas, o que exige vários índices compostos personalizados. Elas podem ser criadas manualmente no Console do Firebase, mas é mais simples escrever as definições no arquivo firestore.indexes.json
e implantá-las usando a CLI do Firebase.
Se você abrir o arquivo firestore.indexes.json
, vai notar que os índices necessários já foram fornecidos:
{
"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 implantar esses índices, execute o seguinte comando:
$ firebase deploy --only firestore:indexes
A criação do índice não é instantânea. Você pode monitorar o progresso no Console do Firebase.
Configure o app
Nos arquivos util/FirestoreInitializer.kt
e util/AuthInitializer.kt
, configuramos o SDK do Firebase para se conectar aos emuladores no modo de depuração:
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
}
Se você quiser testar seu app com o projeto real do Firebase, faça o seguinte:
- Crie o app no modo de lançamento e execute-o em um dispositivo.
- Substitua
BuildConfig.DEBUG
temporariamente porfalse
e execute o app novamente.
Talvez seja necessário sair do app e fazer login novamente para se conectar corretamente à produção.