Blokir Toko

Banyak pengguna tetap mengelola kredensial mereka sendiri saat menyiapkan perangkat Android baru. Proses manual ini dapat menjadi sulit dan sering kali mengakibatkan pengalaman pengguna yang buruk. Block Store API, library yang didukung oleh layanan Google Play, berupaya mengatasi hal ini dengan memberikan cara bagi aplikasi untuk menyimpan kredensial pengguna tanpa risiko kompleksitas atau keamanan yang terkait dengan penyimpanan sandi pengguna.

Block Store API memungkinkan aplikasi Anda menyimpan data yang nantinya dapat diambil untuk mengautentikasi ulang pengguna di perangkat baru. Hal ini membantu memberikan pengalaman yang lebih lancar bagi pengguna, karena mereka tidak perlu melihat layar login saat meluncurkan aplikasi Anda untuk pertama kalinya di perangkat baru.

Manfaat menggunakan Block Store antara lain:

  • Solusi penyimpanan kredensial terenkripsi untuk developer. Kredensial dienkripsi secara menyeluruh jika memungkinkan.
  • Simpan token sebagai ganti nama pengguna dan sandi.
  • Menghilangkan hambatan dari alur login.
  • Hemat pengguna dari beban pengelolaan {i>password<i} yang rumit.
  • Google memverifikasi identitas pengguna.

Sebelum memulai

Untuk mempersiapkan aplikasi Anda, selesaikan langkah-langkah di bagian berikut ini.

Mengonfigurasi aplikasi Anda

Dalam file build.gradle level project, sertakan repositori Maven Google di bagian buildscript dan allprojects:

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

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

Tambahkan dependensi layanan Google Play untuk Block Store API ke file build Gradle modul Anda, yang biasanya adalah app/build.gradle:

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

Cara kerjanya

Block Store memungkinkan developer menyimpan dan memulihkan array hingga 16 byte. Hal ini memungkinkan Anda untuk menyimpan informasi penting mengenai sesi pengguna saat ini dan menawarkan fleksibilitas untuk menyimpan informasi ini sesuka Anda. Data ini dapat dienkripsi end-to-end dan infrastruktur yang mendukung Block Store dibangun di atas infrastruktur Pencadangan dan Pemulihan.

Panduan ini akan membahas kasus penggunaan menyimpan token pengguna untuk Block Store. Langkah-langkah berikut menguraikan cara kerja aplikasi yang menggunakan Block Store:

  1. Selama alur autentikasi aplikasi, atau kapan saja setelahnya, Anda dapat menyimpan token autentikasi pengguna ke Block Store untuk diambil pada lain waktu.
  2. Token akan disimpan secara lokal dan juga dapat dicadangkan ke cloud, dengan enkripsi end-to-end jika memungkinkan.
  3. Data ditransfer saat pengguna memulai alur pemulihan di perangkat baru.
  4. Jika pengguna memulihkan aplikasi selama alur pemulihan, aplikasi Anda kemudian dapat mengambil token yang disimpan dari Block Store di perangkat baru.

Menyimpan token

Saat pengguna login ke aplikasi, Anda dapat menyimpan token autentikasi yang dibuat untuk pengguna tersebut untuk Memblokir Toko. Anda dapat menyimpan token ini menggunakan nilai pasangan kunci unik yang memiliki maksimum 4 kb per entri. Untuk menyimpan token, panggil setBytes() dan setKey() pada instance StoreBytesData.Builder untuk menyimpan kredensial pengguna ke perangkat sumber. Setelah Anda menyimpan token dengan Block Store, token tersebut akan dienkripsi dan disimpan secara lokal di perangkat.

Contoh berikut menunjukkan cara menyimpan token autentikasi ke perangkat lokal:

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)
    }

Gunakan token default

Data yang disimpan menggunakan StoreBytes tanpa kunci akan menggunakan kunci default BlockstoreClient.DEFAULT_ Penjual_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)
    }

Mengambil token

Kemudian, saat pengguna melalui alur pemulihan di perangkat baru, layanan Google Play akan memverifikasi pengguna tersebut terlebih dahulu, lalu mengambil data Block Store Anda. Pengguna sudah setuju untuk memulihkan data aplikasi Anda sebagai bagian dari alur pemulihan, jadi tidak diperlukan persetujuan tambahan. Saat pengguna membuka aplikasi, Anda dapat meminta token dari Block Store dengan memanggil retrieveBytes(). Token yang diambil selanjutnya bisa digunakan untuk membuat pengguna tetap login di perangkat baru.

Contoh berikut menunjukkan cara mengambil beberapa token berdasarkan kunci tertentu.

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 blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry 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)
  }

Mengambil semua token.

Berikut adalah contoh cara mengambil semua token yang disimpan ke BlockStore.

Java

BlockstoreClient client = Blockstore.getClient(this)

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

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry 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)
  }

Berikut adalah contoh cara mengambil kunci default.

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)

Menghapus token

Penghapusan token dari BlockStore mungkin diperlukan karena alasan berikut:

  • Pengguna akan melalui alur pengguna logout.
  • Token telah dicabut atau tidak valid.

Mirip dengan mengambil token, Anda dapat menentukan token mana yang perlu dihapus dengan menetapkan array kunci yang memerlukan penghapusan.

Berikut ini contoh untuk menghapus kunci tertentu.

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)

Hapus Semua Token

Contoh di bawah ini menghapus semua token yang saat ini disimpan ke 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")
  }

