فروشگاه بلوک

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

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

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

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

قبل از شروع

برای آماده سازی اپلیکیشن خود، مراحل زیر را انجام دهید.

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

در فایل 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 به توسعه دهندگان اجازه می دهد تا آرایه های 16 بایتی را ذخیره و بازیابی کنند. این به شما امکان می دهد اطلاعات مهم مربوط به جلسه کاربر فعلی را ذخیره کنید و انعطاف پذیری را برای ذخیره این اطلاعات به هر نحوی که دوست دارید ارائه می دهد. این داده‌ها را می‌توان رمزگذاری سرتاسری کرد و زیرساختی که از Block Store پشتیبانی می‌کند در بالای زیرساخت پشتیبان‌گیری و بازیابی ساخته شده است.

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

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

ذخیره توکن

وقتی کاربری وارد برنامه شما می‌شود، می‌توانید رمز احراز هویتی را که برای آن کاربر تولید می‌کنید در Block Store ذخیره کنید. شما می توانید این نشانه را با استفاده از یک مقدار جفت کلید منحصر به فرد که حداکثر 4 کیلوبایت در هر ورودی دارد، ذخیره کنید. برای ذخیره توکن، 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()
client.deleteBytes(deleteAllRequest)
  .addOnSuccessListener { result: Boolean ->
    Log.d(TAG,
          "Any data found and deleted? $result")
  }

رمزگذاری انتها به انتها

برای اینکه رمزگذاری سرتاسر در دسترس باشد، دستگاه باید دارای اندروید 9 یا بالاتر باشد و کاربر باید قفل صفحه (پین، الگو یا رمز عبور) را برای دستگاه خود تنظیم کرده باشد. با فراخوانی isEndToEndEncryptionAvailable() می توانید بررسی کنید که آیا رمزگذاری در دستگاه موجود است یا خیر.

نمونه زیر نشان می دهد که چگونه می توان تأیید کرد که آیا رمزگذاری در طول پشتیبان گیری ابری موجود است یا خیر:

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

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

برای فعال کردن پشتیبان‌گیری ابری، متد setShouldBackupToCloud() را به شی StoreBytesData خود اضافه کنید. زمانی که setShouldBackupToCloud() به عنوان true تنظیم شود، 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 > پشتیبان‌گیری بررسی کرد)، داده‌های فروشگاه مسدود کردن در سراسر برنامه حذف نصب/نصب مجدد باقی می‌ماند.

برای تست می توانید مراحل زیر را دنبال کنید:

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

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

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

بازیابی ابر

  1. Blockstor API را در برنامه آزمایشی خود ادغام کنید. برنامه آزمایشی باید به Play Store ارسال شود.
  2. در دستگاه مبدأ، از برنامه آزمایشی برای فراخوانی API Blockstore برای ذخیره داده‌های خود استفاده کنید، در حالی که بایدBackUpToCloud روی true تنظیم شود.
  3. برای دستگاه‌های O و بالاتر، می‌توانید به صورت دستی یک پشتیبان‌گیری ابری Block Store را راه‌اندازی کنید: به تنظیمات > Google > پشتیبان‌گیری بروید، روی دکمه «اکنون پشتیبان‌گیری» کلیک کنید.
    1. برای تأیید موفقیت آمیز بودن پشتیبان‌گیری ابری Block Store، می‌توانید:
      1. پس از اتمام پشتیبان‌گیری، خطوط گزارش را با برچسب «CloudSyncBpTkSvc» جستجو کنید.
      2. شما باید خطوطی مانند این را ببینید: "......، CloudSyncBpTkSvc: نتیجه همگام سازی: SUCCESS، ...، اندازه آپلود شده: XXX بایت ..."
    2. پس از پشتیبان‌گیری ابری Block Store، یک دوره 5 دقیقه‌ای «سرد شدن» وجود دارد. در عرض این 5 دقیقه، با کلیک بر روی دکمه "Backup Now" یک نسخه پشتیبان دیگر از Block Store ابری راه اندازی نمی شود.
  4. دستگاه مورد نظر را به حالت کارخانه بازنشانی کنید و از یک جریان بازیابی ابری عبور کنید. برای بازیابی برنامه آزمایشی خود در طول جریان بازیابی، انتخاب کنید. برای اطلاعات بیشتر درباره جریان‌های بازیابی ابر، به جریان‌های بازیابی ابر پشتیبانی‌شده مراجعه کنید.
  5. در دستگاه مورد نظر، از برنامه آزمایشی برای فراخوانی API Blockstore برای بازیابی اطلاعات خود استفاده کنید.
  6. بررسی کنید که بایت های بازیابی شده مشابه بایت های ذخیره شده در دستگاه مبدا باشد.

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

رمزگذاری End to End

  • رمزگذاری End to End در دستگاه‌های دارای Android 9 (API 29) و بالاتر پشتیبانی می‌شود.
  • دستگاه باید دارای قفل صفحه با پین، الگو یا رمز عبور باشد تا رمزگذاری سرتاسر فعال شود و داده‌های کاربر به درستی رمزگذاری شود.

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

بازیابی دستگاه به دستگاه به شما نیاز دارد که یک دستگاه منبع و یک دستگاه هدف داشته باشید. این دو دستگاهی هستند که داده ها را منتقل می کنند.

برای پشتیبان‌گیری، دستگاه‌های منبع باید دارای Android 6 (API 23) و بالاتر باشند.

دستگاه‌های دارای Android 9 (API 29) و بالاتر را هدف قرار دهید تا قابلیت بازیابی داشته باشند.

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

Cloud Backup and Restore Flow

پشتیبان گیری و بازیابی ابری به یک دستگاه منبع و یک دستگاه هدف نیاز دارد.

برای پشتیبان‌گیری، دستگاه‌های منبع باید دارای Android 6 (API 23) و بالاتر باشند.

دستگاه های هدف بر اساس فروشندگانشان پشتیبانی می شوند. دستگاه‌های پیکسل می‌توانند از Android 9 (API 29) از این ویژگی استفاده کنند و همه دستگاه‌های دیگر باید از Android 12 (API 31) یا بالاتر استفاده کنند.