Catch up on highlights from Firebase at Google I/O 2023. Learn more

Offline auf Daten zugreifen

Cloud Firestore unterstützt die Offline-Datenpersistenz. Diese Funktion speichert eine Kopie der Cloud Firestore-Daten, die Ihre App aktiv nutzt, zwischen, sodass Ihre App auf die Daten zugreifen kann, wenn das Gerät offline ist. Sie können die zwischengespeicherten Daten schreiben, lesen, anhören und abfragen. Wenn das Gerät wieder online ist, synchronisiert Cloud Firestore alle von Ihrer App vorgenommenen lokalen Änderungen mit dem Cloud Firestore-Backend.

Um die Offline-Persistenz zu verwenden, müssen Sie keine Änderungen am Code vornehmen, den Sie für den Zugriff auf Cloud Firestore-Daten verwenden. Bei aktivierter Offline-Persistenz verwaltet die Cloud Firestore-Clientbibliothek automatisch den Online- und Offline-Datenzugriff und synchronisiert lokale Daten, wenn das Gerät wieder online ist.

Konfigurieren Sie die Offline-Persistenz

Wenn Sie Cloud Firestore initialisieren, können Sie die Offline-Persistenz aktivieren oder deaktivieren:

  • Für Android- und Apple-Plattformen ist die Offline-Persistenz standardmäßig aktiviert. Um die Persistenz zu deaktivieren, legen Sie die Option PersistenceEnabled auf false fest.
  • Für das Web ist die Offline-Persistenz standardmäßig deaktiviert. Um die Persistenz zu aktivieren, rufen Sie die Methode enablePersistence auf. Der Cache von Cloud Firestore wird zwischen Sitzungen nicht automatisch geleert. Wenn Ihre Web-App vertrauliche Informationen verarbeitet, fragen Sie den Benutzer daher unbedingt, ob er sich auf einem vertrauenswürdigen Gerät befindet, bevor Sie die Persistenz aktivieren.

Web modular API

// Memory cache is the default if no config is specified.
initializeFirestore(app);

// This is the default behavior if no persistence is specified.
initializeFirestore(app, {localCache: memoryLocalCache()});

// Defaults to single-tab persistence if no tab manager is specified.
initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})});

// Same as `initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})})`,
// but more explicit about tab management.
initializeFirestore(app, 
  {localCache: 
    persistentLocalCache(/*settings*/{tabManager: persistentSingleTabManager()})
});

// Use multi-tab IndexedDb persistence.
initializeFirestore(app, 
  {localCache: 
    persistentLocalCache(/*settings*/{tabManager: persistentMultipleTabManager()})
  });
  

Web namespaced API

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
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
let settings = FirestoreSettings()

// Use memory-only cache
settings.cacheSettings =
    MemoryCacheSettings(garbageCollectorSettings: MemoryLRUGCSettings())

// Use persistent disk cache, with 1 MB cache size
settings.cacheSettings = PersistentCacheSettings(sizeBytes: 1_000_000)

// Any additional options
// ...

// Enable offline data persistence
let db = Firestore.firestore()
db.settings = settings
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init];

// Use memory-only cache
settings.cacheSettings = [[FIRMemoryCacheSettings alloc]
    initWithGarbageCollectorSettings:[[FIRMemoryLRUGCSettings alloc] init]];

// Use persistent disk cache (default behavior)
// This example uses 1 million bytes, or 1 MB.
settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@1000000];

// Any additional options
// ...

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

Kotlin+KTX

val settings = firestoreSettings {
    // Use memory cache
    setLocalCacheSettings(memoryCacheSettings {})
    // Use persistent disk cache (default)
    setLocalCacheSettings(persistentCacheSettings {})
}
db.firestoreSettings = settings

Java

FirebaseFirestoreSettings settings = 
new FirebaseFirestoreSettings.Builder(db.getFirestoreSettings())
    // Use memory-only cache
    .setLocalCacheSettings(MemoryCacheSettings.newBuilder().build())
    // Use persistent disk cache (default)
    .setLocalCacheSettings(PersistentCacheSettings.newBuilder()
                            .build())
    .build();
db.setFirestoreSettings(settings);

Dart

// Apple and Android
db.settings = const Settings(persistenceEnabled: true);

// Web
await db
    .enablePersistence(const PersistenceSettings(synchronizeTabs: true));

Konfigurieren Sie die Cachegröße

Wenn die Persistenz aktiviert ist, speichert Cloud Firestore jedes vom Backend empfangene Dokument für den Offline-Zugriff zwischen. Cloud Firestore legt einen Standardschwellenwert für die Cache-Größe fest. Nach Überschreiten des Standardwerts versucht Cloud Firestore regelmäßig, ältere, nicht verwendete Dokumente zu bereinigen. Sie können einen anderen Schwellenwert für die Cache-Größe konfigurieren oder den Bereinigungsprozess vollständig deaktivieren:

Web modular API

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

const firestoreDb = initializeFirestore(app, {
  cacheSizeBytes: CACHE_SIZE_UNLIMITED
});

