Chặn cửa hàng

Nhiều người dùng vẫn quản lý thông tin đăng nhập của riêng mình khi thiết lập thiết bị Android mới thiết bị. Quy trình thủ công này có thể trở nên khó khăn và thường mang lại kết quả kém trải nghiệm người dùng. Block Store API, một thư viện được Google Play cung cấp dịch vụ của Google, tìm cách giải quyết vấn đề này bằng cách cung cấp một cách giúp ứng dụng lưu thông tin đăng nhập của người dùng không phức tạp hoặc rủi ro bảo mật liên quan đến việc lưu mật khẩu của người dùng.

Block Store API cho phép ứng dụng của bạn lưu trữ dữ liệu mà sau này ứng dụng có thể truy xuất để xác thực lại người dùng trên thiết bị mới. Điều này giúp mang lại trải nghiệm liền mạch cho người dùng vì họ không cần thấy màn hình đăng nhập khi khởi chạy ứng dụng của bạn lần đầu trên thiết bị mới.

Sau đây là những lợi ích khi sử dụng Block Store:

  • Giải pháp lưu trữ thông tin xác thực được mã hoá dành cho nhà phát triển. Thông tin đăng nhập là được mã hoá hai đầu khi có thể.
  • Lưu mã thông báo thay vì tên người dùng và mật khẩu.
  • Loại bỏ rào cản khỏi quy trình đăng nhập.
  • Giúp người dùng không phải quản lý những mật khẩu phức tạp.
  • Google sẽ xác minh danh tính của người dùng.

Trước khi bắt đầu

Để chuẩn bị cho ứng dụng của bạn, hãy hoàn tất các bước trong những phần sau.

Định cấu hình ứng dụng

Trong tệp build.gradle cấp dự án, hãy thêm Maven của Google kho lưu trữ trong cả buildscriptallprojects phần:

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

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

Thêm Dịch vụ Google Play phần phụ thuộc của Block Store API vào tệp bản dựng Gradle của mô-đun, thường là app/build.gradle:

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

Cách hoạt động

Block Store cho phép các nhà phát triển lưu và khôi phục lên đến 16 byte. Điều này cho phép bạn lưu thông tin quan trọng liên quan đến phiên người dùng hiện tại và mang lại sự linh hoạt để lưu thông tin này theo cách bạn muốn. Dữ liệu này có thể được mã hoá hai đầu và cơ sở hạ tầng hỗ trợ Block Store được xây dựng trên cơ sở hạ tầng Sao lưu và Khôi phục.

Hướng dẫn này sẽ đề cập đến trường hợp sử dụng lưu mã thông báo của người dùng vào Block Store. Các bước sau đây trình bày cách hoạt động của một ứng dụng sử dụng Block Store:

  1. Trong quy trình xác thực của ứng dụng hoặc bất cứ lúc nào sau đó, bạn có thể lưu trữ mã xác thực của người dùng để Chặn Cửa hàng để truy xuất sau.
  2. Mã thông báo sẽ được lưu trữ cục bộ và cũng có thể được sao lưu vào đám mây, được mã hoá hai đầu khi có thể.
  3. Dữ liệu được chuyển khi người dùng bắt đầu quy trình khôi phục trên một thiết bị mới.
  4. Nếu người dùng khôi phục ứng dụng của bạn trong quy trình khôi phục, thì ứng dụng của bạn có thể truy xuất mã thông báo đã lưu từ Block Store trên thiết bị mới.

Đang lưu mã thông báo

Khi người dùng đăng nhập vào ứng dụng, bạn có thể lưu mã thông báo xác thực mà bạn tạo cho người dùng đó vào mục Chặn Cửa hàng. Bạn có thể lưu trữ mã thông báo này bằng cách sử dụng một giá trị cặp khoá duy nhất có tối đa 4 KB mỗi mục nhập. Để lưu trữ mã thông báo, hãy gọi setBytes()setKey() trên bản sao của StoreBytesData.Builder để lưu trữ thông tin xác thực của người dùng vào thiết bị nguồn. Sau khi bạn lưu mã thông báo với Block Store, mã thông báo sẽ được mã hoá và lưu trữ trên thiết bị.

