حظر متجر

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

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

تشمل مزايا استخدام 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. توضّح الخطوات التالية طريقة عمل تطبيق يستخدم Block Store:

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

نقل البيانات من جهاز إلى آخر

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

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

  1. ادمج واجهة برمجة التطبيقات Block Store في تطبيق الاختبار، ويجب إرسال تطبيق الاختبار إلى "متجر Play".
  2. على الجهاز المصدر، استخدِم تطبيق الاختبار لاستدعاء Block Store API لتخزين بياناتك، مع ضبط shouldBackUpToCloud على true.
  3. بالنسبة إلى الأجهزة التي تعمل بالإصدار O والإصدارات الأحدث، يمكنك بدء عملية الاحتفاظ بنسخة احتياطية من Block Store على السحابة الإلكترونية يدويًا: انتقِل إلى الإعدادات > Google > الاحتفاظ بنسخة احتياطية، ثم انقر على الزر "الاحتفاظ بنسخة احتياطية الآن".
    1. للتحقّق من نجاح عملية الاحتفاظ بنسخة احتياطية من Block Store على السحابة الإلكترونية، يمكنك إجراء ما يلي:
      1. بعد انتهاء عملية النسخ الاحتياطي، ابحث عن أسطر السجلّ التي تتضمّن العلامة “CloudSyncBpTkSvc”.
      2. من المفترض أن تظهر لك أسطر مثل هذا السطر: "......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., uploaded size: XXX bytes ..."
    2. بعد الاحتفاظ بنسخة احتياطية من Block Store على السحابة الإلكترونية، هناك فترة "استراحة" مدتها 5 دقائق. خلال هذه الدقائق الخمس، لن يؤدي النقر على الزر "الاحتفاظ بنسخة احتياطية الآن" إلى بدء عملية احتياطية أخرى على السحابة الإلكترونية باستخدام Block Store.
  4. أعِد ضبط الجهاز المستهدف على الإعدادات الأصلية واتّبِع خطوات استعادة البيانات من السحابة الإلكترونية. اختَر لاستعادة تطبيقك التجريبي أثناء عملية الاستعادة. لمزيد من المعلومات حول عمليات استعادة البيانات من السحابة الإلكترونية، يُرجى الاطّلاع على عمليات استعادة البيانات من السحابة الإلكترونية المتوافقة.
  5. على الجهاز المستهدف، استخدِم تطبيق الاختبار لاستدعاء Block store API من أجل استرداد بياناتك.
  6. تأكَّد من أنّ وحدات البايت التي تم استردادها هي نفسها التي تم تخزينها في الجهاز المصدر.

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

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

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

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

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

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

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

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

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

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

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

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