Web namespaced API

firebase.firestore().settings({
    cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED
});
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
// 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
// Set cache size to 1 MB
settings.cacheSettings = PersistentCacheSettings(sizeBytes: 1_000_000)
Firestore.firestore().settings = settings
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
// 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;
// Set cache size to 1 MB
settings.cacheSettings =
    [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@1000000];
[FIRFirestore firestore].settings = 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

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

Dart

db.settings = const Settings(
  persistenceEnabled: true,
  cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED,
);

Hören Sie sich Offline-Daten an

Wenn das Gerät offline ist und Sie die Offline-Persistenz aktiviert haben, erhalten Ihre Listener Abhörereignisse, wenn sich die lokal zwischengespeicherten Daten ändern. Sie können Dokumente, Sammlungen und Abfragen anhören.

Um zu überprüfen, ob Sie Daten vom Server oder vom Cache erhalten, verwenden Sie die fromCache Eigenschaft für SnapshotMetadata in Ihrem Snapshot-Ereignis. Wenn fromCache true ist, stammen die Daten aus dem Cache und sind möglicherweise veraltet oder unvollständig. Wenn fromCache den false hat, sind die Daten vollständig und aktuell mit den neuesten Updates auf dem Server.

Standardmäßig wird kein Ereignis ausgelöst, wenn sich nur die SnapshotMetadata geändert haben. Wenn Sie sich auf die fromCache Werte verlassen, geben Sie beim Anhängen Ihres Listen-Handlers die Listenoption includeMetadataChanges an.

Web modular API

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

Web namespaced API

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);
      });
  });
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
// 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)")
}
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
// 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);
    }];

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

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

            }
        });

Dart

db
    .collection("cities")
    .where("state", isEqualTo: "CA")
    .snapshots(includeMetadataChanges: true)
    .listen((querySnapshot) {
  for (var change in querySnapshot.docChanges) {
    if (change.type == DocumentChangeType.added) {
      final source =
          (querySnapshot.metadata.isFromCache) ? "local cache" : "server";

      print("Data fetched from $source}");
    }
  }
});

Holen Sie sich Offline-Daten

Wenn Sie ein Dokument erhalten, während das Gerät offline ist, gibt Cloud Firestore Daten aus dem Cache zurück.

Beim Abfragen einer Sammlung wird ein leeres Ergebnis zurückgegeben, wenn keine zwischengespeicherten Dokumente vorhanden sind. Beim Abrufen eines bestimmten Dokuments wird stattdessen ein Fehler zurückgegeben.

Offline-Daten abfragen

Die Abfrage funktioniert mit Offline-Persistenz. Sie können die Ergebnisse von Abfragen entweder mit einem direkten Abruf oder durch Abhören abrufen, wie in den vorherigen Abschnitten beschrieben. Sie können auch neue Abfragen für lokal gespeicherte Daten erstellen, während das Gerät offline ist. Die Abfragen werden jedoch zunächst nur für die zwischengespeicherten Dokumente ausgeführt.

Konfigurieren Sie Offline-Abfrageindizes

Standardmäßig scannt das Firestore SDK alle Dokumente in einer Sammlung in seinem lokalen Cache, wenn Offline-Abfragen ausgeführt werden. Bei diesem Standardverhalten kann die Leistung von Offline-Abfragen beeinträchtigt werden, wenn Benutzer über einen längeren Zeitraum offline sind.

Sie können die Leistung von Offline-Abfragen verbessern, indem Sie lokale Abfrageindizes konfigurieren:

Schnell

Das Apple-Plattform-SDK stellt eine setIndexConfiguration Methode bereit, die dieselbe JSON-strukturierte Konfiguration liest, die zum Konfigurieren von Indizes auf dem Server verwendet wird, und dabei demselben Indexdefinitionsformat folgt.

// You will normally read this from a file asset or cloud storage.
let indexConfigJson = """
  {
    indexes: [
        ...
    ],
    fieldOverrides: [
        ...
    ]
  }
"""

// Apply the configuration.
Firestore.firestore().setIndexConfiguration(indexConfigJson)
Ziel c

Das Apple-Plattform-SDK stellt setIndexConfiguration - Methoden bereit, die dieselbe JSON-strukturierte Konfiguration lesen, die zum Konfigurieren von Indizes auf dem Server verwendet wird, und dabei demselben Indexdefinitionsformat folgen.

// You will normally read this from a file asset or cloud storage.
NSString *indexConfigJson = @" {                   "
                             "   indexes: [        "
                             "     ...             "
                             "   ],                "
                             "   fieldOverrides: [ "
                             "     ...             "
                             "   ]                 "
                             " }                   ";

// Apply the configuration.
[[FIRFirestore firestore] setIndexConfigurationFromJSON:indexConfigJson
                                             completion:^(NSError * _Nullable error) {
    // ...
}];

Java

Das Android SDK stellt eine setIndexConfiguration Methode bereit, die dieselbe JSON-strukturierte Konfiguration liest, die zum Konfigurieren von Indizes auf dem Server verwendet wird, und dabei demselben Indexdefinitionsformat folgt.