Enkripsi end-to-end

Agar enkripsi end-to-end tersedia, perangkat harus menjalankan Android 9 atau yang lebih baru, dan pengguna harus menyetel kunci layar (PIN, pola, atau sandi) untuk perangkat. Anda dapat memverifikasi apakah enkripsi akan tersedia di perangkat dengan memanggil isEndToEndEncryptionAvailable().

Contoh berikut menunjukkan cara memverifikasi apakah enkripsi akan tersedia selama pencadangan cloud:

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

Aktifkan pencadangan cloud

Untuk mengaktifkan pencadangan cloud, tambahkan metode setShouldBackupToCloud() ke objek StoreBytesData Anda. Block Store akan mencadangkan secara berkala ke cloud berdasarkan byte yang disimpan saat setShouldBackupToCloud() ditetapkan sebagai true.

Contoh berikut menunjukkan cara mengaktifkan pencadangan cloud hanya jika pencadangan cloud dienkripsi end-to-end:

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.")
          }
        }

Cara menguji

Gunakan metode berikut selama pengembangan untuk menguji alur pemulihan.

Uninstal/instal ulang perangkat yang sama

Jika pengguna mengaktifkan layanan Pencadangan (dapat dicentang di Setelan > Google > Pencadangan), data Block Store akan dipertahankan selama proses uninstal/instal ulang aplikasi.

Anda dapat mengikuti langkah-langkah berikut untuk mengujinya:

  1. Integrasikan BlockStore API ke aplikasi pengujian Anda.
  2. Gunakan aplikasi pengujian untuk memanggil BlockStore API guna menyimpan data Anda.
  3. Uninstal aplikasi pengujian Anda, lalu instal ulang aplikasi Anda di perangkat yang sama.
  4. Gunakan aplikasi pengujian untuk memanggil BlockStore API guna mengambil data Anda.
  5. Pastikan byte yang diambil sama dengan byte yang disimpan sebelum uninstal.

Perangkat ke perangkat

Dalam sebagian besar kasus, tindakan ini memerlukan reset perangkat target ke setelan pabrik. Kemudian, Anda dapat memasuki alur pemulihan nirkabel Android atau pemulihan kabel Google (untuk perangkat yang didukung).

Pemulihan cloud

  1. Integrasikan Blockstore API ke aplikasi pengujian Anda. Aplikasi pengujian harus dikirim ke Play Store.
  2. Di perangkat sumber, gunakan aplikasi pengujian untuk memanggil Blockstore API guna menyimpan data Anda, dengan shouldBackUpToCloud ditetapkan ke true.
  3. Untuk perangkat Android O dan yang lebih baru, Anda dapat memicu pencadangan cloud Block Store secara manual: buka Setelan > Google > Pencadangan, klik tombol "Cadangkan Sekarang".
    1. Untuk memastikan bahwa pencadangan cloud Block Store berhasil, Anda dapat:
      1. Setelah pencadangan selesai, telusuri baris log dengan tag "CloudSyncBpTkSvc".
      2. Anda akan melihat baris seperti ini: “......, CloudSyncBpTkSvc: hasil sinkronisasi: SUCCESS, ..., ukuran yang diupload: XXX byte ...”
    2. Setelah pencadangan cloud Block Store, ada periode “istirahat” selama 5 menit. Dalam waktu 5 menit, mengklik tombol "Cadangkan Sekarang" tidak akan memicu pencadangan cloud Block Store lainnya.
  4. Reset perangkat target ke setelan pabrik dan ikuti alur pemulihan cloud. Pilih untuk memulihkan aplikasi pengujian Anda selama alur pemulihan. Untuk mengetahui informasi selengkapnya tentang alur pemulihan cloud, lihat Alur pemulihan cloud yang didukung.
  5. Pada perangkat target, gunakan aplikasi pengujian untuk memanggil Blockstore API guna mengambil data Anda.
  6. Pastikan byte yang diambil sama dengan byte yang disimpan di perangkat sumber.

Persyaratan Perangkat

Enkripsi Menyeluruh

  • Enkripsi end-to-end didukung di perangkat yang menjalankan Android 9 (API 29) dan yang lebih baru.
  • Perangkat harus menyetel kunci layar dengan PIN, pola, atau sandi agar enkripsi menyeluruh dapat diaktifkan dan mengenkripsi data pengguna dengan benar.

Alur Pemulihan Perangkat ke Perangkat

Pemulihan perangkat ke perangkat mengharuskan Anda memiliki perangkat sumber dan perangkat target. Ini akan menjadi dua perangkat yang mentransfer data.

Perangkat Sumber harus menjalankan Android 6 (API 23) dan yang lebih baru agar dapat melakukan pencadangan.

Target perangkat yang menjalankan Android 9 (API 29) dan yang lebih baru agar dapat dipulihkan.

Informasi selengkapnya tentang alur pemulihan perangkat ke perangkat dapat ditemukan di sini.

Alur Pencadangan dan Pemulihan Cloud

Pencadangan dan pemulihan cloud akan memerlukan perangkat sumber dan perangkat target.

Perangkat Sumber harus menjalankan Android 6 (API 23) dan yang lebih baru agar dapat melakukan pencadangan.

Perangkat Target didukung berdasarkan vendornya. Perangkat Pixel dapat menggunakan fitur ini dari Android 9 (API 29) dan semua perangkat lainnya harus menjalankan Android 12 (API 31) atau yang lebih baru.