ブロック ストア

新しい Android のセットアップ時に、多くのユーザーが依然として自分の認証情報を管理している できます。この手動プロセスは難しくなりがちで、 向上させることができますBlock Store API(Google Play が提供するライブラリ) サービスでは、この問題を解決するために、アプリで保存する方法を ユーザー認証情報を管理でき、保存に伴う複雑さや ユーザー パスワード。

Block Store API を使用すると、アプリが後で利用可能なデータを保存できるようになります。 新しいデバイスでユーザーを再認証する必要があります。これにより ログイン画面を見る必要がないため、シームレスなユーザー エクスペリエンスが実現します。 新しいデバイスで初めてアプリを起動するとき

Block Store を使用するメリットは次のとおりです。

  • デベロッパー向けの暗号化認証情報ストレージ ソリューション。クルデンシャルは エンドツーエンドの暗号化が適用されます
  • ユーザー名とパスワードの代わりにトークンを保存します。
  • ログインフローの煩わしさを解消します。
  • 複雑なパスワードを管理する負担からユーザーを解放します。
  • Google がユーザーの ID を確認します。
で確認できます。

始める前に

アプリを準備するには、以下のセクションに示す手順を完了します。

アプリを設定する

プロジェクト レベルの build.gradle ファイルに、Google の Maven リポジトリを、buildscript と および allprojects セクション:

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

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

Google Play 開発者サービスを追加する Block Store API の依存関係を モジュールの Gradle ビルドファイル、 通常は app/build.gradle です。

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

仕組み

Block Store では、最大 16 バイトの配列を保存および復元できます。 これにより、現在のユーザー セッションに関する重要な情報を保存できます。また、この情報を自由に保存できます。このデータはエンドツーエンドの暗号化が可能で、Block Store をサポートするインフラストラクチャはバックアップと復元のインフラストラクチャ上に構築されています。

このガイドでは、ユーザーのトークンを Block Store に保存するユースケースを取り上げます。 次の手順では、Block Store を利用するアプリがどのように動作するかを概説します。

  1. アプリの認証フローの途中でも、その後も、認証フローの後でいつでも、 ユーザーの認証トークンを Block Store に保存して後で取得できるようにします。
  2. トークンはローカルに保存されるだけでなく、クラウドにバックアップすることもできます。 エンドツーエンドの暗号化が適用されます
  3. ユーザーが新しいデバイスで復元フローを開始すると、データが転送されます。
  4. 復元フロー中にユーザーがアプリを復元した場合、アプリは次のことができます。 保存したトークンを新しいデバイスの Block Store から取得します。

トークンを保存する

ユーザーがアプリにログインしたら、そのユーザー用に生成した認証トークンを Block Store に保存できます。エントリあたり最大 4 KB の一意のキーペア値を使用して、このトークンを格納できます。 トークンを保存するには、setBytes() を呼び出します。 および setKey() あるインスタンスの StoreBytesData.Builder ユーザーの認証情報をソースデバイスに保存します。トークンを保存した後 場合、トークンは暗号化され、デバイスにローカルに保存されます。

次のサンプルは、認証トークンを ローカル デバイスに対して次のコマンドを実行します。

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

デフォルトのトークンを使用する

キーなしで StoreBytes を使用して保存されたデータには、デフォルトのキー 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)
    }

トークンの取得

その後、ユーザーが新しい Compute Engine インスタンスで復元フローを Google Play 開発者サービスは、まずユーザーを確認してからブロックを取得します。 データを保存する。ユーザーは、サービスの一環としてアプリデータを復元することにすでに同意しています 復元フローで使用されるため、追加の同意は必要ありません。ユーザーが開いたとき 次の呼び出しによって、Block Store からトークンをリクエストできます。 retrieveBytes()。 取得したトークンは、ユーザーを新しいデバイスでログイン状態に保つために使用できます。 できます。

次のサンプルは、特定のキーに基づいて複数のトークンを取得する方法を示しています。

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

すべてのトークンを取得しています。

以下は、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)
  }

以下に、デフォルトの鍵を取得する方法の例を示します。

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)

トークンの削除

次の理由により、BlockStore からのトークンの削除が必要になる場合があります。

  • ユーザーがログアウト ユーザーフローを実行します。
  • トークンが取り消されているか、無効です。

トークンを取得する場合と同様に、削除が必要なキーの配列を設定して、削除が必要なトークンを指定できます。

以下は、特定のキーを削除する例です。

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)

すべてのトークンを削除

次の例では、現在 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")
  }

エンドツーエンドの暗号化

