حظر متجر

لا يزال العديد من المستخدمين يديرون بيانات اعتمادهم الخاصة عند إعداد جهاز Android جديد. يمكن أن تصبح هذه العملية اليدوية صعبة، وغالبًا ما تؤدي إلى ترك انطباع سيئ لدى المستخدم. تعمل واجهة برمجة التطبيقات Block Store API، وهي مكتبة مدعومة من خدمات Google Play، على حلّ هذه المشكلة من خلال توفير طريقة لحفظ شهادات اعتماد المستخدمين في التطبيقات بدون التعقيد أو المخاطرة الأمنية المرتبطة بحفظ كلمات مرور المستخدمين.

تسمح واجهة برمجة التطبيقات Block Store API لتطبيقك بتخزين البيانات التي يمكنه فيما بعد retrieving استرجاعها لإعادة مصادقة المستخدمين على جهاز جديد. يساعد ذلك في توفير تجربة استخدام أكثر سلاسة للمستخدم، إذ لا يحتاج إلى رؤية شاشة تسجيل الدخول عند تشغيل تطبيقك لأول مرة على الجهاز الجديد.

تشمل مزايا استخدام 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 للمطوّرين حفظ مصفوفات تصل إلى 16 بايت واستعادتها. يتيح لك ذلك حفظ معلومات مهمة بشأن جلسة المستخدم الحالية ويمنحك مرونة حفظ هذه المعلومات بالطريقة التي تريدها. يمكن أن تخضع هذه البيانات للتشفير التام بين الأطراف، ويتم إنشاء البنية الأساسية التي تتوافق مع "متجر الكتل" على البنية الأساسية لميزة "الاحتفاظ بنسخة احتياطية والاستعادة".

سيتناول هذا الدليل حالة استخدام حفظ الرمز المميّز للمستخدم في Block Store. توضِّح الخطوات التالية آلية عمل تطبيق يستخدم Block Store:

  1. أثناء عملية مصادقة تطبيقك أو في أي وقت لاحق، يمكنك تخزين رمز مصادقة المستخدم في Block Store لاسترداده لاحقًا.
  2. سيتم تخزين الرمز المميّز على الجهاز، ويمكن أيضًا الاحتفاظ بنسخة احتياطية منه على السحابة الإلكترونية، وسيتم تشفيره بشكل تام بين الأطراف كلما أمكن ذلك.
  3. يتم نقل البيانات عندما يبدأ المستخدم عملية استعادة على جهاز جديد.
  4. إذا أعاد المستخدم تثبيت تطبيقك أثناء عملية الاستعادة، يمكن لتطبيقك بعد ذلك retrievingاسترداد الرمز المميّز المحفوظ من Block Store على الجهاز الجديد.

حفظ الرمز المميّز

عندما يسجّل مستخدم الدخول إلى تطبيقك، يمكنك حفظ الرمز المميّز للمصادقة الذي تنشئه لهذا المستخدم في Block Store. يمكنك تخزين هذا الرمز المميّز باستخدام قيمة فريدة لزوج مفتاح يبلغ حجمها 4 كيلوبايت كحد أقصى لكل إدخال. لتخزين الرمز المميّز، يمكنك استدعاء setBytes() وsetKey() في مثيل من StoreBytesData.Builder لتخزين بيانات اعتماد المستخدم في الجهاز المصدر. بعد حفظ الرمز المميّز باستخدام Block Store، يتم تشفيره ونقله للتخزين على الجهاز.

يوضّح المثال التالي كيفية حفظ الرمز المميّز للمصادقة في الجهاز المحلي:

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

استرداد الرمز المميّز

لاحقًا، عندما يُجري المستخدم عملية الاستعادة على جهاز جديد، تتحقّق خدمات Google Play أولاً من هوية المستخدم، ثم تسترجع بيانات Block Store. سبق أن وافق المستخدم على استعادة بيانات تطبيقك كجزء من عملية الاستعادة، لذا لا يلزم الحصول على موافقات إضافية. عندما يفتح المستخدم تطبيقك، يمكنك طلب رمزك المميّز من 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()
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. سيُنشئ Block Store بشكل دوري نُسخة احتياطية من ‎megs التي يتم تخزينها في السحابة الإلكترونية عند ضبط setShouldBackupToCloud() على "صحيح".

