مسدود کردن فروشگاه

بسیاری از کاربران هنوز هنگام راه‌اندازی دستگاه جدید مجهز به Android، اعتبارنامه‌های خود را مدیریت می‌کنند. این فرایند دستی می‌تواند چالش‌برانگیز شود و اغلب منجر به تجربه کاربری ضعیف می‌شود. Block Store API، کتابخانه‌ای که با پشتیبانی خدمات Google Play ارائه می‌شود، به‌دنبال حل این مشکل است و روشی را برای برنامه‌ها فراهم می‌کند تا اعتبارنامه‌های کاربر را بدون پیچیدگی یا خطر امنیتی مرتبط با ذخیره گذرواژه‌های کاربر ذخیره کنند.

Block Store API به برنامه شما اجازه می‌دهد داده‌هایی را ذخیره کند که بعداً می‌تواند برای اصالت‌سنجی مجدد کاربران در دستگاه جدید بازیابی کند. این کار به ارائه تجربه‌ای یکپارچه‌تر برای کاربر کمک می‌کند، زیرا هنگام راه‌اندازی برنامه شما برای اولین‌بار در دستگاه جدید، نیازی به دیدن صفحه ورود به سیستم ندارد.

مزایای استفاده از Block Store شامل موارد زیر است:

  • راهکار ذخیره‌سازی اعتبارنامه رمزگذاری‌شده برای توسعه‌دهندگان. اعتبارنامه‌ها درصورت امکان سرتاسر رمزگذاری می‌شوند.
  • به‌جای نام کاربری و گذرواژه، کد ذخیره کنید.
  • اصطکاک را از جریان‌های ورود به سیستم حذف کنید.
  • کاربران را از بار مدیریت گذرواژه‌های پیچیده نجات دهید.
  • ‫Google هویت کاربر را درستی‌سنجی می‌کند.

قبل‌از شروع

برای آماده‌سازی برنامه‌تان، مراحل بخش‌های زیر را تکمیل کنید.

پیکربندی برنامه

در فایل build.gradle سطح پروژه، مخزن Maven Google را در هر دو بخش 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 به توسعه‌دهندگان اجازه می‌دهد تا ۱۶ آرایه بایت را ذخیره و بازیابی کنند. این به شما امکان می‌دهد اطلاعات مهم مربوط به جلسه کاربر فعلی را ذخیره کنید و انعطاف‌پذیری لازم را برای ذخیره این اطلاعات به هر روشی که دوست دارید ارائه می‌دهد. این داده‌ها می‌تواند سرتاسر رمزگذاری شود و زیرساختی که از Block Store پشتیبانی می‌کند بر زیرساخت «پشتیبان‌گیری و بازیابی» ساخته شده است.

این راهنما مورد استفاده ذخیره کردن کد کاربر در Block Store را پوشش می‌دهد. مراحل زیر نحوه عملکرد برنامه‌ای را که از Block Store استفاده می‌کند شرح می‌دهد:

  1. درطول جریان اصالت‌سنجی برنامه، یا هرزمان پس‌از آن، می‌توانید کد اصالت‌سنجی کاربر را برای بازیابی بعدی در Block Store ذخیره کنید.
  2. این کد به‌صورت محلی ذخیره می‌شود و همچنین می‌توان از آن در فضای ابری پشتیبان‌گیری کرد، و درصورت امکان، به‌صورت سرتاسر رمزگذاری می‌شود.
  3. وقتی کاربر جریان بازیابی را در دستگاه جدیدی شروع می‌کند، داده‌ها منتقل می‌شود.
  4. اگر کاربر برنامه‌تان را درطول جریان بازیابی بازیابی کند، برنامه‌تان می‌تواند ژتون ذخیره‌شده را از Block Store در دستگاه جدید بازیابی کند.

درحال ذخیره کردن کد

وقتی کاربری به سیستم برنامه‌تان وارد می‌شود، می‌توانید کد اصالت‌سنجی‌ای را که برای آن کاربر تولید می‌کنید در Block Store ذخیره کنید. می‌توانید این توکن را بااستفاده از مقدار جفت کلید منحصربه‌فردی که حداکثر ۴ کیلوبایت برای هر ورودی دارد ذخیره کنید. برای ذخیره کردن کد، setBytes() و setKey() را در نمونه‌ای از StoreBytesData.Builder فراخوانی کنید تا اعتبارنامه‌های کاربر در دستگاه مبدأ ذخیره شود. پس‌از ذخیره کردن توکن با Block Store، توکن رمزگذاری می‌شود و به‌صورت محلی در دستگاه ذخیره می‌شود.

