Viele Nutzer verwalten ihre eigenen Anmeldedaten immer noch selbst, wenn sie ein neues Android-Gerät einrichten. Dieser manuelle Prozess kann schwierig sein und führt oft zu einer schlechten Nutzererfahrung. Die Block Store API, eine von den Google Play-Diensten bereitgestellte Bibliothek, soll dieses Problem lösen. Sie bietet Apps die Möglichkeit, Nutzeranmeldedaten zu speichern, ohne dass die Komplexität oder das Sicherheitsrisiko des Speicherns von Nutzerpasswörtern entsteht.
Mit der Block Store API kann deine App Daten speichern, die sie später abrufen kann, um Nutzer auf einem neuen Gerät noch einmal zu authentifizieren. Das sorgt für eine reibungslosere Nutzung, da der Nutzer beim ersten Starten der App auf dem neuen Gerät keinen Anmeldebildschirm sieht.
Die Verwendung von Block Store bietet unter anderem folgende Vorteile:
- Verschlüsselter Anmeldedatenspeicher für Entwickler. Anmeldedaten werden nach Möglichkeit Ende-zu-Ende-verschlüsselt.
- Tokens anstelle von Nutzernamen und Passwörtern speichern.
- Hürden bei der Anmeldung beseitigen.
- Nutzer müssen sich keine komplexen Passwörter mehr merken.
- Google überprüft die Identität des Nutzers.
Hinweis
Führen Sie die Schritte in den folgenden Abschnitten aus, um Ihre App vorzubereiten.
Eigene App konfigurieren
Fügen Sie in der build.gradle-Datei auf Projektebene in den Bereichen buildscript und allprojects das Maven-Repository von Google ein:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
Fügen Sie der Gradle-Build-Datei Ihres Moduls (normalerweise app/build.gradle) die Google Play-Dienste-Abhängigkeit für die Block Store API hinzu:
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 flexibel speichern. Diese Daten können mit Ende-zu-Ende-Verschlüsselung geschützt werden. Die Infrastruktur, die Block Store unterstützt, basiert auf der Infrastruktur für Sicherung und Wiederherstellung.
In diesem Leitfaden wird der Anwendungsfall des Speicherns des Tokens eines Nutzers im Block Store behandelt. Die folgenden Schritte beschreiben, wie eine App, die Block Store verwendet, funktioniert:
- Während des Authentifizierungsvorgangs deiner App oder jederzeit danach kannst du das Authentifizierungstoken des Nutzers im Block Store speichern, um es später abzurufen.
- Das Token wird lokal gespeichert und kann auch in der Cloud gesichert werden, wenn möglich mit Ende-zu-Ende-Verschlüsselung.
- Die Daten werden übertragen, wenn der Nutzer auf einem neuen Gerät einen Wiederherstellungsvorgang startet.
- Wenn der Nutzer deine App während der Wiederherstellung wiederherstellt, kann deine App das gespeicherte Token aus dem Block Store auf dem neuen Gerät abrufen.
Token speichern
Wenn sich ein Nutzer in deiner App anmeldet, kannst du das Authentifizierungstoken, das du für diesen Nutzer generierst, im Block Store speichern. Sie können dieses Token mit einem eindeutigen Schlüsselpaarwert speichern, der maximal 4 KB pro Eintrag umfasst. Rufen Sie zum Speichern des Tokens setBytes() und setKey() für eine 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)
}
Standardtoken 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 den Wiederherstellungsvorgang auf einem neuen Gerät durchläuft, überprüfen die Google Play-Dienste zuerst den Nutzer und rufen dann deine Block Store-Daten ab. Der Nutzer hat der Wiederherstellung Ihrer App-Daten im Rahmen des Wiederherstellungsvorgangs bereits zugestimmt, sodass keine zusätzlichen Einwilligungen erforderlich sind. Wenn der Nutzer Ihre App öffnet, können Sie Ihr Token aus dem Block Store anfordern, indem Sie retrieveBytes() aufrufen. Das abgerufene Token kann dann verwendet werden, um den Nutzer auf dem neuen Gerät angemeldet zu lassen.
Im folgenden Beispiel wird gezeigt, wie Sie mehrere Tokens anhand bestimmter Schlüssel 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<String> 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 Beispiel wird gezeigt, wie Sie alle in BlockStore gespeicherten Tokens abrufen.
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)
}
Im folgenden Beispiel wird gezeigt, 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 durchläuft den User-Flow zur Abmeldung.
- 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 von Schlüsseln festlegen, die gelöscht werden müssen.
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<String> 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 im Block Store 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
// Delete all data.
val deleteAllRequest = DeleteBytesRequest.Builder()
.setDeleteAll(true)
.build()
client.deleteBytes(deleteAllRequest)
.addOnSuccessListener { result -> Log.d(TAG, "Any data found and deleted? $result") }
Ende-zu-Ende-Verschlüsselung
Damit die Ende-zu-Ende-Verschlüsselung verfügbar ist, muss auf dem Gerät Android 9 oder höher installiert sein und der Nutzer muss eine Displaysperre (PIN, Muster oder Passwort) für sein Gerät eingerichtet haben. Sie können prüfen, ob die Verschlüsselung auf dem Gerät verfügbar ist, indem Sie isEndToEndEncryptionAvailable() aufrufen.
Im folgenden Beispiel wird gezeigt, wie Sie prüfen, ob die Verschlüsselung während der Cloud-Sicherung verfügbar ist:
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 die Methode setShouldBackupToCloud() zu Ihrem StoreBytesData-Objekt hinzu. Block Store sichert die gespeicherten Byte regelmäßig in der Cloud, wenn setShouldBackupToCloud() auf „true“ gesetzt ist.
Im folgenden Beispiel wird gezeigt, wie Sie die Cloud-Sicherung nur dann 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.")
}
}
Testen
Verwenden Sie während der Entwicklung die folgenden Methoden, um die Wiederherstellungsabläufe zu testen.
Deinstallation und Neuinstallation auf demselben Gerät
Wenn der Nutzer Sicherungsdienste aktiviert (kann unter Einstellungen > Google > Sicherung geprüft werden), bleiben Block Store-Daten auch nach der Deinstallation und Neuinstallation einer App erhalten.
So können Sie die Funktion testen:
- Binden Sie die Block Store API in Ihre Test-App ein.
- Verwenden Sie die Test-App, um die Block Store API aufzurufen und Ihre Daten zu speichern.
- Deinstallieren Sie die Test-App und installieren Sie sie dann auf demselben Gerät neu.
- Rufe mit der Test-App die Block Store API auf, um deine Daten abzurufen.
- Prüfen Sie, ob die abgerufenen Byte mit den vor der Deinstallation gespeicherten Byte übereinstimmen.
Von Gerät zu Gerät
In den meisten Fällen ist dazu ein Zurücksetzen des Zielgeräts auf die Werkseinstellungen erforderlich. Anschließend kannst du die kabellose Wiederherstellung für Android oder die Wiederherstellung per Kabel von Google (für unterstützte Geräte) starten.
Cloud-Wiederherstellung
- Binden Sie die Block Store API in Ihre Test-App ein. Die Test-App muss im Google Play Store eingereicht werden.
- Rufe auf dem Quellgerät mit der Test-App die Block Store API auf, um deine Daten zu speichern. Setze dabei
shouldBackUpToCloudauftrue. - Auf Geräten mit Android 8.0 (API-Level 26) oder 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“.
- So können Sie prüfen, ob die Cloud-Sicherung mit Block Store erfolgreich war:
- Suchen Sie nach Abschluss der Sicherung nach Logzeilen mit dem Tag
[CloudSyncBackupTaskService]. - Die Ausgabe sollte etwa so aussehen:
..., [CloudSyncBackupTaskService] sync result: SUCCESS,..., uploaded size: [size] bytes ...
- Suchen Sie nach Abschluss der Sicherung nach Logzeilen mit dem Tag
- Nach einer Block Store-Cloud-Sicherung gibt es eine fünfminütige „Abkühlphase“. Wenn Sie innerhalb dieser 5 Minuten auf die Schaltfläche „Jetzt sichern“ klicken, wird keine weitere Block Store-Cloud-Sicherung ausgelöst.
- So können Sie prüfen, ob die Cloud-Sicherung mit Block Store erfolgreich war:
- Setze das Zielgerät auf die Werkseinstellungen zurück und führe eine Wiederherstellung aus der Cloud durch. Wählen Sie die Option zum Wiederherstellen Ihrer Test-App während des Wiederherstellungsvorgangs aus. Weitere Informationen zu Cloud-Wiederherstellungsabläufen finden Sie unter Unterstützte Cloud-Wiederherstellungsabläufe.
- Verwenden Sie auf dem Zielgerät die Test-App, um die Block Store API aufzurufen und Ihre Daten abzurufen.
- Prüfen Sie, ob die abgerufenen Byte mit den auf dem Quellgerät gespeicherten Byte übereinstimmen.
Geräteanforderungen
Prüfe die folgenden Anforderungen für Geräte, die an Block Store-Vorgängen teilnehmen.
Ende-zu-Ende-Verschlüsselung
- Die Ende-zu-Ende-Verschlüsselung wird auf Geräten mit Android 9 (API 29) oder 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 werden und die Daten des Nutzers korrekt verschlüsseln kann.
Wiederherstellung von Gerät zu Gerät
Für die Wiederherstellung von Gerät zu Gerät benötigst du ein Quell- und ein Zielgerät. Das sind die beiden Geräte, zwischen denen Daten übertragen werden.
Auf Quellgeräten muss Android 6 (API 23) oder höher installiert sein, damit eine Sicherung erstellt werden kann.
Zielgeräte mit Android 9 (API 29) oder höher, um die Wiederherstellung zu ermöglichen.
Weitere Informationen zur Wiederherstellung von Gerät zu Gerät findest du unter Unterstützte Abläufe für die Wiederherstellung von Gerät zu Gerät.
Ablauf für Cloud-Sicherung und -Wiederherstellung
Für die Cloud-Sicherung und ‑Wiederherstellung sind ein Quell- und ein Zielgerät erforderlich.
Auf Quellgeräten muss Android 6 (API 23) oder höher installiert sein, damit eine Sicherung möglich ist.
Zielgerä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.