// You will normally read this from a file asset or cloud storage.
String indexConfigJson = " {                   "
                       + "   indexes: [        "
                       + "     ...             "
                       + "   ],                "
                       + "   fieldOverrides: [ "
                       + "     ...             "
                       + "   ]                 "
                       + " }                   ";
// Apply the configuration.
FirebaseFirestore.getInstance().setIndexConfiguration(indexConfigJson);

Kotlin+KTX

Das Android SDK stellt eine setIndexConfiguration Methode bereit, die dieselbe JSON-strukturierte Konfiguration liest, die zum Konfigurieren von Indizes auf dem Server verwendet wird, und dabei demselben Indexdefinitionsformat folgt.

// You will normally read this from a file asset or cloud storage.
val indexConfigJson = """
{
  indexes: [
      ...
  ],
  fieldOverrides: [
      ...
  ]
}
"""

// Apply the configuration.
FirebaseFirestore.getInstance().setIndexConfiguration(indexConfigJson)

Dart

Das Flutter SDK stellt eine setIndexConfigurationFromJSON Methode bereit, die dieselbe JSON-strukturierte Konfiguration liest, die zum Konfigurieren von Indizes auf dem Server verwendet wird, und dabei demselben Indexdefinitionsformat folgt.

// You will normally read this from a file asset or cloud storage.
var indexConfigJson = """
{
  indexes: [
      ...
  ],
  fieldOverrides: [
      ...
  ]
}
""";

// Apply the configuration.
await FirebaseFirestore.instance.setIndexConfigurationFromJSON(json: indexConfigJson);

Alternativ können Sie die setIndexConfiguration Methode verwenden, um Indizes mit einer klassenbasierten API zu konfigurieren.

var indexes = [
  Index(
    collectionGroup: "posts",
    queryScope: QueryScope.collection,
    fields: [
      IndexField(fieldPath: "author", arrayConfig: ArrayConfig.contains),
      IndexField(fieldPath: "timestamp", order: Order.descending)
    ],
  ),
];
await FirebaseFirestore.instance.setIndexConfiguration(indexes: indexes);

Die zu verwendende Offline-Indexkonfiguration hängt davon ab, auf welche Sammlungen und Dokumente Ihre App offline häufig zugreift und welche Offline-Leistung Sie wünschen. Während Sie Ihre Back-End-Indexkonfiguration zur Verwendung auf dem Client exportieren können, unterscheiden sich die Offline-Zugriffsmuster Ihrer App wahrscheinlich erheblich von den Online-Zugriffsmustern, sodass Ihre Online-Indexkonfiguration möglicherweise nicht für die Offline-Verwendung geeignet ist. Auf welche Sammlungen und Dokumente soll Ihre App offline mit hoher Leistung zugreifen? Nachdem Sie das Verhalten Ihrer App analysiert haben, befolgen Sie die Grundsätze zur Indexdefinition aus dem Indexierungsleitfaden .

So machen Sie Offline-Indexkonfigurationen zum Laden in Ihrer Client-App verfügbar:

  • Kompilieren und verteilen Sie sie mit Ihrer App
  • Laden Sie sie von einem CDN herunter
  • Rufen Sie sie von einem Speichersystem wie Cloud Storage für Firebase ab.

Deaktivieren und aktivieren Sie den Netzwerkzugriff

Mit der folgenden Methode können Sie den Netzwerkzugriff für Ihren Cloud Firestore-Client deaktivieren. Während der Netzwerkzugriff deaktiviert ist, rufen alle Snapshot-Listener und Dokumentanforderungen Ergebnisse aus dem Cache ab. Schreibvorgänge werden in die Warteschlange gestellt, bis der Netzwerkzugriff wieder aktiviert wird.

Web modular API

import { disableNetwork } from "firebase/firestore"; 

await disableNetwork(db);
console.log("Network disabled!");
// Do offline actions
// ...

Web namespaced API

firebase.firestore().disableNetwork()
    .then(() => {
        // Do offline actions
        // ...
    });
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
Firestore.firestore().disableNetwork { (error) in
    // Do offline things
    // ...
}
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) {
  // Do offline actions
  // ...
}];

Kotlin+KTX

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

Java

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

Dart

db.disableNetwork().then((_) {
  // Do offline things
});

Verwenden Sie die folgende Methode, um den Netzwerkzugriff wieder zu aktivieren:

Web modular API

import { enableNetwork } from "firebase/firestore"; 

await enableNetwork(db);
// Do online actions
// ...

Web namespaced API

firebase.firestore().enableNetwork()
    .then(() => {
        // Do online actions
        // ...
    });
Schnell
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
Firestore.firestore().enableNetwork { (error) in
    // Do online things
    // ...
}
Ziel c
Hinweis: Dieses Produkt ist nicht auf watchOS- und App Clip-Zielen verfügbar.
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) {
  // Do online actions
  // ...
}];

Kotlin+KTX

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

Java

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

Dart

db.enableNetwork().then((_) {
  // Back online
});