Check out what’s new from Firebase@ Google I/O 2021, and join our alpha program for early access to the new Remote Config personalization feature. Learn more

Accéder aux données hors ligne

Cloud Firestore prend en charge la persistance des données hors connexion. Cette fonctionnalité met en cache une copie des données Cloud Firestore que votre application utilise activement, afin que votre application puisse accéder aux données lorsque l'appareil est hors ligne. Vous pouvez écrire, lire, écouter et interroger les données mises en cache. Lorsque l'appareil revient en ligne, Cloud Firestore synchronise toutes les modifications locales apportées par votre application au backend Cloud Firestore.

Pour utiliser la persistance hors connexion, vous n'avez pas besoin de modifier le code que vous utilisez pour accéder aux données Cloud Firestore. Lorsque la persistance hors ligne est activée, la bibliothèque cliente Cloud Firestore gère automatiquement l'accès aux données en ligne et hors ligne et synchronise les données locales lorsque l'appareil est de nouveau en ligne.

Configurer la persistance hors ligne

Lorsque vous initialisez Cloud Firestore, vous pouvez activer ou désactiver la persistance hors connexion :

  • Pour Android et iOS, la persistance hors ligne est activée par défaut. Pour désactiver la persistance, définissez l'option PersistenceEnabled sur false .
  • Pour le Web, la persistance hors ligne est désactivée par défaut. Pour activer la persistance, appelez la méthode enablePersistence . Le cache de Cloud Firestore n'est pas automatiquement effacé entre les sessions. Par conséquent, si votre application Web gère des informations sensibles, assurez-vous de demander à l'utilisateur s'il utilise un appareil de confiance avant d'activer la persistance.

Web v8

firebase.firestore().enablePersistence()
  .catch((err) => {
      if (err.code == 'failed-precondition') {
          // Multiple tabs open, persistence can only be enabled
          // in one tab at a a time.
          // ...
      } else if (err.code == 'unimplemented') {
          // The current browser does not support all of the
          // features required to enable persistence
          // ...
      }
  });
// Subsequent queries will use persistence, if it was enabled successfully

Web v9

import { enableIndexedDbPersistence } from "firebase/firestore"; 

enableIndexedDbPersistence(db)
  .catch((err) => {
      if (err.code == 'failed-precondition') {
          // Multiple tabs open, persistence can only be enabled
          // in one tab at a a time.
          // ...
      } else if (err.code == 'unimplemented') {
          // The current browser does not support all of the
          // features required to enable persistence
          // ...
      }
  });
// Subsequent queries will use persistence, if it was enabled successfully
Rapide
let settings = FirestoreSettings()
settings.isPersistenceEnabled = true

// Any additional options
// ...

// Enable offline data persistence
let db = Firestore.firestore()
db.settings = settings
Objectif c
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init];
settings.persistenceEnabled = YES;

// Any additional options
// ...

// Enable offline data persistence
FIRFirestore *db = [FIRFirestore firestore];
db.settings = settings;

Java

FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
        .setPersistenceEnabled(true)
        .build();
db.setFirestoreSettings(settings);

Kotlin+KTX

val settings = firestoreSettings {
    isPersistenceEnabled = true
}
db.firestoreSettings = settings

Configurer la taille du cache

Lorsque la persistance est activée, Cloud Firestore met en cache chaque document reçu du backend pour un accès hors connexion. Cloud Firestore définit un seuil par défaut pour la taille du cache. Après avoir dépassé la valeur par défaut, Cloud Firestore tente périodiquement de nettoyer les documents plus anciens et inutilisés. Vous pouvez configurer un seuil de taille de cache différent ou désactiver complètement le processus de nettoyage :

Web v8

firebase.firestore().settings({
    cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED
});

Web v9

import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore";

const firestoreDb = initializeFirestore(app, {
  cacheSizeBytes: CACHE_SIZE_UNLIMITED
});
Rapide
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "FirestoreCacheSizeUnlimited"
// to disable clean-up.
let settings = Firestore.firestore().settings
settings.cacheSizeBytes = FirestoreCacheSizeUnlimited
Firestore.firestore().settings = settings
Objectif c
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "kFIRFirestoreCacheSizeUnlimited"
// to disable clean-up.
FIRFirestoreSettings *settings = [FIRFirestore firestore].settings;
settings.cacheSizeBytes = kFIRFirestoreCacheSizeUnlimited;
[FIRFirestore firestore].settings = settings;
  

Java


// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED"
// to disable clean-up.
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
        .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
        .build();
db.setFirestoreSettings(settings);

Kotlin+KTX


// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED"
// to disable clean-up.
val settings = FirebaseFirestoreSettings.Builder()
        .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
        .build()
db.firestoreSettings = settings

Écouter des données hors ligne

Lorsque l'appareil est hors ligne, si vous avez activé la persistance hors ligne, vos auditeurs recevront des événements d'écoute lorsque les données mises en cache localement changent. Vous pouvez écouter des documents, des collections et des requêtes.

Pour vérifier si vous recevez des données du serveur ou du cache, utilisez la propriété fromCache sur SnapshotMetadata dans votre événement d'instantané. Si fromCache est true , les données proviennent du cache et peuvent être périmées ou incomplètes. Si fromCache est false , les données sont complètes et à jour avec les dernières mises à jour sur le serveur.

Par défaut, aucun événement n'est déclenché si seuls les SnapshotMetadata changé. Si vous vous fiez aux valeurs fromCache , spécifiez l'option d'écoute includeMetadataChanges lorsque vous attachez votre gestionnaire d'écoute.

Web v8

