حظر متجر

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

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

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

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

قبل البدء

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

إعداد تطبيقك

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

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

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

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

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

طريقة العمل

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

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

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

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

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

من جهاز إلى آخر

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

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

  1. ادمج واجهة برمجة تطبيقات "متجر Play" في تطبيقك التجريبي. يجب إرسال التطبيق التجريبي إلى "متجر Play".
  2. على الجهاز المصدر، استخدِم تطبيق الاختبار لاستدعاء واجهة برمجة التطبيقات Blockstore لتخزين بياناتك، مع ضبط shouldBackUpToCloud على "صحيح".
  3. على الأجهزة O والإصدارات الأحدث، يمكنك يدويًا تفعيل عملية الاحتفاظ بنسخة احتياطية على السحابة الإلكترونية من "متجر حظر المحتوى" عبر الانتقال إلى الإعدادات > Google > الاحتفاظ بنسخة احتياطية، والنقر على زر "الاحتفاظ بنسخة احتياطية الآن".
    1. للتأكّد من نجاح عملية الاحتفاظ بنسخة احتياطية من "متجر حظر المحتوى" على السحابة الإلكترونية، يمكنك إجراء ما يلي:
      1. بعد انتهاء عملية الاحتفاظ بنسخة احتياطية، ابحث عن سطور السجلّ التي تحتوي على العلامة "CloudSyncBpTkSvc".
      2. من المفترض أن تظهر لك سطور مثل هذه: "......, CloudSyncBpTkSvc: المزامنة result: 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 (واجهة برمجة التطبيقات 31) أو الإصدارات الأحدث.