Confira tudo que foi anunciado no Firebase Summit e veja como usar o Firebase para acelerar o desenvolvimento de apps e executar os aplicativos com confiança. Saiba mais

Recursos offline em plataformas da Apple

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Os aplicativos do Firebase funcionam mesmo se seu aplicativo perder temporariamente a conexão de rede. Além disso, o Firebase fornece ferramentas para manter os dados localmente, gerenciar a presença e lidar com a latência.

Persistência de disco

Os aplicativos Firebase lidam automaticamente com interrupções temporárias de rede. Os dados armazenados em cache estão disponíveis off-line e o Firebase reenvia todas as gravações quando a conectividade de rede é restaurada.

Quando você habilita a persistência de disco, seu aplicativo grava os dados localmente no dispositivo para que seu aplicativo possa manter o estado off-line, mesmo que o usuário ou o sistema operacional reinicie o aplicativo.

Você pode ativar a persistência de disco com apenas uma linha de código.

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
Database.database().isPersistenceEnabled = true

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
[FIRDatabase database].persistenceEnabled = YES;

Comportamento de Persistência

Ao habilitar a persistência, todos os dados que o cliente do Firebase Realtime Database sincronizaria enquanto estiver on-line persistem no disco e ficam disponíveis off-line, mesmo quando o usuário ou o sistema operacional reinicia o aplicativo. Isso significa que seu aplicativo funciona como funcionaria online usando os dados locais armazenados no cache. Os retornos de chamada do ouvinte continuarão a disparar para atualizações locais.

O cliente Firebase Realtime Database mantém automaticamente uma fila de todas as operações de gravação executadas enquanto seu aplicativo está off-line. Quando a persistência está habilitada, essa fila também é mantida no disco para que todas as suas gravações estejam disponíveis quando o usuário ou o sistema operacional reiniciar o aplicativo. Quando o aplicativo recupera a conectividade, todas as operações são enviadas para o servidor Firebase Realtime Database.

Se seu aplicativo usa Firebase Authentication , o cliente do Firebase Realtime Database mantém o token de autenticação do usuário nas reinicializações do aplicativo. Se o token de autenticação expirar enquanto seu aplicativo estiver offline, o cliente pausará as operações de gravação até que seu aplicativo reautentique o usuário, caso contrário, as operações de gravação poderão falhar devido a regras de segurança.

Mantendo os dados atualizados

O Firebase Realtime Database sincroniza e armazena uma cópia local dos dados para ouvintes ativos. Além disso, você pode manter locais específicos sincronizados.

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
let scoresRef = Database.database().reference(withPath: "scores")
scoresRef.keepSynced(true)

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"];
[scoresRef keepSynced:YES];

O cliente do Firebase Realtime Database baixa automaticamente os dados nesses locais e os mantém sincronizados, mesmo que a referência não tenha ouvintes ativos. Você pode desativar a sincronização com a seguinte linha de código.

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
scoresRef.keepSynced(false)

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
[scoresRef keepSynced:NO];

Por padrão, 10 MB de dados sincronizados anteriormente são armazenados em cache. Isso deve ser suficiente para a maioria dos aplicativos. Se o cache ultrapassar seu tamanho configurado, o Firebase Realtime Database limpará os dados que foram usados ​​menos recentemente. Os dados mantidos em sincronia não são removidos do cache.

Consultar dados off-line

O Firebase Realtime Database armazena os dados retornados de uma consulta para uso off-line. Para consultas construídas off-line, o Firebase Realtime Database continua a funcionar para dados carregados anteriormente. Se os dados solicitados não foram carregados, o Firebase Realtime Database carrega os dados do cache local. Quando a conectividade de rede estiver disponível novamente, os dados serão carregados e refletirão a consulta.

Por exemplo, este código consulta os últimos quatro itens em um Firebase Realtime Database de pontuações

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
let scoresRef = Database.database().reference(withPath: "scores")
scoresRef.queryOrderedByValue().queryLimited(toLast: 4).observe(.childAdded) { snapshot in
  print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")")
}

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"];
[[[scoresRef queryOrderedByValue] queryLimitedToLast:4]
    observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
      NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value);
    }];

Suponha que o usuário perca a conexão, fique offline e reinicie o aplicativo. Ainda offline, o aplicativo consulta os dois últimos itens do mesmo local. Esta consulta retornará com sucesso os dois últimos itens porque o aplicativo carregou todos os quatro itens na consulta acima.

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
scoresRef.queryOrderedByValue().queryLimited(toLast: 2).observe(.childAdded) { snapshot in
  print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")")
}

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
[[[scoresRef queryOrderedByValue] queryLimitedToLast:2]
    observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
      NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value);
    }];