Mẫu sau đây trình bày cách lưu mã thông báo xác thực vào thiết bị cục bộ:

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

Dùng mã thông báo mặc định

Dữ liệu được lưu bằng StoreBytes mà không có khoá sẽ sử dụng khoá mặc định 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)
    }

Truy xuất mã thông báo

Sau đó, khi người dùng trải qua quy trình khôi phục trên thiết bị của bạn, trước tiên, Dịch vụ Google Play sẽ xác minh người dùng, sau đó truy xuất Khối của bạn Lưu trữ dữ liệu. Người dùng đó đã đồng ý khôi phục dữ liệu ứng dụng của bạn theo quy trình khôi phục, nên không cần có sự đồng ý khác. Khi người dùng mở ứng dụng của mình, bạn có thể yêu cầu mã thông báo từ Block Store bằng cách gọi retrieveBytes(). Sau đó, mã thông báo đã truy xuất có thể được dùng để duy trì trạng thái đăng nhập của người dùng trên thiết bị.

Mẫu sau đây cho biết cách truy xuất nhiều mã thông báo dựa trên các khoá cụ thể.

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

Đang truy xuất tất cả mã thông báo.

Dưới đây là ví dụ về cách truy xuất tất cả các mã thông báo đã lưu vào 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)
  }

Dưới đây là ví dụ về cách truy xuất khoá mặc định.

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)

Đang xoá mã thông báo

Bạn có thể phải xoá mã thông báo khỏi BlockStore vì những lý do sau:

  • Người dùng sẽ trải qua quy trình đăng xuất của người dùng.
  • Mã thông báo đã bị thu hồi hoặc không hợp lệ.

Tương tự như việc truy xuất mã thông báo, bạn có thể chỉ định mã thông báo cần xoá bằng cách thiết lập một mảng khoá cần xoá.

Dưới đây là ví dụ về cách xoá một số khoá nhất định.

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)

Xoá tất cả mã thông báo

Ví dụ bên dưới sẽ xoá tất cả các mã thông báo hiện đã lưu vào 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")
  }

Mã hoá hai đầu

Để sử dụng được phương thức mã hoá hai đầu, thiết bị phải: chạy Android 9 trở lên và người dùng phải đặt một phương thức khoá màn hình (mã PIN, hình mở khoá hoặc mật khẩu) cho thiết bị của họ. Bạn có thể xác minh xem liệu quá trình mã hoá có có sẵn trên thiết bị này bằng cách gọi isEndToEndEncryptionAvailable().

Mẫu sau đây trình bày cách xác minh xem tính năng mã hoá có hoạt động trong sao lưu trên đám mây:

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

Bật tính năng sao lưu trên đám mây

Để bật tính năng sao lưu trên đám mây, hãy thêm setShouldBackupToCloud() vào chiến dịch của bạn StoreBytesData . Block Store sẽ sao lưu định kỳ để lưu trữ các byte dữ liệu trên đám mây khi setShouldBackupToCloud() được đặt thành true.

Mẫu sau đây trình bày cách bật tính năng sao lưu trên đám mây chỉ khi tính năng sao lưu trên đám mây được mã hoá hai đầu:

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ách kiểm tra

Sử dụng các phương thức sau trong quá trình phát triển để kiểm thử việc khôi phục luồng.

Gỡ cài đặt/cài đặt lại cùng một thiết bị

Nếu người dùng bật Dịch vụ sao lưu (bạn có thể kiểm tra phần này tại Cài đặt > Google > Sao lưu), dữ liệu Chặn lưu trữ là vẫn tồn tại trong quá trình gỡ cài đặt/cài đặt lại ứng dụng.

Bạn có thể làm theo các bước sau để kiểm tra:

  1. Tích hợp BlockStore API vào ứng dụng kiểm thử của bạn.
  2. Sử dụng ứng dụng kiểm thử để gọi BlockStore API nhằm lưu trữ dữ liệu của bạn.
  3. Gỡ cài đặt ứng dụng kiểm thử rồi cài đặt lại ứng dụng đó trên cùng một thiết bị.
  4. Sử dụng ứng dụng kiểm thử để gọi BlockStore API nhằm truy xuất dữ liệu của bạn.
  5. Xác minh rằng các byte được truy xuất giống với các byte được lưu trữ trước đó gỡ cài đặt.

