حظر متجر

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

تسمح واجهة برمجة التطبيقات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.2.0'
}

آلية العمل

تسمح سياسة الحظر للمطوّرين بحفظ مصفوفات يصل حجمها إلى 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_ فيديوهاتك_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) من خلال الاتصال على الرقم 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)

حذف جميع الرموز المميّزة

يحذف المثال أدناه جميع الرموز المميّزة المحفوظة حاليًا في OpenStore:

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

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

لإتاحة التشفير التام بين الأطراف، يجب أن يعمل الجهاز بالإصدار 9 من نظام التشغيل Android أو إصدار أحدث، ويجب أن يضبط المستخدم قفل شاشة (رقم التعريف الشخصي أو النقش أو كلمة المرور) للجهاز. يمكنك التأكد مما إذا كان التشفير سيكون متاحًا على الجهاز من خلال طلب 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. ادمج واجهة برمجة التطبيقاتBlockStore API مع تطبيقك التجريبي.
  2. استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة التطبيقاتBlockStore API لتخزين بياناتك.
  3. ألغِ تثبيت التطبيق التجريبي ثم أعِد تثبيته على الجهاز نفسه.
  4. استخدِم التطبيق التجريبي لاستدعاء واجهة برمجة التطبيقاتBlockStore API لاسترداد بياناتك.
  5. تحقق من أن وحدات البايت التي تم استردادها هي نفسها تلك التي تم تخزينها قبل إلغاء التثبيت.

من جهاز لآخر

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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