نمونه زیر نحوه ذخیره کردن کد اصالت‌سنجی را در دستگاه محلی نشان می‌دهد:

جاوا

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

کاتلین

  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.

جاوا

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

کاتلین

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

درحال بازیابی کد

بعداً، وقتی کاربر جریان بازیابی را در دستگاه جدیدی طی می‌کند، خدمات Google Play ابتدا کاربر را تأیید می‌کند، سپس داده‌های Block Store شما را بازیابی می‌کند. کاربر قبلاً با بازیابی داده‌های برنامه شما به‌عنوان بخشی از جریان بازیابی موافقت کرده است، بنابراین هیچ رضایت دیگری لازم نیست. وقتی کاربر برنامه‌تان را باز می‌کند، می‌توانید با فراخوانی retrieveBytes()، توکن خود را از Block Store درخواست کنید. سپس می‌توان از کد بازیابی‌شده برای حفظ ورود کاربر به سیستم در دستگاه جدید استفاده کرد.

نمونه زیر نشان می‌دهد که چگونه چندین توکن را براساس کلیدهای خاص بازیابی کنید.

جاوا

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

کاتلین

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 آورده شده است.

جاوا

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

کاتلین

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

در زیر نمونه‌ای از نحوه بازیابی کلید پیش‌فرض آورده شده است.

جاوا

BlockStoreClient client = Blockstore.getClient(this);
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
    .build();
client.retrieveBytes(retrieveRequest);

کاتلین

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
  .build()
client.retrieveBytes(retrieveRequest)

درحال حذف کردن داده‌واحدها

ممکن است به دلایل زیر لازم باشد توکن‌ها را از BlockStore حذف کنید:

  • کاربر مراحل جریان کاربر خروج از سیستم را طی می‌کند.
  • توکن لغو شده است یا نامعتبر است.

مشابه بازیابی کردن توکن‌ها، می‌توانید با تنظیم آرایه‌ای از کلیدها که باید حذف شوند، مشخص کنید کدام توکن‌ها باید حذف شوند.

مثال زیر نحوه حذف کلیدهای خاص را نشان می‌دهد:

جاوا

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)

کاتلین

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 را نشان می‌دهد:

جاوا

// 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));

کاتلین

  val deleteAllRequest = DeleteBytesRequest.Builder()
  .setDeleteAll(true)
  .build()
retrieve bytes, the key BlockstoreClient.DEFAULT_BYTES_DATA_KEY can be used
in the RetrieveBytesRequest instance 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")
        }

فعال کردن پشتیبان‌گیری در فضای ابری

برای فعال کردن پشتیبان‌گیری ابری، روش setShouldBackupToCloud() را به شیء StoreBytesData اضافه کنید. وقتی setShouldBackupToCloud() روی درست تنظیم شده باشد، Block Store به‌طور دوره‌ای بایت‌های ذخیره‌شده را در فضای ابری پشتیبان‌گیری می‌کند.

نمونه زیر نشان می‌دهد که چگونه پشتیبان‌گیری ابری را فقط زمانی که پشتیبان‌گیری ابری رمزگذاری سرتاسر شده است فعال کنید:

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 > پشتیبان‌گیری بررسی کنید)، داده‌های Block Store در حذف نصب/بازنصب برنامه حفظ می‌شود.

برای آزمایش می‌توانید این مراحل را دنبال کنید:

  1. Block Store API را در برنامه آزمایشی‌تان ادغام کنید.
  2. از برنامه آزمایشی برای فراخوانی Block Store API برای ذخیره داده‌هایتان استفاده کنید.
  3. برنامه آزمایشی را حذف نصب کنید و سپس برنامه را در همان دستگاه بازنصب کنید.
  4. از برنامه آزمایشی برای فراخوانی Block Store API جهت بازیابی داده‌هایتان استفاده کنید.
  5. درستی‌سنجی کنید که بایت‌های بازیابی‌شده همان بایت‌هایی باشند که قبل‌از حذف نصب ذخیره شده‌اند.

دستگاه به دستگاه

در بیشتر موارد، این کار مستلزم بازنشانی کارخانه‌ای دستگاه مقصد است. سپس می‌توانید وارد جریان بازیابی بی‌سیم Android یا بازیابی با کابل Google شوید (برای دستگاه‌های پشتیبانی‌شده).

