Blockhaus

Viele Nutzer verwalten ihre Anmeldedaten immer noch selbst, wenn sie ein neues Android-Gerät einrichten. Dieser manuelle Prozess kann schwierig werden und führt oft zu einer schlechten Nutzererfahrung. Die Block Store API, eine Bibliothek, die auf Google Play-Diensten basiert, soll dieses Problem lösen, indem sie Apps die Möglichkeit bietet, Nutzeranmeldedaten zu speichern, ohne dass die Komplexität oder das Sicherheitsrisiko des Speicherns von Nutzerpasswörtern damit verbunden ist.

Mit der Block Store API kann Ihre App Daten speichern, die später abgerufen werden können, um Nutzer auf einem neuen Gerät noch einmal zu authentifizieren. So wird die Nutzerfreundlichkeit verbessert, da Nutzer beim ersten Starten der App auf dem neuen Gerät keinen Anmeldebildschirm sehen.

Die Verwendung von Block Store bietet folgende Vorteile:

  • Verschlüsselte Lösung für den Anmeldedatenspeicher für Entwickler. Anmeldedaten werden nach Möglichkeit mit Ende-zu-Ende-Verschlüsselung geschützt.
  • Speichern Sie Tokens anstelle von Nutzernamen und Passwörtern.
  • Vereinfachen Sie die Anmeldung.
  • Erleichtern Sie Nutzern die Verwaltung komplexer Passwörter.
  • Google überprüft die Identität des Nutzers.

Hinweis

Führen Sie die Schritte in den folgenden Abschnitten aus, um Ihre App vorzubereiten.

App konfigurieren

Fügen Sie in der Datei build.gradle auf Projektebene das Maven-Repository von Google in die Abschnitte buildscript und allprojects ein:

buildscript {
  repositories {
    google()
    mavenCentral()
  }
}

allprojects {
  repositories {
    google()
    mavenCentral()
  }
}

Fügen Sie die Abhängigkeit für die Google Play-Dienste für die Block Store API der Gradle-Build-Datei Ihres Moduls hinzu, die in der Regel app/build.gradle lautet:

dependencies {
  implementation 'com.google.android.gms:play-services-auth-blockstore:16.4.0'
}

Funktionsweise

Mit Block Store können Entwickler bis zu 16-Byte-Arrays speichern und wiederherstellen. So können Sie wichtige Informationen zur aktuellen Nutzersitzung speichern und diese Informationen beliebig speichern. Diese Daten können Ende-zu-Ende verschlüsselt werden. Die Infrastruktur, die Block Store unterstützt, basiert auf der Sicherungs- und Wiederherstellungsinfrastruktur.

In diesem Leitfaden wird der Anwendungsfall behandelt, bei dem das Token eines Nutzers im Block Store gespeichert wird. In den folgenden Schritten wird beschrieben, wie eine App mit Block Store funktioniert:

  1. Während des Authentifizierungsvorgangs Ihrer App oder jederzeit danach können Sie das Authentifizierungstoken des Nutzers zum späteren Abrufen im Block Store speichern.
  2. Das Token wird lokal gespeichert und kann auch in der Cloud gesichert werden, wobei es nach Möglichkeit Ende-zu-Ende verschlüsselt wird.
  3. Die Daten werden übertragen, wenn der Nutzer auf einem neuen Gerät einen Wiederherstellungsvorgang startet.
  4. Wenn der Nutzer Ihre App während des Wiederherstellungsvorgangs wiederherstellt, kann Ihre App das gespeicherte Token aus dem Block Store auf dem neuen Gerät abrufen.

Token speichern

Wenn sich ein Nutzer in Ihrer App anmeldet, können Sie das Authentifizierungstoken, das Sie für diesen Nutzer generieren, in Block Store speichern. Sie können dieses Token mit einem eindeutigen Schlüsselpaarwert speichern, der maximal 4 KB pro Eintrag hat. Rufe zum Speichern des Tokens setBytes() und setKey() auf einer Instanz von StoreBytesData.Builder auf, um die Anmeldedaten des Nutzers auf dem Quellgerät zu speichern. Nachdem Sie das Token mit Block Store gespeichert haben, wird es verschlüsselt und lokal auf dem Gerät gespeichert.

Im folgenden Beispiel wird gezeigt, wie das Authentifizierungstoken auf dem lokalen Gerät gespeichert wird:

