حظر متجر

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

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

تشمل مزايا استخدام متجر الحظر ما يلي:

  • حل تخزين بيانات الاعتماد المشفَّرة للمطوّرين تخضع بيانات الاعتماد للتشفير التام بين الأطراف إن أمكن.
  • حفظ الرموز المميّزة بدلاً من أسماء المستخدمين وكلمات المرور
  • يمكنك التخلص من الصعوبات التي تحدث أثناء عمليات تسجيل الدخول.
  • وفِّر على المستخدمين عبء إدارة كلمات المرور المعقدة.
  • تتحقّق Google من هوية المستخدم.

قبل البدء

لإعداد تطبيقك، يُرجى إكمال الخطوات الواردة في الأقسام التالية.

إعداد تطبيقك

في ملف build.gradle على مستوى المشروع، يُرجى تضمين مستودع Maven من Google في كل من القسمَين buildscript وallprojects:

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

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

أضِف تبعية خدمات Google Play لواجهة برمجة تطبيقات Play Store إلى ملف إصدار Gradle للوحدة، الذي يكون عادةً app/build.gradle:

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

آلية العمل

تسمح أداة الحظر Store للمطوّرين بحفظ واستعادة صفائف يصل حجمها إلى 16 بايت. يسمح لك هذا بحفظ المعلومات المهمة المتعلقة بجلسة المستخدم الحالية ويوفر المرونة في حفظ هذه المعلومات كيفما تشاء. يمكن أن تخضع هذه البيانات للتشفير التام بين الأطراف، وقد تم إنشاء البنية الأساسية التي تتوافق مع بروتوكول "متجر الكتل" على أساس البنية الأساسية لميزة "الاحتفاظ بنسخة احتياطية والاستعادة".

يتناول هذا الدليل حالة الاستخدام الخاصة بحفظ الرمز المميّز للمستخدم في "متجر الحظر". توضّح الخطوات التالية آلية عمل أحد التطبيقات التي تستخدم متاجر الحظر:

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

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

عندما يسجّل أحد المستخدمين الدخول إلى تطبيقك، يمكنك حفظ الرمز المميّز للمصادقة الذي تنشئه لهذا المستخدم في متجر الحظر. ويمكنك تخزين هذا الرمز المميّز باستخدام قيمة فريدة لزوج مفاتيح يبلغ الحد الأقصى لها 4 كيلوبايت لكل إدخال. لتخزين الرمز المميّز، اتّصِل بالرمزَين 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_byte_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" أولاً من هوية المستخدم، ثم تسترد بيانات "متجر الحظر". سبق أن وافق المستخدم على استعادة بيانات تطبيقك كجزء من عملية الاستعادة، لذا لا حاجة إلى موافقات إضافية. عندما يفتح المستخدم تطبيقك، يمكنك طلب الرمز المميّز من "متجر الحظر" من خلال الاتصال بالرقم 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 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)
  }

جارٍ استرداد جميع الرموز المميّزة.

في ما يلي مثال على كيفية استرداد جميع الرموز المميّزة المحفوظة في 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)
  }

في ما يلي مثال على كيفية استرداد المفتاح التلقائي.

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 أو إصدار أحدث وأن يضبط المستخدم قفل الشاشة (رقم التعريف الشخصي أو النقش أو كلمة المرور) للجهاز. يمكنك التحقّق مما إذا كان التشفير سيكون متاحًا على الجهاز من خلال الاتصال على isEndToEndEncryptionAvailable().

يعرض النموذج التالي كيفية التحقق مما إذا كان التشفير متاحًا أثناء النسخ الاحتياطي على السحابة الإلكترونية:

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

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

لتفعيل ميزة الاحتفاظ بنسخة احتياطية على السحابة الإلكترونية، أضِف الإجراء setShouldBackupToCloud() إلى عنصر StoreBytesData. ستعمل أداة حظر المتجر على الاحتفاظ بنسخة احتياطية بشكل دوري من وحدات البايت المخزَّنة في السحابة الإلكترونية عند ضبط 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 > الاحتفاظ بنسخة احتياطية)، سيتم حظر بيانات المتجر في عملية إلغاء تثبيت التطبيق أو إعادة تثبيته.

يمكنك اتباع الخطوات التالية لاختبار ما يلي:

  1. يجب دمج واجهة برمجة التطبيقات OpenStore API مع تطبيقك التجريبي.
  2. استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة التطبيقات BlockStore API لتخزين بياناتك.
  3. ألغِ تثبيت التطبيق التجريبي ثم أعِد تثبيته على الجهاز نفسه.
  4. استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة التطبيقات BlockStore API لاسترداد بياناتك.
  5. تحقَّق من أنّ وحدات البايت التي تم استردادها هي نفسها تلك التي تم تخزينها قبل إلغاء التثبيت.

من جهاز لآخر

وفي معظم الحالات، سيتطلب ذلك إعادة ضبط الجهاز المستهدف على الإعدادات الأصلية. يمكنك بعد ذلك إدخال خطوات استعادة البيانات لاسلكيًا على Android أو استعادة كابل Google (للأجهزة المتوافقة).

استعادة البيانات في السحابة الإلكترونية

  1. يجب دمج واجهة برمجة تطبيقات Openstore API مع تطبيقك التجريبي. ويجب إرسال التطبيق التجريبي إلى "متجر Play".
  2. على الجهاز المصدر، استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة تطبيقاتBlockstore لتخزين بياناتك، مع ضبط shouldBackUpToCloud على "صحيح".
  3. بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل O والإصدارات الأحدث، يمكنك يدويًا تفعيل الاحتفاظ بنسخة احتياطية من Cloud Store من خلال الانتقال إلى الإعدادات > Google > الاحتفاظ بنسخة احتياطية، ثم النقر على زر "الاحتفاظ بنسخة احتياطية الآن".
    1. للتحقّق من نجاح الاحتفاظ بنسخة احتياطية من Cloud Store، يمكنك تنفيذ ما يلي:
      1. بعد انتهاء عملية الاحتفاظ بنسخة احتياطية، ابحث عن سطور السجلّ التي تتضمّن العلامة "CloudSyncBpTkSvc".
      2. من المفترَض أن تظهر لك أسطر مثل: "......, CloudSyncBpTkSvc: Syncresult: Success, ..., محمّل: XXX بايت ..."
    2. بعد الاحتفاظ بنسخة احتياطية على السحابة الإلكترونية من حظر المتجر، هناك فترة "تبريد" مدتها 5 دقائق. خلال هذه الدقائق الخمس، لن يؤدي النقر على زر "الاحتفاظ بنسخة احتياطية الآن" إلى تشغيل نسخة احتياطية أخرى في السحابة الإلكترونية لـ "متجر الكتل".
  4. عليك إعادة ضبط الجهاز المستهدف على الإعدادات الأصلية وإجراء عملية استعادة البيانات على السحابة الإلكترونية. حدد هذا الخيار لاستعادة التطبيق التجريبي أثناء عملية الاستعادة. لمزيد من المعلومات حول عمليات استعادة البيانات في السحابة الإلكترونية، يُرجى الاطّلاع على عمليات استعادة البيانات في السحابة الإلكترونية.
  5. على الجهاز المستهدف، استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة التطبيقات Blockstore API لاسترداد بياناتك.
  6. تأكَّد من أنّ وحدات البايت التي تم استردادها هي نفسها وحدات البايت التي تم تخزينها في الجهاز المصدر.

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

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

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

مسار استعادة الجهاز من جهاز إلى جهاز

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

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

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

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

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

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

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

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