No exemplo anterior, o cliente do Firebase Realtime Database gera eventos 'filhos adicionados' para os dois dinossauros com pontuação mais alta, usando o cache persistente. Mas não gerará um evento de 'valor', pois o aplicativo nunca executou essa consulta enquanto estiver online.

Se o aplicativo solicitar os últimos seis itens enquanto estiver off-line, ele obterá eventos 'filhos adicionados' para os quatro itens em cache imediatamente. Quando o dispositivo volta a ficar on-line, o cliente do Firebase Realtime Database sincroniza com o servidor e obtém os dois últimos eventos 'filhos adicionados' e 'valor' para o aplicativo.

Lidando com transações off-line

Todas as transações executadas enquanto o aplicativo está offline são enfileiradas. Depois que o aplicativo recupera a conectividade de rede, as transações são enviadas para o servidor Realtime Database.

Gerenciando Presença

Em aplicações de tempo real, muitas vezes é útil detectar quando os clientes se conectam e desconectam. Por exemplo, você pode querer marcar um usuário como 'offline' quando seu cliente se desconectar.

Os clientes do Firebase Database fornecem primitivas simples que você pode usar para gravar no banco de dados quando um cliente se desconecta dos servidores do Firebase Database. Essas atualizações ocorrem independentemente de o cliente se desconectar corretamente ou não, portanto, você pode confiar nelas para limpar os dados mesmo se uma conexão cair ou um cliente travar. Todas as operações de gravação, incluindo configuração, atualização e remoção, podem ser executadas após uma desconexão.

Aqui está um exemplo simples de gravação de dados após a desconexão usando a primitiva onDisconnect :

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
let presenceRef = Database.database().reference(withPath: "disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnectSetValue("I disconnected!")

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
FIRDatabaseReference *presenceRef = [[FIRDatabase database] referenceWithPath:@"disconnectmessage"];
// Write a string when this client loses connection
[presenceRef onDisconnectSetValue:@"I disconnected!"];

Como funciona o onDisconnect

Quando você estabelece uma operação onDisconnect() , a operação reside no servidor Firebase Realtime Database. O servidor verifica a segurança para garantir que o usuário possa executar o evento de gravação solicitado e informa ao seu aplicativo se ele é inválido. O servidor então monitora a conexão. Se a qualquer momento a conexão atingir o tempo limite ou for fechada ativamente pelo cliente do Realtime Database, o servidor verificará a segurança uma segunda vez (para garantir que a operação ainda seja válida) e então invocará o evento.

Seu aplicativo pode usar o retorno de chamada na operação de gravação para garantir que o onDisconnect foi anexado corretamente:

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
presenceRef.onDisconnectRemoveValue { error, reference in
  if let error = error {
    print("Could not establish onDisconnect event: \(error)")
  }
}

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
[presenceRef onDisconnectRemoveValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *reference) {
  if (error != nil) {
    NSLog(@"Could not establish onDisconnect event: %@", error);
  }
}];

Um evento onDisconnect também pode ser cancelado chamando .cancel() :

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
presenceRef.onDisconnectSetValue("I disconnected")
// some time later when we change our minds
presenceRef.cancelDisconnectOperations()

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
[presenceRef onDisconnectSetValue:@"I disconnected"];
// some time later when we change our minds
[presenceRef cancelDisconnectOperations];

Detectando o estado da conexão

Para muitos recursos relacionados à presença, é útil que seu aplicativo saiba quando está online ou offline. O Firebase Realtime Database fornece um local especial em /.info/connected , que é atualizado sempre que o estado da conexão do cliente do Firebase Realtime Database muda. Aqui está um exemplo:

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
let connectedRef = Database.database().reference(withPath: ".info/connected")
connectedRef.observe(.value, with: { snapshot in
  if snapshot.value as? Bool ?? false {
    print("Connected")
  } else {
    print("Not connected")
  }
})

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
FIRDatabaseReference *connectedRef = [[FIRDatabase database] referenceWithPath:@".info/connected"];
[connectedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  if([snapshot.value boolValue]) {
    NSLog(@"connected");
  } else {
    NSLog(@"not connected");
  }
}];

/.info/connected é um valor booleano que não é sincronizado entre os clientes do Realtime Database porque o valor depende do estado do cliente. Em outras palavras, se um cliente lê /.info/connected como falso, isso não garante que outro cliente também leia falso.

Lidando com a latência

Carimbos de data/hora do servidor

