Muchos usuarios siguen administrando sus propias credenciales cuando configuran un nuevo dispositivo Android. dispositivo. Este proceso manual puede volverse desafiante y, a menudo, da como resultado una mala la experiencia del usuario. La API de Block Store, una biblioteca con la tecnología de Google Play servicios, busca resolver esta situación ofreciéndole a las apps una forma de ahorrar credenciales de usuario sin la complejidad ni el riesgo de seguridad asociado con ahorrar las contraseñas de los usuarios.
La API de Block Store permite que tu app almacene datos que luego podrá para volver a autenticar a los usuarios en un dispositivo nuevo. Esto ayuda a proporcionar una experiencia fluida para el usuario, ya que no necesita ver una pantalla de acceso cuando inicies tu app por primera vez en el dispositivo nuevo.
Los beneficios de usar Block Store incluyen los siguientes:
- Solución de almacenamiento de credenciales encriptadas para desarrolladores. Las credenciales son con encriptación de extremo a extremo siempre que sea posible.
- Guarda tokens en lugar de nombres de usuario y contraseñas.
- Elimina las dificultades de los flujos de acceso.
- Evita que los usuarios se encarguen de administrar contraseñas complejas.
- Google verifica la identidad del usuario.
Antes de comenzar
Para preparar tu app, completa los pasos que se indican en las siguientes secciones.
Cómo configurar tu app
En tu archivo build.gradle
de nivel de proyecto, incluye Google Maven's
repositorio en tu buildscript
y allprojects
:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
Agrega los Servicios de Google Play.
de la API de Block Store a tu
archivo de compilación de Gradle del módulo,
que suele ser app/build.gradle
:
dependencies {
implementation 'com.google.android.gms:play-services-auth-blockstore:16.4.0'
}
Cómo funciona
Block Store permite que los desarrolladores guarden y restablezcan hasta 16 arrays de bytes. Esto te permite guardar información importante sobre la sesión del usuario actual y te ofrece la flexibilidad de guardar esta información de la forma que desees. Estos datos pueden encriptarse de extremo a extremo, y la infraestructura que admite Block Store se basa en la infraestructura de copia de seguridad y restablecimiento.
En esta guía, se explica el caso de uso de guardar el token de un usuario en Block Store. En los siguientes pasos, se describe cómo funcionaría una app que utiliza Block Store:
- Durante el flujo de autenticación de tu app, o en cualquier momento posterior, puedes almacenar el token de autenticación del usuario a Block Store para recuperarlo más tarde.
- El token se almacenará de forma local y también se podrá crear una copia de seguridad en la nube. con encriptación de extremo a extremo siempre que sea posible.
- Los datos se transfieren cuando el usuario inicia un flujo de restablecimiento en un dispositivo nuevo.
- Si el usuario restablece tu app durante el flujo de restablecimiento, esta podrá recuperar el token guardado de Block Store en el dispositivo nuevo
Guarda el token
Cuando un usuario accede a tu app, puedes guardar el token de autenticación que generas para ese usuario en Block Store. Puedes almacenar este token con un valor de par de claves único que tenga un máximo de 4 KB por entrada.
Para almacenar el token, llama a setBytes()
.
y setKey()
en una instancia de
StoreBytesData.Builder
para almacenar las credenciales del usuario en el dispositivo de origen. Después de guardar el token
con Block Store, el token se encripta y se almacena localmente en el dispositivo.
En el siguiente ejemplo, se muestra cómo guardar el token de autenticación en el dispositivo local:
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) }
Usar el token predeterminado
Los datos guardados con StoreBytes sin una clave usan la clave predeterminada 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) }
Recupera el token
Más adelante, cuando un usuario realice el flujo de restablecimiento en una nueva
dispositivo, los Servicios de Google Play primero verifican al usuario y, luego, recuperan tu bloqueo
Almacena datos. El usuario ya aceptó restablecer los datos de tu app como parte del
el flujo de restablecimiento, por lo que no se requieren consentimientos adicionales. Cuando el usuario abre
tu app, puedes solicitar tu token de Block Store llamando
retrieveBytes()
El token recuperado se puede usar para mantener al usuario conectado en el nuevo
dispositivo.
En el siguiente ejemplo, se muestra cómo recuperar varios tokens según claves específicas.
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) }
Recuperando todos los tokens.
A continuación, se muestra un ejemplo de cómo recuperar todos los tokens guardados en 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) }
A continuación, se muestra un ejemplo de cómo recuperar la clave predeterminada.
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)
Borra tokens
Es posible que sea necesario borrar tokens de BlockStore por los siguientes motivos:
- El usuario pasa por el flujo de cierre de sesión.
- Se revocó el token o no es válido.
Al igual que con la recuperación de tokens, puedes especificar cuáles deben borrarse configurando un array de claves que requieran eliminación.
A continuación, se muestra un ejemplo de cómo borrar determinadas claves.
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)
Borrar todos los tokens
En el siguiente ejemplo, se borran todos los tokens guardados actualmente en 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() client.deleteBytes(deleteAllRequest) .addOnSuccessListener { result: Boolean -> Log.d(TAG, "Any data found and deleted? $result") }
Encriptación de extremo a extremo
Para que la encriptación de extremo a extremo esté disponible, el dispositivo debe estar
con Android 9 o versiones posteriores, y el usuario debe haber configurado un bloqueo de pantalla
(PIN, patrón o contraseña) del dispositivo. Puedes verificar si la encriptación
estar disponible en el dispositivo llamando a isEndToEndEncryptionAvailable()
.
En el siguiente ejemplo, se muestra cómo verificar si la encriptación estará disponible durante copia de seguridad en la nube:
client.isEndToEndEncryptionAvailable()
.addOnSuccessListener { result ->
Log.d(TAG, "Will Block Store cloud backup be end-to-end encrypted? $result")
}
Habilitar copia de seguridad en la nube
Para habilitar la copia de seguridad en la nube, agrega
setShouldBackupToCloud()
método a tu
StoreBytesData
. Block Store hará copias de seguridad en la nube de los bytes almacenados
setShouldBackupToCloud()
se establece como verdadero.
En el siguiente ejemplo, se muestra cómo habilitar la copia de seguridad en la nube solo cuando la copia de seguridad en la nube se encripta de extremo a extremo:
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.")
}
}
Cómo hacer la prueba
Usa los siguientes métodos durante el desarrollo para probar el restablecimiento a los flujos de trabajo.
Desinstalación y reinstalación del mismo dispositivo
Si el usuario habilita los servicios de copia de seguridad (puedes comprobarlo en Configuración > Google > Copia de seguridad), los datos de Block Store que persistan durante la desinstalación y reinstalación de la app.
Puedes seguir estos pasos para realizar la prueba:
- Integra la API de BlockStore a tu app de prueba.
- Usa la app de prueba para invocar la API de BlockStore y almacenar tus datos.
- Desinstala la app de prueba y vuelve a instalarla en el mismo dispositivo.
- Usa la app de prueba para invocar la API de BlockStore y recuperar tus datos.
- Verifica que los bytes recuperados sean los mismos que se almacenaron antes desinstalación.
De un dispositivo a otro
En la mayoría de los casos, deberás restablecer la configuración de fábrica del dispositivo de destino. Puedes Luego, ingresa al flujo de restablecimiento inalámbrico de Android. o restablecimiento de cables de Google (para dispositivos compatibles).
Restablecimiento de la nube
- Integra la API de Blockstore a tu app de prueba. La app de prueba debe enviados a Play Store.
- En el dispositivo de origen, usa la app de prueba para invocar la API de Blockstore para almacenar los datos, con shouldBackUpToCloud configurado como true.
- Para dispositivos O y superiores, puedes activar manualmente una copia de seguridad en la nube de Block Store:
ve a Configuración > Google > Copia de seguridad, haz clic en el botón “Crear copia de seguridad ahora”.
- Para verificar que la copia de seguridad en la nube de Block Store se haya realizado correctamente, puedes hacer lo siguiente:
- Cuando finalice la copia de seguridad, busca líneas de registro con la etiqueta “CloudSyncBpTkSvc”.
- Deberías ver líneas como estas: “......, CloudSyncBpTkSvc: sync resultado: SUCCESS, ..., tamaño de carga subido: XXX bytes ..."
- Después de una copia de seguridad en la nube de Block Store, hay un período de “inactividad” de 5 minutos. Después de ese plazo, no se activará hacer clic en el botón “Crear copia de seguridad ahora”. otra copia de seguridad en la nube de Block Store.
- Para verificar que la copia de seguridad en la nube de Block Store se haya realizado correctamente, puedes hacer lo siguiente:
- Restableces la configuración de fábrica del dispositivo de destino y pasas por un flujo de restablecimiento en la nube. Seleccionar para restablecer la app de prueba durante el flujo de restablecimiento. Para obtener más información en los flujos de restablecimiento de la nube, consulta Flujos de restablecimiento de nube admitidos.
- En el dispositivo de destino, usa la app de prueba para invocar la API de Blockstore para recuperar tus datos.
- Verifica que los bytes recuperados sean los mismos que se almacenaron en la dispositivo de origen.
Requisitos del dispositivo
Encriptación de extremo a extremo
- La encriptación de extremo a extremo es compatible con dispositivos que ejecutan Android 9 (nivel de API 29) y versiones posteriores.
- El dispositivo debe tener configurado un bloqueo de pantalla con un PIN, un patrón o una contraseña para habilitar la encriptación de extremo a extremo y encriptar correctamente los datos del usuario.
Flujo de restablecimiento de dispositivo a dispositivo
Para el restablecimiento de un dispositivo a otro, deberás tener un dispositivo de origen y uno de destino. Estos serán los dos dispositivos que van a transferir los datos.
Para crear una copia de seguridad, los dispositivos de origen deben ejecutar Android 6 (nivel de API 23) y versiones posteriores.
Orienta los dispositivos que ejecuten Android 9 (nivel de API 29) y versiones posteriores para tener la capacidad de restablecerse.
Obtén más información sobre el flujo de restablecimiento de un dispositivo a otro aquí.
Flujo de copia de seguridad y restablecimiento de Cloud
La copia de seguridad y el restablecimiento en la nube requerirán un dispositivo de origen y uno de destino.
Para crear una copia de seguridad, los dispositivos de origen deben ejecutar Android 6 (nivel de API 23) y versiones posteriores.
Los dispositivos de destino son compatibles según sus proveedores. Los dispositivos Pixel pueden usar esta función a partir de Android 9 (nivel de API 29) y todos los demás dispositivos deben ejecutar Android 12 (nivel de API 31) o una versión posterior.