Wielu użytkowników nadal zarządza swoimi danymi logowania podczas konfigurowania nowego urządzenia z Androidem. Ten ręczny proces może być trudny i często powoduje pogorszenie wrażeń użytkowników. Interfejs Block Store API, biblioteka oparta na Usługach Google Play, ma na celu rozwiązanie tego problemu, umożliwiając aplikacjom zapisywanie danych logowania użytkowników bez złożoności i ryzyka związanego z zapisywaniem haseł użytkowników.
Interfejs Block Store API umożliwia aplikacji przechowywanie danych, które może później pobrać, aby ponownie uwierzytelnić użytkowników na nowym urządzeniu. Ułatwia to użytkownikom korzystanie z aplikacji, ponieważ nie muszą oni widzieć ekranu logowania podczas pierwszego uruchomienia aplikacji na nowym urządzeniu.
Korzyści z używania Block Store:
- Rozwiązanie do szyfrowanego magazynu danych logowania dla programistów. Dane logowania są w miarę możliwości w pełni szyfrowane.
- Zapisywanie tokenów zamiast nazw użytkowników i haseł.
- Eliminowanie problemów z procesami logowania.
- Zwalnianie użytkowników z obowiązku zarządzania złożonymi hasłami.
- Google weryfikuje tożsamość użytkownika.
Zanim zaczniesz
Aby przygotować aplikację, wykonaj czynności opisane w tych sekcjach.
Konfiguracja aplikacji
W pliku build.gradle na poziomie projektu dodaj repozytorium Google Maven do sekcji buildscript
i allprojects:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
Dodaj zależność Usług Google Play dla interfejsu Block Store API do pliku build.gradle modułu. Jest to zwykle app/build.gradle:
dependencies {
implementation 'com.google.android.gms:play-services-auth-blockstore:16.4.0'
}
Jak to działa
Block Store umożliwia programistom zapisywanie i przywracanie maksymalnie 16 tablic bajtów. Dzięki temu możesz zapisywać ważne informacje dotyczące bieżącej sesji użytkownika i masz możliwość zapisywania tych informacji w dowolny sposób. Te dane mogą być w pełni szyfrowane, a infrastruktura obsługująca Block Store jest oparta na infrastrukturze tworzenia i przywracania kopii zapasowych.
W tym przewodniku omówimy przypadek użycia polegający na zapisywaniu tokena użytkownika w Block Store. Poniższe kroki opisują, jak działa aplikacja korzystająca z Block Store:
- Podczas procesu uwierzytelniania aplikacji lub w dowolnym momencie później możesz zapisać token uwierzytelniania użytkownika w Block Store, aby móc go później pobrać.
- Token będzie przechowywany lokalnie i można go też zapisać w chmurze. W miarę możliwości będzie on w pełni szyfrowany.
- Dane są przesyłane, gdy użytkownik rozpocznie proces przywracania na nowym urządzeniu.
- Jeśli użytkownik przywróci Twoją aplikację podczas procesu przywracania, będzie ona mogła pobrać zapisany token z Block Store na nowym urządzeniu.
Zapisywanie tokena
Gdy użytkownik zaloguje się w Twojej aplikacji, możesz zapisać w Block Store token uwierzytelniania wygenerowany dla tego użytkownika. Możesz przechowywać ten token za pomocą unikalnej pary klucz-wartość, która może mieć maksymalnie 4 KB na wpis. Aby zapisać token, wywołaj
setBytes() i setKey() w instancji
StoreBytesData.Builder, aby zapisać dane logowania użytkownika na urządzeniu
źródłowym. Po zapisaniu tokena w Block Store jest on szyfrowany i przechowywany lokalnie na urządzeniu.
Ten przykład pokazuje, jak zapisać token uwierzytelniania na urządzeniu lokalnym:
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) }
Używanie domyślnego tokena
Dane zapisane za pomocą StoreBytes bez klucza używają domyślnego klucza BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
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) }
Pobieranie tokena
Gdy użytkownik przejdzie proces przywracania na nowym urządzeniu, Usługi Google Play najpierw zweryfikują użytkownika, a następnie pobiorą dane Block Store. Użytkownik wyraził już zgodę na przywrócenie danych aplikacji w ramach procesu przywracania, więc nie są wymagane żadne dodatkowe zgody. Gdy użytkownik otworzy Twoją aplikację, możesz poprosić
o token z Block Store, wywołując metodę retrieveBytes(). Pobrany token może być używany do utrzymywania użytkownika zalogowanego na nowym urządzeniu.
Ten przykład pokazuje, jak pobrać wiele tokenów na podstawie określonych kluczy.
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 ListrequestedKeys = 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) }
Pobieranie wszystkich tokenów
Poniżej znajdziesz przykład pobierania wszystkich tokenów zapisanych w BlockStore.
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) }
Poniżej znajdziesz przykład pobierania klucza domyślnego.
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)
Usuwanie tokenów
Usuwanie tokenów z BlockStore może być wymagane z tych powodów:
- Użytkownik przechodzi proces wylogowania.
- Token został unieważniony lub jest nieprawidłowy.
Podobnie jak w przypadku pobierania tokenów, możesz określić, które tokeny mają zostać usunięte, ustawiając tablicę kluczy, które mają zostać usunięte.
Ten przykład pokazuje, jak usunąć określone klucze:
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 ListrequestedKeys = 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)
Usuwanie wszystkich tokenów
Ten przykład pokazuje, jak usunąć wszystkie tokeny zapisane obecnie w BlockStore:
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 keyBlockstoreClient.DEFAULT_BYTES_DATA_KEYcan be used in theRetrieveBytesRequestinstance 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")
}
Włączanie tworzenia kopii zapasowej w chmurze
Aby włączyć tworzenie kopii zapasowej w chmurze, dodaj metodę setShouldBackupToCloud() do obiektu
StoreBytesData. Block Store będzie okresowo tworzyć w chmurze kopię zapasową bajtów przechowywanych, gdy setShouldBackupToCloud() jest ustawiona na true.
Ten przykład pokazuje, jak włączyć tworzenie kopii zapasowej w chmurze tylko wtedy, gdy jest ona w pełni szyfrowana:
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.")
}
}
Jak testować
Podczas programowania użyj tych metod, aby przetestować procesy przywracania.
Odinstalowywanie i ponowne instalowanie na tym samym urządzeniu
Jeśli użytkownik włączy usługi tworzenia kopii zapasowej (można to sprawdzić w sekcji Ustawienia > Google > Kopia zapasowa), dane Block Store będą zachowywane po odinstalowaniu i ponownym zainstalowaniu aplikacji.
Aby przetestować tę funkcję, wykonaj te czynności:
- Zintegruj interfejs Block Store API z aplikacją testową.
- Użyj aplikacji testowej, aby wywołać interfejs Block Store API i zapisać dane.
- Odinstaluj aplikację testową, a następnie zainstaluj ją ponownie na tym samym urządzeniu.
- Użyj aplikacji testowej, aby wywołać interfejs Block Store API i pobrać dane.
- Sprawdź, czy pobrane bajty są takie same jak te, które zostały zapisane przed odinstalowaniem.
Między urządzeniami
W większości przypadków będzie to wymagało przywrócenia ustawień fabrycznych na urządzeniu docelowym. Następnie możesz przejść proces przywracania bezprzewodowego Androida lub przywracania za pomocą kabla Google (w przypadku obsługiwanych urządzeń).
Przywracanie z chmury
- Zintegruj interfejs Block Store API z aplikacją testową. Aplikacja testowa musi zostać przesłana do Sklepu Play.
- Na urządzeniu źródłowym użyj aplikacji testowej, aby wywołać interfejs Block Store API i zapisać dane, ustawiając wartość
shouldBackUpToCloudnatrue. - Na urządzeniach z Androidem O i nowszym możesz ręcznie wywołać tworzenie kopii zapasowej w chmurze Block Store: otwórz Ustawienia > Google > Kopia zapasowa i kliknij przycisk „Utwórz kopię zapasową”.
- Aby sprawdzić, czy tworzenie kopii zapasowej w chmurze Block Store się powiodło:
- Po zakończeniu tworzenia kopii zapasowej wyszukaj wiersze logu z tagiem „CloudSyncBpTkSvc”.
- Powinny się pojawić wiersze takie jak ten: „......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., uploaded size: XXX bytes ...”
- Po utworzeniu kopii zapasowej w chmurze Block Store następuje 5-minutowy okres „ochłodzenia”. W ciągu tych 5 minut kliknięcie przycisku „Utwórz kopię zapasową” nie spowoduje utworzenia kolejnej kopii zapasowej w chmurze Block Store.
- Aby sprawdzić, czy tworzenie kopii zapasowej w chmurze Block Store się powiodło:
- Przywróć urządzenie docelowe do ustawień fabrycznych i przejdź proces przywracania z chmury. Podczas procesu przywracania wybierz przywrócenie aplikacji testowej. Więcej informacji o procesach przywracania z chmury znajdziesz w sekcji Obsługiwane procesy przywracania z chmury.
- Na urządzeniu docelowym użyj aplikacji testowej, aby wywołać interfejs Block Store API i pobrać dane.
- Sprawdź, czy pobrane bajty są takie same jak te, które zostały zapisane na urządzeniu źródłowym.
Wymagania dotyczące urządzeń
Pełne szyfrowanie
- Pełne szyfrowanie jest obsługiwane na urządzeniach z Androidem 9 (API 29) lub nowszym.
- Aby włączyć pełne szyfrowanie i prawidłowo zaszyfrować dane użytkownika, na urządzeniu musi być ustawiona blokada ekranu z kodem PIN, wzorem lub hasłem.
Proces przywracania między urządzeniami
Przywracanie między urządzeniami wymaga urządzenia źródłowego i docelowego. Będą to 2 urządzenia, między którymi będą przesyłane dane.
Aby utworzyć kopię zapasową, urządzenia źródłowe muszą mieć Androida 6 (API 23) lub nowszego.
Aby przywrócić dane, urządzenia docelowe muszą mieć Androida 9 (API 29) lub nowszego.
Więcej informacji o procesie przywracania między urządzeniami znajdziesz tutaj.
Proces tworzenia i przywracania kopii zapasowej w chmurze
Tworzenie i przywracanie kopii zapasowej w chmurze wymaga urządzenia źródłowego i urządzenia docelowego.
Aby utworzyć kopię zapasową, urządzenia źródłowe muszą mieć Androida 6 (API 23) lub nowszego.
Urządzenia docelowe są obsługiwane w zależności od producenta. Urządzenia Pixel mogą korzystać z tej funkcji od Androida 9 (API 29), a wszystkie inne urządzenia muszą mieć Androida 12 (API 31) lub nowszego.