Java

  BlockstoreClient client = Blockstore.getClient(this);
  byte[] bytes1 = new byte[] { 1, 2, 3, 4 };  // Store one data block.
  String key1 = "com.example.app.key1";
  StoreBytesData storeRequest1 = StoreBytesData.Builder()
          .setBytes(bytes1)
          // Call this method to set the key value pair the data should be associated with.
          .setKeys(Arrays.asList(key1))
          .build();
  client.storeBytes(storeRequest1)
    .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes"))
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

  val client = Blockstore.getClient(this)

  val bytes1 = byteArrayOf(1, 2, 3, 4) // Store one data block.
  val key1 = "com.example.app.key1"
  val storeRequest1 = StoreBytesData.Builder()
    .setBytes(bytes1) // Call this method to set the key value with which the data should be associated with.
    .setKeys(Arrays.asList(key1))
    .build()
  client.storeBytes(storeRequest1)
    .addOnSuccessListener { result: Int ->
      Log.d(TAG,
            "Stored $result bytes")
    }
    .addOnFailureListener { e ->
      Log.e(TAG, "Failed to store bytes", e)
    }

Standard-Token verwenden

Für Daten, die mit StoreBytes ohne Schlüssel gespeichert werden, wird der Standardschlüssel BlockstoreClient.DEFAULT_BYTES_DATA_KEY verwendet.

Java

  BlockstoreClient client = Blockstore.getClient(this);
  // The default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
  byte[] bytes = new byte[] { 9, 10 };
  StoreBytesData storeRequest = StoreBytesData.Builder()
          .setBytes(bytes)
          .build();
  client.storeBytes(storeRequest)
    .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes"))
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

  val client = Blockstore.getClient(this);
  // the default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
  val bytes = byteArrayOf(1, 2, 3, 4)
  val storeRequest = StoreBytesData.Builder()
    .setBytes(bytes)
    .build();
  client.storeBytes(storeRequest)
    .addOnSuccessListener { result: Int ->
      Log.d(TAG,
            "stored $result bytes")
    }
    .addOnFailureListener { e ->
      Log.e(TAG, "Failed to store bytes", e)
    }

Token abrufen

Wenn ein Nutzer später auf einem neuen Gerät die Wiederherstellung durchläuft, prüfen die Google Play-Dienste zuerst den Nutzer und rufen dann Ihre Block Store-Daten ab. Der Nutzer hat bereits im Rahmen des Wiederherstellungsvorgangs zugestimmt, dass Ihre App-Daten wiederhergestellt werden. Es sind also keine zusätzlichen Einwilligungen erforderlich. Wenn der Nutzer deine App öffnet, kannst du dein Token über Block Store anfordern, indem du retrieveBytes() aufrufst. Das abgerufene Token kann dann verwendet werden, um den Nutzer auf dem neuen Gerät angemeldet zu halten.

Im folgenden Beispiel wird gezeigt, wie Sie anhand bestimmter Schlüssel mehrere Tokens abrufen.

Java

BlockstoreClient client = Blockstore.getClient(this);

// Retrieve data associated with certain keys.
String key1 = "com.example.app.key1";
String key2 = "com.example.app.key2";
String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to retrieve data stored without a key