db.collection("cities").where("state", "==", "CA")
  .onSnapshot({ includeMetadataChanges: true }, (snapshot) => {
      snapshot.docChanges().forEach((change) => {
          if (change.type === "added") {
              console.log("New city: ", change.doc.data());
          }

          var source = snapshot.metadata.fromCache ? "local cache" : "server";
          console.log("Data came from " + source);
      });
  });

Web v9

import { collection, onSnapshot, where, query } from "firebase/firestore"; 

const q = query(collection(db, "cities"), where("state", "==", "CA"));
onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
    snapshot.docChanges().forEach((change) => {
        if (change.type === "added") {
            console.log("New city: ", change.doc.data());
        }

        const source = snapshot.metadata.fromCache ? "local cache" : "server";
        console.log("Data came from " + source);
    });
});
Rapide
// Listen to metadata updates to receive a server snapshot even if
// the data is the same as the cached data.
db.collection("cities").whereField("state", isEqualTo: "CA")
    .addSnapshotListener(includeMetadataChanges: true) { querySnapshot, error in
        guard let snapshot = querySnapshot else {
            print("Error retreiving snapshot: \(error!)")
            return
        }

        for diff in snapshot.documentChanges {
            if diff.type == .added {
                print("New city: \(diff.document.data())")
            }
        }

        let source = snapshot.metadata.isFromCache ? "local cache" : "server"
        print("Metadata: Data fetched from \(source)")
}
Objectif c
// Listen to metadata updates to receive a server snapshot even if
// the data is the same as the cached data.
[[[db collectionWithPath:@"cities"] queryWhereField:@"state" isEqualTo:@"CA"]
    addSnapshotListenerWithIncludeMetadataChanges:YES
    listener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      if (snapshot == nil) {
        NSLog(@"Error retreiving snapshot: %@", error);
        return;
      }
      for (FIRDocumentChange *diff in snapshot.documentChanges) {
        if (diff.type == FIRDocumentChangeTypeAdded) {
          NSLog(@"New city: %@", diff.document.data);
        }
      }

      NSString *source = snapshot.metadata.isFromCache ? @"local cache" : @"server";
      NSLog(@"Metadata: Data fetched from %@", source);
    }];

Java

db.collection("cities").whereEqualTo("state", "CA")
        .addSnapshotListener(MetadataChanges.INCLUDE, new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot querySnapshot,
                                @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    Log.w(TAG, "Listen error", e);
                    return;
                }

                for (DocumentChange change : querySnapshot.getDocumentChanges()) {
                    if (change.getType() == Type.ADDED) {
                        Log.d(TAG, "New city:" + change.getDocument().getData());
                    }

                    String source = querySnapshot.getMetadata().isFromCache() ?
                            "local cache" : "server";
                    Log.d(TAG, "Data fetched from " + source);
                }

            }
        });

Kotlin+KTX

db.collection("cities").whereEqualTo("state", "CA")
        .addSnapshotListener(MetadataChanges.INCLUDE) { querySnapshot, e ->
            if (e != null) {
                Log.w(TAG, "Listen error", e)
                return@addSnapshotListener
            }

            for (change in querySnapshot!!.documentChanges) {
                if (change.type == DocumentChange.Type.ADDED) {
                    Log.d(TAG, "New city: ${change.document.data}")
                }

                val source = if (querySnapshot.metadata.isFromCache)
                    "local cache"
                else
                    "server"
                Log.d(TAG, "Data fetched from $source")
            }
        }

Obtenir des données hors ligne

Si vous obtenez un document alors que l'appareil est hors ligne, Cloud Firestore renvoie les données du cache.

Lors de l'interrogation d'une collection, un résultat vide est renvoyé s'il n'y a pas de documents mis en cache. Lors de la récupération d'un document spécifique, une erreur est renvoyée à la place.

Interroger les données hors connexion

L'interrogation fonctionne avec la persistance hors ligne. Vous pouvez récupérer les résultats des requêtes avec un get direct ou en écoutant, comme décrit dans les sections précédentes. Vous pouvez également créer de nouvelles requêtes sur des données persistantes localement lorsque l'appareil est hors ligne, mais les requêtes ne seront initialement exécutées que sur les documents mis en cache.

Désactiver et activer l'accès au réseau

Vous pouvez utiliser la méthode ci-dessous pour désactiver l'accès au réseau pour votre client Cloud Firestore. Lorsque l'accès au réseau est désactivé, tous les écouteurs d'instantané et les demandes de documents récupèrent les résultats du cache. Les opérations d'écriture sont mises en file d'attente jusqu'à ce que l'accès au réseau soit réactivé.

Web v8

firebase.firestore().disableNetwork()
    .then(() => {
        // Do offline actions
        // ...
    });

Web v9

import { disableNetwork } from "firebase/firestore"; 

await disableNetwork(db);
console.log("Network disabled!");
// Do offline actions
// ...
Rapide
Firestore.firestore().disableNetwork { (error) in
    // Do offline things
    // ...
}
Objectif c
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) {
  // Do offline actions
  // ...
}];

Java

db.disableNetwork()
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // Do offline things
                // ...
            }
        });

Kotlin+KTX

db.disableNetwork().addOnCompleteListener {
    // Do offline things
    // ...
}

Utilisez la méthode suivante pour réactiver l'accès au réseau :

Web v8

firebase.firestore().enableNetwork()
    .then(() => {
        // Do online actions
        // ...
    });

Web v9

import { enableNetwork } from "firebase/firestore"; 

await enableNetwork(db);
// Do online actions
// ...
Rapide
Firestore.firestore().enableNetwork { (error) in
    // Do online things
    // ...
}
Objectif c
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) {
  // Do online actions
  // ...
}];

Java

db.enableNetwork()
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // Do online things
                // ...
            }
        });

Kotlin+KTX

db.enableNetwork().addOnCompleteListener {
    // Do online things
    // ...
}