بازیابی ابری

  1. Block Store API را با برنامه آزمایشی‌تان ادغام کنید. برنامه آزمایشی باید به «فروشگاه Play» ارسال شود.
  2. در دستگاه منبع، از برنامه آزمایشی برای فراخوانی Block Store API برای ذخیره کردن داده‌هایتان استفاده کنید، و shouldBackUpToCloud را روی true تنظیم کنید.
  3. برای دستگاه‌های دارای Android نسخه O و بالاتر، می‌توانید پشتیبان‌گیری ابری Block Store را به‌صورت دستی راه‌اندازی کنید: به تنظیمات > Google > پشتیبان‌گیری بروید، روی دکمه «اکنون پشتیبان‌گیری شود» کلیک کنید.
    1. برای تأیید اینکه پشتیبان‌گیری ابری Block Store موفقیت‌آمیز بوده است، می‌توانید:
      1. پس‌از اتمام پشتیبان‌گیری، خطوط گزارش را با برچسب «CloudSyncBpTkSvc» جستجو کنید.
      2. باید خطوطی مانند این را ببینید: «......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., uploaded size: XXX bytes ...»
    2. پس‌از پشتیبان‌گیری ابری Block Store، یک دوره «آرام‌سازی» ۵ دقیقه‌ای وجود دارد. در این ۵ دقیقه، کلیک کردن روی دکمه «اکنون پشتیبان‌گیری شود» باعث راه‌اندازی پشتیبان‌گیری ابری Block Store دیگری نخواهد شد.
  4. دستگاه هدف را بازنشانی کارخانه‌ای کنید و جریان بازیابی ابری را طی کنید. را انتخاب کنید تا برنامه آزمایشی‌تان را درطول جریان بازیابی بازیابی کنید. برای اطلاعات بیشتر درباره جریان‌های بازیابی ابری، به جریان‌های بازیابی ابری پشتیبانی‌شده مراجعه کنید.
  5. در دستگاه هدف، از برنامه آزمایشی برای فراخوانی Block store API جهت بازیابی داده‌هایتان استفاده کنید.
  6. تأیید کنید که بایت‌های بازیابی‌شده با بایت‌های ذخیره‌شده در دستگاه منبع یکسان است.

الزامات دستگاه

رمزگذاری سرتاسر

  • رمزگذاری سرتاسر در دستگاه‌های دارای Android 9 (میانای برنامه‌سازی کاربردی ۲۹) و بالاتر پشتیبانی می‌شود.
  • دستگاه باید قفل صفحه‌ای داشته باشد که با پین، الگو، یا گذرواژه تنظیم شده باشد تا رمزگذاری سرتاسر فعال شود و داده‌های کاربر را به‌درستی رمزگذاری کند.

جریان بازیابی دستگاه به دستگاه

برای بازیابی دستگاه به دستگاه، باید دستگاه مبدأ و دستگاه مقصد داشته باشید. این دو دستگاه همان دستگاه‌هایی هستند که داده‌ها را منتقل می‌کنند.

دستگاه‌های مبدأ برای پشتیبان‌گیری باید Android 6 (میانای برنامه‌سازی کاربردی ۲۳) و بالاتر داشته باشند.

دستگاه‌های هدف که Android نسخه ۹ (میانای برنامه‌سازی کاربردی ۲۹) و بالاتر را اجرا می‌کنند، قابلیت بازیابی دارند.

اطلاعات بیشتر درباره جریان بازیابی دستگاه به دستگاه را می‌توانید در اینجا پیدا کنید.

جریان پشتیبان‌گیری و بازیابی ابری

پشتیبان‌گیری و بازیابی ابری به دستگاه مبدأ و دستگاه مقصد نیاز دارد.

دستگاه‌های مبدأ برای پشتیبان‌گیری باید Android 6 (میانای برنامه‌سازی کاربردی ۲۳) و بالاتر داشته باشند.

دستگاه‌های هدف براساس فروشندگانشان پشتیبانی می‌شوند. دستگاه‌های Pixel می‌توانند از این ویژگی از Android 9 (میانای برنامه‌سازی کاربردی ۲۹) استفاده کنند و همه دستگاه‌های دیگر باید Android 12 (میانای برنامه‌سازی کاربردی ۳۱) یا بالاتر را اجرا کنند.