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 prowadzi do pogorszenia wrażeń użytkowników. Interfejs Block Store API, biblioteka obsługiwana przez usługi Google Play, rozwiązuje ten problem, umożliwiając aplikacjom zapisywanie danych logowania użytkownika bez złożoności i ryzyka związanego z zapisywaniem haseł.
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. Dzięki temu użytkownik nie musi widzieć ekranu logowania, gdy po raz pierwszy uruchamia aplikację na nowym urządzeniu.
Zalety korzystania z Block Store:
- Rozwiązanie do przechowywania zaszyfrowanych danych logowania dla deweloperów. Dane logowania są w miarę możliwości w pełni szyfrowane.
- Zapisuj tokeny zamiast nazw użytkowników i haseł.
- Uprość proces logowania.
- Użytkownicy nie muszą już zarządzać złożonymi hasłami.
- Google zweryfikuje tożsamość użytkownika.
Zanim zaczniesz
Aby przygotować aplikację, wykonaj czynności opisane w poniższych sekcjach.
Konfiguracja aplikacji
W sekcjach buildscript i allprojects pliku build.gradle na poziomie projektu dodaj repozytorium Google Maven:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
Dodaj zależność Usług Google Play do 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 deweloperom zapisywanie i przywracanie maksymalnie 16 tablic bajtów. Umożliwia to zapisywanie ważnych informacji dotyczących bieżącej sesji użytkownika i zapewnia elastyczność zapisywania tych informacji w dowolny sposób. Dane te 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 opisujemy przypadek użycia polegający na zapisywaniu tokena użytkownika w Block Store. Poniżej opisujemy, jak działa aplikacja korzystająca z Block Store:
- Podczas procesu uwierzytelniania aplikacji lub w dowolnym momencie po jego zakończeniu możesz zapisać token uwierzytelniania użytkownika w Block Store, aby móc go później pobrać.
- Token będzie przechowywany lokalnie i może być również zapisywany w kopii zapasowej w chmurze, w miarę możliwości z pełnym szyfrowaniem.
- Dane są przenoszone, gdy użytkownik inicjuje proces przywracania na nowym urządzeniu.
- Jeśli użytkownik przywróci aplikację podczas procesu przywracania, aplikacja może pobrać zapisany token z Block Store na nowym urządzeniu.
Zapisywanie tokena
Gdy użytkownik loguje się w aplikacji, możesz zapisać w Block Store token uwierzytelniania wygenerowany dla tego użytkownika. Możesz przechowywać ten token, używając unikalnej pary klucz-wartość, która może mieć maksymalnie 4 KB na wpis. Aby zapisać token, wywołaj metody setBytes() i setKey() w instancji StoreBytesData.Builder. Pozwoli to 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.
Poniższy 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żyj domyślnego tokena
Dane zapisane za pomocą metody StoreBytes bez klucza używają klucza domyślnego 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
Później, gdy użytkownik przejdzie przez proces przywracania na nowym urządzeniu, Usługi Google Play najpierw zweryfikują użytkownika, a następnie pobiorą dane z 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 aplikację, możesz poprosić o token z Block Store, wywołując metodę retrieveBytes(). Pobrany token może być następnie używany do utrzymywania zalogowania użytkownika na nowym urządzeniu.
Poniższy 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) }
Pobieram wszystkie tokeny.
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
Usunięcie tokenów z BlockStore może być konieczne z tych powodów:
- Użytkownik przechodzi przez wzorzec przeglądania wylogowywania.
- 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 wymagają usunięcia.
Poniższy 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)
Usuń wszystkie tokeny
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łącz kopię zapasową w chmurze
Aby włączyć tworzenie kopii zapasowej w chmurze, dodaj metodę setShouldBackupToCloud() do obiektu StoreBytesData. Gdy zasada setShouldBackupToCloud() ma wartość „true”, Block Store będzie okresowo tworzyć w chmurze kopie zapasowe przechowywanych bajtów.
Poniższy przykład pokazuje, jak włączyć tworzenie kopii zapasowej w chmurze tylko wtedy, gdy jest ona w pełni zaszyfrowana:
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 przeprowadzić test
Aby przetestować procesy przywracania, podczas programowania użyj tych metod.
odinstalowanie i ponowna instalacja na tym samym urządzeniu,
Jeśli użytkownik włączy usługi 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 przeprowadzić test, 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 potem ponownie zainstaluj aplikację 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.
Z urządzenia na urządzenie
W większości przypadków będzie to wymagało przywrócenia urządzenia docelowego do ustawień fabrycznych. Następnie możesz przejść do procesu przywracania bezprzewodowego na Androidzie lub przywracania za pomocą kabla Google (w przypadku obsługiwanych urządzeń).
Przywracanie z chmury
- Zintegruj interfejs Block Store API z aplikacją testową. Aplikację testową należy przesłać 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 parametr
shouldBackUpToCloudnatrue. - Na urządzeniach z systemem Android O lub nowszym możesz ręcznie uruchomić tworzenie kopii zapasowej Block Store w chmurze:
kliknij Ustawienia > Google > Kopia zapasowa, a następnie przycisk „Utwórz kopię zapasową teraz”.
- Aby sprawdzić, czy tworzenie kopii zapasowej w chmurze w Block Store się powiodło, możesz:
- Po zakończeniu tworzenia kopii zapasowej wyszukaj wiersze logu z tagiem „CloudSyncBpTkSvc”.
- Powinny się wyświetlić wiersze podobne do tego: „......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., rozmiar przesyłanych plików: XXX bajtów ...”
- Po utworzeniu kopii zapasowej w chmurze w Block Store następuje 5-minutowy okres „schładzania”. W ciągu tych 5 minut kliknięcie przycisku „Utwórz kopię zapasową teraz” nie spowoduje utworzenia kolejnej kopii zapasowej Block Store w chmurze.
- Aby sprawdzić, czy tworzenie kopii zapasowej w chmurze w Block Store się powiodło, możesz:
- Przywróć urządzenie docelowe do ustawień fabrycznych i przeprowadź proces przywracania z chmury. Wybierz, aby przywrócić aplikację testową podczas procesu przywracania. 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 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 można było włączyć pełne szyfrowanie i prawidłowo szyfrować dane użytkownika, urządzenie musi mieć ustawioną blokadę ekranu za pomocą kodu PIN, wzoru lub hasła.
Proces przywracania danych z urządzenia na urządzenie
Przywracanie z urządzenia na urządzenie wymaga urządzenia źródłowego i docelowego. Będą to 2 urządzenia, między którymi będą przenoszone dane.
Aby można było utworzyć kopię zapasową, na urządzeniach źródłowych musi być zainstalowany Android 6 (API 23) lub nowszy.
Urządzenia docelowe z Androidem 9 (API 29) lub nowszym, aby umożliwić przywracanie.
Więcej informacji o procesie przywracania danych z urządzenia na urządzenie znajdziesz tutaj.
Proces tworzenia i przywracania kopii zapasowej w chmurze
Do tworzenia i przywracania kopii zapasowej w chmurze potrzebne są urządzenie źródłowe i urządzenie docelowe.
Aby można było utworzyć kopię zapasową, na urządzeniach źródłowych musi być zainstalowany Android 6 (API 23) lub nowszy.
Urządzenia docelowe są obsługiwane na podstawie ich dostawców. 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.