Từ thiết bị này sang thiết bị khác

Trong hầu hết các trường hợp, bạn sẽ phải đặt lại thiết bị đích về trạng thái ban đầu. Bạn có thể sau đó nhập quy trình khôi phục qua Wi-Fi Android hoặc khôi phục cáp Google (đối với các thiết bị được hỗ trợ).

Khôi phục trên đám mây

  1. Tích hợp Blockstore API vào ứng dụng kiểm thử của bạn. Ứng dụng thử nghiệm cần đã gửi đến Cửa hàng Play.
  2. Trên thiết bị nguồn, hãy dùng ứng dụng kiểm thử để gọi API Blockstore nhằm lưu trữ dữ liệu của bạn khi shouldBackUpToCloud được đặt thành true.
  3. Đối với các thiết bị O trở lên, bạn có thể kích hoạt bản sao lưu trên đám mây của Cửa hàng khối theo cách thủ công: đi đến Cài đặt > Google > Sao lưu, nhấp vào nút “Sao lưu ngay”.
    1. Để xác minh rằng bản sao lưu trên đám mây của Block Store đã thành công, bạn có thể làm như sau:
      1. Sau khi sao lưu xong, hãy tìm các dòng nhật ký có thẻ "CloudSyncBpTkSvc".
      2. Bạn sẽ thấy các dòng như sau: “......, CloudSyncBpTkSvc: sync kết quả: thành công, ..., kích thước đã tải lên: XXX byte ..."
    2. Sau khi sao lưu dữ liệu trên đám mây của Block Store, bạn sẽ có khoảng thời gian “hạ nhiệt” là 5 phút. Trong vòng 5 phút đó, thao tác nhấp vào nút “Sao lưu ngay” sẽ không kích hoạt một bản sao lưu khác trên đám mây của Cửa hàng khối.
  4. Đặt lại thiết bị mục tiêu về trạng thái ban đầu rồi thực hiện quy trình khôi phục trên đám mây. Chọn để khôi phục ứng dụng kiểm thử trong quy trình khôi phục. Để biết thêm thông tin về quy trình khôi phục trên đám mây, hãy xem phần Các quy trình khôi phục trên đám mây được hỗ trợ.
  5. Trên thiết bị mục tiêu, hãy dùng ứng dụng kiểm thử để gọi Blockstore API nhằm truy xuất dữ liệu của bạn.
  6. Xác minh rằng các byte được truy xuất giống như các byte được lưu trữ trong thiết bị nguồn.

Yêu cầu về thiết bị

Mã hoá hai đầu

  • Tính năng mã hoá hai đầu được hỗ trợ trên các thiết bị chạy Android 9 (API 29) trở lên.
  • Thiết bị phải đặt phương thức khoá màn hình bằng mã PIN, hình mở khoá hoặc mật khẩu để tính năng mã hoá hai đầu được bật và mã hoá chính xác dữ liệu của người dùng.

Quy trình khôi phục từ thiết bị này sang thiết bị khác

Việc khôi phục từ thiết bị sang thiết bị khác sẽ yêu cầu bạn phải có thiết bị nguồn và thiết bị mục tiêu. Đây sẽ là hai thiết bị đang chuyển dữ liệu.

Các thiết bị Nguồn phải chạy Android 6 (API 23) trở lên để sao lưu.

Nhắm đến các thiết bị chạy Android 9 (API 29) trở lên để có thể khôi phục.

Bạn có thể xem thêm thông tin về quy trình khôi phục thiết bị tại đây.

Quy trình sao lưu và khôi phục trên đám mây

Tính năng sao lưu và khôi phục trên đám mây sẽ yêu cầu thiết bị nguồn và thiết bị mục tiêu.

Các thiết bị Nguồn phải chạy Android 6 (API 23) trở lên để sao lưu.

Thiết bị mục tiêu được hỗ trợ dựa trên nhà cung cấp tương ứng. Các thiết bị Pixel có thể sử dụng tính năng này trên Android 9 (API cấp 29) và tất cả các thiết bị khác phải chạy Android 12 (API cấp 31) trở lên.