List requestedKeys = Arrays.asList(key1, key2, key3); // Add keys to array
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(requestedKeys)
    .build();

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map<String, BlockstoreData> blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry<String, BlockstoreData> entry : blockstoreDataMap.entrySet()) {
            Log.d(TAG, String.format(
                "Retrieved bytes %s associated with key %s.",
                new String(entry.getValue().getBytes()), entry.getKey()));
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

val client = Blockstore.getClient(this)

// Retrieve data associated with certain keys.
val key1 = "com.example.app.key1"
val key2 = "com.example.app.key2"
val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key

val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(requestedKeys)
  .build()

client.retrieveBytes(retrieveRequest)
  .addOnSuccessListener { result: RetrieveBytesResponse ->
    val blockstoreDataMap =
      result.blockstoreDataMap
    for ((key, value) in blockstoreDataMap) {
      Log.d(ContentValues.TAG, String.format(
        "Retrieved bytes %s associated with key %s.",
        String(value.bytes), key))
    }
  }
  .addOnFailureListener { e: Exception? ->
    Log.e(ContentValues.TAG,
          "Failed to store bytes",
          e)
  }

Alle Tokens werden abgerufen.

Im Folgenden findest du ein Beispiel dafür, wie du alle im BlockStore gespeicherten Tokens abrufen kannst.

Java

BlockstoreClient client = Blockstore.getClient(this)

// Retrieve all data.
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setRetrieveAll(true)
    .build();

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map<String, BlockstoreData> blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry<String, BlockstoreData> entry : blockstoreDataMap.entrySet()) {
            Log.d(TAG, String.format(
                "Retrieved bytes %s associated with key %s.",
                new String(entry.getValue().getBytes()), entry.getKey()));
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setRetrieveAll(true)
  .build()

client.retrieveBytes(retrieveRequest)
  .addOnSuccessListener { result: RetrieveBytesResponse ->
    val blockstoreDataMap =
      result.blockstoreDataMap
    for ((key, value) in blockstoreDataMap) {
      Log.d(ContentValues.TAG, String.format(
        "Retrieved bytes %s associated with key %s.",
        String(value.bytes), key))
    }
  }
  .addOnFailureListener { e: Exception? ->
    Log.e(ContentValues.TAG,
          "Failed to store bytes",
          e)
  }

Unten sehen Sie ein Beispiel dafür, wie Sie den Standardschlüssel abrufen.

Java

BlockStoreClient client = Blockstore.getClient(this);
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
    .build();
client.retrieveBytes(retrieveRequest);

Kotlin

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
  .build()
client.retrieveBytes(retrieveRequest)

Tokens löschen

Das Löschen von Tokens aus dem BlockStore kann aus folgenden Gründen erforderlich sein:

  • Der Nutzer führt den Abmeldevorgang durch.
  • Das Token wurde widerrufen oder ist ungültig.

Ähnlich wie beim Abrufen von Tokens können Sie angeben, welche Tokens gelöscht werden sollen, indem Sie ein Array mit Schlüsseln festlegen, die gelöscht werden sollen.

Im folgenden Beispiel wird gezeigt, wie bestimmte Schlüssel gelöscht werden:

Java

BlockstoreClient client = Blockstore.getClient(this);

// Delete data associated with certain keys.
String key1 = "com.example.app.key1";
String key2 = "com.example.app.key2";
String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to delete data stored without key

List requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array
DeleteBytesRequest deleteRequest = new DeleteBytesRequest.Builder()
      .setKeys(requestedKeys)
      .build();
client.deleteBytes(deleteRequest)

Kotlin

val client = Blockstore.getClient(this)

// Retrieve data associated with certain keys.
val key1 = "com.example.app.key1"
val key2 = "com.example.app.key2"
val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key

val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array

val retrieveRequest = DeleteBytesRequest.Builder()
      .setKeys(requestedKeys)
      .build()

client.deleteBytes(retrieveRequest)

Alle Tokens löschen

Im folgenden Beispiel wird gezeigt, wie alle derzeit im BlockStore gespeicherten Tokens gelöscht werden:

Java

// Delete all data.
DeleteBytesRequest deleteAllRequest = new DeleteBytesRequest.Builder()
      .setDeleteAll(true)
      .build();
client.deleteBytes(deleteAllRequest)
.addOnSuccessListener(result -> Log.d(TAG, "Any data found and deleted? " + result));

Kotlin

  val deleteAllRequest = DeleteBytesRequest.Builder()
  .setDeleteAll(true)
  .build()
retrieve bytes, the key BlockstoreClient.DEFAULT_BYTES_DATA_KEY can be used
in the RetrieveBytesRequest instance in order to get your saved data

The following example shows how to retrieve the default key.

Java

End-to-end encryption

In order for end-to-end encryption to be made available, the device must be running Android 9 or higher, and the user must have set a screen lock (PIN, pattern, or password) for their device. You can verify if encryption will be available on the device by calling isEndToEndEncryptionAvailable().

The following sample shows how to verify if encryption will be available during cloud backup:

client.isEndToEndEncryptionAvailable()
        .addOnSuccessListener { result ->
          Log.d(TAG, "Will Block Store cloud backup be end-to-end encrypted? $result")
        }

Cloud-Sicherung aktivieren

Wenn Sie die Cloud-Sicherung aktivieren möchten, fügen Sie Ihrem StoreBytesData-Objekt die Methode setShouldBackupToCloud() hinzu. Wenn setShouldBackupToCloud() auf „wahr“ gesetzt ist, werden die gespeicherten Byte regelmäßig in der Cloud gesichert.

Im folgenden Beispiel wird gezeigt, wie Sie die Cloud-Sicherung nur aktivieren, wenn die Cloud-Sicherung Ende-zu-Ende-verschlüsselt ist:

val client = Blockstore.getClient(this)
val storeBytesDataBuilder = StoreBytesData.Builder()
        .setBytes(/* BYTE_ARRAY */)

client.isEndToEndEncryptionAvailable()
        .addOnSuccessListener { isE2EEAvailable ->
          if (isE2EEAvailable) {
            storeBytesDataBuilder.setShouldBackupToCloud(true)
            Log.d(TAG, "E2EE is available, enable backing up bytes to the cloud.")

            client.storeBytes(storeBytesDataBuilder.build())
                .addOnSuccessListener { result ->
                  Log.d(TAG, "stored: ${result.getBytesStored()}")
                }.addOnFailureListener { e ->
                  Log.e(TAG, Failed to store bytes, e)
                }
          } else {
            Log.d(TAG, "E2EE is not available, only store bytes for D2D restore.")
          }
        }

So testen Sie

Verwenden Sie während der Entwicklung die folgenden Methoden, um die Wiederherstellungsabläufe zu testen.

Deinstallation/Neuinstallation auf demselben Gerät

Wenn der Nutzer Sicherungsdienste aktiviert (Einstellungen > Google > Sicherung), bleiben Block Store-Daten auch nach der Deinstallation und Neuinstallation der App erhalten.

So können Sie Folgendes testen:

  1. Binden Sie die Block Store API in Ihre Test-App ein.
  2. Rufen Sie mit der Test-App die Block Store API auf, um Ihre Daten zu speichern.
  3. Deinstallieren Sie die Test-App und installieren Sie sie dann auf demselben Gerät neu.
  4. Rufen Sie mit der Test-App die Block Store API auf, um Ihre Daten abzurufen.
  5. Prüfen Sie, ob die abgerufenen Bytes mit denjenigen übereinstimmen, die vor der Deinstallation gespeichert wurden.

Gerät zu Gerät

In den meisten Fällen ist dazu ein Zurücksetzen des Zielgeräts auf die Werkseinstellungen erforderlich. Sie können dann die kabellose Wiederherstellung mit Android oder die kabelgebundene Wiederherstellung mit Google (für unterstützte Geräte) ausführen.

Wiederherstellung aus der Cloud

  1. Binden Sie die Block Store API in Ihre Test-App ein. Die Test-App muss im Play Store eingereicht werden.
  2. Rufen Sie auf dem Quellgerät mit der Test-App die Block Store API auf, um Ihre Daten zu speichern. Dabei muss shouldBackUpToCloud auf true festgelegt sein.
  3. Auf Geräten mit Version O und höher können Sie eine Block Store-Cloud-Sicherung manuell auslösen: Gehen Sie zu Einstellungen > Google > Sicherung und klicken Sie auf die Schaltfläche „Jetzt sichern“.
    1. So können Sie prüfen, ob die Block Store-Cloud-Sicherung erfolgreich war:
      1. Suchen Sie nach Abschluss der Sicherung nach Logzeilen mit dem Tag „CloudSyncBpTkSvc“.
      2. Sie sollten Zeilen wie diese sehen: „......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., uploaded size: XXX bytes ...”
    2. Nach einer Block Store-Cloud-Sicherung gibt es eine 5-minütige Wartezeit. Innerhalb dieser 5 Minuten wird durch Klicken auf die Schaltfläche „Jetzt sichern“ keine weitere Block Store-Cloud-Sicherung ausgelöst.
  4. Setzen Sie das Zielgerät auf die Werkseinstellungen zurück und führen Sie eine Wiederherstellung aus der Cloud durch. Wählen Sie während des Wiederherstellungsvorgangs aus, dass Ihre Test-App wiederhergestellt werden soll. Weitere Informationen zu Cloud-Wiederherstellungsabläufen finden Sie unter Unterstützte Cloud-Wiederherstellungsabläufe.
  5. Rufen Sie auf dem Zielgerät mit der Test-App die Block Store API auf, um Ihre Daten abzurufen.
  6. Prüfen Sie, ob die abgerufenen Bytes mit denjenigen übereinstimmen, die auf dem Quellgerät gespeichert waren.

Geräteanforderungen

Ende-zu-Ende-Verschlüsselung

  • Die Ende-zu-Ende-Verschlüsselung wird auf Geräten mit Android 9 (API 29) und höher unterstützt.
  • Auf dem Gerät muss eine Displaysperre mit einer PIN, einem Muster oder einem Passwort eingerichtet sein, damit die Ende-zu-Ende-Verschlüsselung aktiviert und die Daten des Nutzers korrekt verschlüsselt werden können.

Wiederherstellung von Gerät zu Gerät

Für die Wiederherstellung von Gerät zu Gerät benötigen Sie ein Quell- und ein Zielgerät. Das sind die beiden Geräte, zwischen denen Daten übertragen werden.

Auf den Quellgeräten muss Android 6 (API 23) oder höher installiert sein, damit eine Sicherung möglich ist.

Richten Sie Ihre App auf Geräte mit Android 9 (API 29) oder höher aus, damit eine Wiederherstellung möglich ist.

Weitere Informationen zur Wiederherstellung von einem Gerät auf ein anderes

Ablauf für die Sicherung und Wiederherstellung in der Cloud

Für die Sicherung und Wiederherstellung in der Cloud sind ein Quell- und ein Zielgerät erforderlich.

Auf den Quellgeräten muss Android 6 (API 23) oder höher installiert sein, damit eine Sicherung möglich ist.

Target-Geräte werden je nach Anbieter unterstützt. Pixel-Geräte können diese Funktion ab Android 9 (API 29) verwenden. Auf allen anderen Geräten muss Android 12 (API 31) oder höher installiert sein.