エンドツーエンドの暗号化を利用するには、デバイスが Android 9 以降を搭載しており、ユーザーが画面ロックを設定していること (PIN、パターン、またはパスワード)を入力します。暗号化が適用される場合は isEndToEndEncryptionAvailable() を呼び出して、デバイスで利用できるようにします。

次のサンプルは、IP アドレスの使用中に暗号化が使用可能かどうかを確認する方法を示しています。 クラウド バックアップ:

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

クラウド バックアップを有効にする

クラウド バックアップを有効にするには、 setShouldBackupToCloud() メソッドを StoreBytesData 渡されます。ブロックストアは、移行時に保存されたバイト数をクラウドに定期的にバックアップ setShouldBackupToCloud() が true に設定されている。

次のサンプルは、クラウド バックアップの場合にのみクラウド バックアップを有効にする方法を示しています。 エンドツーエンドの暗号化:

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

テスト方法

開発中に以下の方法を使用して、復元をテストします。 できます。

同じデバイスのアンインストールと再インストール

ユーザーがバックアップ サービスを有効にした場合 ([設定] > [Google] > [バックアップ] で確認できます)、店舗データのブロック設定は アプリのアンインストールや再インストール後も変わらない。

テストの手順は次のとおりです。

  1. BlockStore API をテストアプリに統合します。
  2. テストアプリを使用して BlockStore API を呼び出し、データを保存します。
  3. テストアプリをアンインストールしてから、同じデバイスにアプリを再インストールします。
  4. テストアプリを使用して BlockStore API を呼び出し、データを取得します。
  5. 取得したバイトが、以前に格納されたバイト数と同じであることを確認する アンインストールします。
で確認できます。

デバイス間

ほとんどの場合、これを行うには対象デバイスを出荷時の設定にリセットする必要があります。Google Chat では Android のワイヤレス復元フローを開始します。 または Google によるケーブル復元 (サポートされているデバイスの場合)。

クラウドによる復元

  1. Blockstore API をテストアプリに統合します。テストアプリは 。
  2. ソースデバイスで、テストアプリを使用して Blockstore API を呼び出して、 shouldBackUpToCloud を true に設定してデータを暗号化します。
  3. Android O 以降のデバイスでは、Block Store のクラウド バックアップを手動でトリガーできます。 [設定 >Google >バックアップ] の下にある [今すぐバックアップ] ボタンをクリックします。
    1. Block Store のクラウド バックアップが成功したことを確認する手順は次のとおりです。 <ph type="x-smartling-placeholder">
        </ph>
      1. バックアップが完了したら、タグの付いたログ行を検索します。 「CloudSyncBpTkSvc」を選択します。
      2. 次のような行が表示されます。「......, CloudSyncBpTkSvc: sync 結果: SUCCESS, ..., アップロード サイズ: XXX バイト ...」
    2. Block Store のクラウド バックアップ後、5 分間の「クールダウン」期間があります。 その 5 分以内に [今すぐバックアップ] ボタンをクリックしてもトリガーされません。 Block Store のクラウドバックアップです
  4. 対象デバイスを出荷時の設定にリセットし、クラウド復元フローを行います。選択 を使用して、復元フロー中にテストアプリを復元します。詳細については、このモジュールの クラウドの復元フローについては、サポートされているクラウドの復元フローをご覧ください。
  5. ターゲット デバイスで、テストアプリを使用して Blockstore API を呼び出し、 データを取得できます
  6. 取得したバイトが、 接続します。

デバイスの要件

エンドツーエンドの暗号化

  • エンドツーエンドの暗号化は、Android 9(API 29)以降を搭載したデバイスでサポートされています。
  • エンドツーエンドの暗号化が有効になり、ユーザーのデータを正しく暗号化するには、PIN、パターン、またはパスワードで画面ロックが設定されている必要があります。
で確認できます。

デバイス間の復元フロー

デバイス間の復元には、ソースデバイスとターゲット デバイスが必要です。データを転送する 2 つのデバイスになります。

バックアップするには、ソースデバイスが Android 6(API 23)以降である必要があります。

Android 9(API 29)以降を搭載しているデバイスをターゲットにし、復元できるようにします。

デバイス間の復元フローについて詳しくは、こちらをご覧ください。

クラウドのバックアップと復元のフロー

クラウドのバックアップと復元には、ソースデバイスとターゲット デバイスが必要です。

バックアップするには、ソースデバイスが Android 6(API 23)以降である必要があります。

対象デバイスはベンダーによって異なります。Google Pixel デバイスは Android 9(API 29)からこの機能を使用できます。その他のすべてのデバイスは Android 12(API 31)以降を搭載している必要があります。