Os servidores Firebase Realtime Database fornecem um mecanismo para inserir timestamps gerados no servidor como dados. Esse recurso, combinado com onDisconnect , fornece uma maneira fácil de anotar com segurança a hora em que um cliente do Realtime Database foi desconectado:

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
let userLastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline")
userLastOnlineRef.onDisconnectSetValue(ServerValue.timestamp())

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
FIRDatabaseReference *userLastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"];
[userLastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]];

Inclinação do relógio

Embora firebase.database.ServerValue.TIMESTAMP seja muito mais preciso e preferível para a maioria das operações de leitura/gravação, ocasionalmente pode ser útil estimar a inclinação do relógio do cliente em relação aos servidores do Firebase Realtime Database. Você pode anexar um retorno de chamada ao local /.info/serverTimeOffset para obter o valor, em milissegundos, que os clientes do Firebase Realtime Database adicionam ao horário local relatado (hora da época em milissegundos) para estimar a hora do servidor. Observe que a precisão desse deslocamento pode ser afetada pela latência da rede e, portanto, é útil principalmente para descobrir grandes discrepâncias (> 1 segundo) no horário do relógio.

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
let offsetRef = Database.database().reference(withPath: ".info/serverTimeOffset")
offsetRef.observe(.value, with: { snapshot in
  if let offset = snapshot.value as? TimeInterval {
    print("Estimated server time in milliseconds: \(Date().timeIntervalSince1970 * 1000 + offset)")
  }
})

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
FIRDatabaseReference *offsetRef = [[FIRDatabase database] referenceWithPath:@".info/serverTimeOffset"];
[offsetRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  NSTimeInterval offset = [(NSNumber *)snapshot.value doubleValue];
  NSTimeInterval estimatedServerTimeMs = [[NSDate date] timeIntervalSince1970] * 1000.0 + offset;
  NSLog(@"Estimated server time: %0.3f", estimatedServerTimeMs);
}];

Exemplo de aplicativo de presença

Combinando operações de desconexão com monitoramento do estado da conexão e carimbos de data/hora do servidor, você pode criar um sistema de presença do usuário. Nesse sistema, cada usuário armazena dados em um local de banco de dados para indicar se um cliente do Realtime Database está online ou não. Os clientes definem esse local como verdadeiro quando ficam online e um carimbo de data/hora quando se desconectam. Esse carimbo de data/hora indica a última vez que o usuário em questão esteve online.

Observe que seu aplicativo deve enfileirar as operações de desconexão antes que um usuário seja marcado como online, para evitar quaisquer condições de corrida caso a conexão de rede do cliente seja perdida antes que ambos os comandos possam ser enviados ao servidor.

Aqui está um sistema simples de presença do usuário:

Rápido

Observação: este produto Firebase não está disponível no destino App Clip.
// since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
let myConnectionsRef = Database.database().reference(withPath: "users/morgan/connections")

// stores the timestamp of my last disconnect (the last time I was seen online)
let lastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline")

let connectedRef = Database.database().reference(withPath: ".info/connected")

connectedRef.observe(.value, with: { snapshot in
  // only handle connection established (or I've reconnected after a loss of connection)
  guard let connected = snapshot.value as? Bool, connected else { return }

  // add this device to my connections list
  let con = myConnectionsRef.childByAutoId()

  // when this device disconnects, remove it.
  con.onDisconnectRemoveValue()

  // The onDisconnect() call is before the call to set() itself. This is to avoid a race condition
  // where you set the user's presence to true and the client disconnects before the
  // onDisconnect() operation takes effect, leaving a ghost user.

  // this value could contain info about the device or a timestamp instead of just true
  con.setValue(true)

  // when I disconnect, update the last time I was seen online
  lastOnlineRef.onDisconnectSetValue(ServerValue.timestamp())
})

Objective-C

Observação: este produto Firebase não está disponível no destino App Clip.
// since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
FIRDatabaseReference *myConnectionsRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/connections"];

// stores the timestamp of my last disconnect (the last time I was seen online)
FIRDatabaseReference *lastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"];

FIRDatabaseReference *connectedRef = [[FIRDatabase database] referenceWithPath:@".info/connected"];
[connectedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  if([snapshot.value boolValue]) {
    // connection established (or I've reconnected after a loss of connection)

    // add this device to my connections list
    FIRDatabaseReference *con = [myConnectionsRef childByAutoId];

    // when this device disconnects, remove it
    [con onDisconnectRemoveValue];

    // The onDisconnect() call is before the call to set() itself. This is to avoid a race condition
    // where you set the user's presence to true and the client disconnects before the
    // onDisconnect() operation takes effect, leaving a ghost user.

    // this value could contain info about the device or a timestamp instead of just true
    [con setValue:@YES];


    // when I disconnect, update the last time I was seen online
    [lastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]];
  }
}];