يوضّح المثال التالي كيفية تفعيل ميزة "النسخ الاحتياطي عبر السحابة الإلكترونية" فقط عندما تكون ميزة "النسخ الاحتياطي عبر السحابة الإلكترونية" مشفَّرة بين الأطراف:

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. بالنسبة إلى الأجهزة التي تعمل بالإصدار 10 من نظام التشغيل Android والإصدارات الأحدث، يمكنك بدء عملية الاحتفاظ بنسخة احتياطية من خلال السحابة الإلكترونية في Block Store يدويًا: انتقِل إلى الإعدادات > Google > الاحتفاظ بنسخة احتياطية، ثم انقر على الزر "الاحتفاظ بنسخة احتياطية الآن".
    1. للتأكّد من نجاح الاحتفاظ بنسخة احتياطية من Block Store في السحابة الإلكترونية، يمكنك إجراء ما يلي:
      1. بعد اكتمال عملية الاحتفاظ بنسخة احتياطية، ابحث عن سطور السجلّ التي تحتوي على العلامة “CloudSyncBpTkSvc”.
      2. من المفترض أن تظهر لك أسطر مثل: "......، CloudSyncBpTkSvc: sync result: SUCCESS، ...، uploaded size: XXX bytes ‎ ..."
    2. بعد الاحتفاظ بنسخة احتياطية من "متجر الأقراص" على السحابة الإلكترونية، تُطبَّق فترة انتظار مدتها 5 دقائق. خلال هذه الدقائق الخمس، لن يؤدي النقر على الزر "الاحتفاظ بنسخة احتياطية الآن" إلى بدء عملية إنشاء نسخة احتياطية أخرى من Block Store في السحابة الإلكترونية.
  4. أعِد ضبط الجهاز المستهدَف على الإعدادات الأصلية واتّبِع خطوات استعادة البيانات من السحابة الإلكترونية. اختَر لاستعادة تطبيقك التجريبي أثناء عملية الاستعادة. لمزيد من المعلومات عن عمليات استعادة البيانات من السحابة الإلكترونية، يُرجى الاطّلاع على عمليات استعادة البيانات المتوافقة من السحابة الإلكترونية.
  5. على الجهاز المستهدَف، استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة التطبيقات Block store API ل retrieving retrieve your data.
  6. تأكَّد من أنّ الوحدات المتسلسلة التي تم استرجاعها هي نفسها التي تم تخزينها في الجهاز المصدر.

متطلبات الجهاز

التشفير التام بين الأطراف

  • يتوفّر التشفير التام بين الأطراف على الأجهزة التي تعمل بالإصدار Android 9 (واجهة برمجة التطبيقات 29) والإصدارات الأحدث.
  • يجب أن يكون الجهاز مزوّدًا بقفل شاشة تم ضبطه باستخدام رقم تعريف شخصي أو نقش أو كلمة مرور لأجل تفعيل ميزة "التشفير التام بين الأطراف" وتشفير بيانات المستخدم بشكل صحيح.

عملية استعادة البيانات من جهاز إلى آخر

تتطلّب عملية الاستعادة من جهاز إلى جهاز توفُّر جهاز مصدر وجهاز مستهدف. هذان الجهازان هما الجهازان اللذان ينقلان البيانات.

يجب أن تعمل أجهزة المصدر بنظام التشغيل Android 6 (المستوى 23 من واجهة برمجة التطبيقات) والإصدارات الأحدث للاحتفاظ بنسخة احتياطية.

استهدِف الأجهزة التي تعمل بالإصدار 9 من نظام التشغيل Android (المستوى 29 لواجهة برمجة التطبيقات) والإصدارات الأحدث لتتمكّن من استعادة البيانات.

يمكنك الاطّلاع هنا على مزيد من المعلومات حول عملية الاستعادة من جهاز إلى آخر.

عملية الاحتفاظ بنسخة احتياطية من البيانات واستعادتها في السحابة الإلكترونية

سيتطلب الاحتفاظ بنسخة احتياطية من البيانات واستعادتها في السحابة الإلكترونية جهازَي مصدر وهدف.

يجب أن تعمل أجهزة المصدر بنظام التشغيل Android 6 (المستوى 23 من واجهة برمجة التطبيقات) والإصدارات الأحدث للاحتفاظ بنسخة احتياطية.

تكون الأجهزة المستهدفة متوافقة استنادًا إلى مورّديها. يمكن لأجهزة Pixel استخدام هذه الميزة من Android 9 (المستوى 29 من واجهة برمجة التطبيقات) ويجب أن تعمل جميع الأجهزة الأخرى بالإصدار Android 12 (المستوى 31 من واجهة برمجة التطبيقات) أو إصدار أحدث.