لا يزال العديد من المستخدمين يديرون بيانات اعتمادهم بأنفسهم عند إعداد جهاز جديد يعمل بنظام التشغيل Android. يمكن أن تصبح هذه العملية اليدوية صعبة وغالبًا ما تؤدي إلى تجربة مستخدم سيئة. تهدف واجهة Block Store API، وهي مكتبة مستندة إلى خدمات 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:
- أثناء عملية مصادقة تطبيقك، أو في أي وقت بعد ذلك، يمكنك تخزين رمز المصادقة الخاص بالمستخدم في Block Store لاسترداده لاحقًا.
- سيتم تخزين الرمز المميّز على الجهاز، ويمكن أيضًا الاحتفاظ بنسخة احتياطية منه في السحابة الإلكترونية، مع تشفيره بشكل تام بين الأطراف إن أمكن.
- يتم نقل البيانات عندما يبدأ المستخدم عملية الاستعادة على جهاز جديد.
- إذا استعاد المستخدم تطبيقك أثناء عملية الاستعادة، يمكن لتطبيقك بعد ذلك استرداد الرمز المميّز المحفوظ من 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 ListrequestedKeys = 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 ListrequestedKeys = 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 keyBlockstoreClient.DEFAULT_BYTES_DATA_KEYcan be used in theRetrieveBytesRequestinstance 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 عند إلغاء تثبيت التطبيق أو إعادة تثبيته.
يمكنك اتّباع الخطوات التالية لإجراء الاختبار:
- ادمج واجهة برمجة التطبيقات Block Store في تطبيقك التجريبي.
- استخدِم التطبيق التجريبي لاستدعاء واجهة Block Store API لتخزين بياناتك.
- ألغِ تثبيت تطبيقك التجريبي ثم أعِد تثبيته على الجهاز نفسه.
- استخدِم التطبيق التجريبي لاستدعاء واجهة Block Store API لاسترداد بياناتك.
- تحقَّق من أنّ وحدات البايت التي تم استردادها هي نفسها التي تم تخزينها قبل إلغاء التثبيت.
من جهاز إلى آخر
في معظم الحالات، سيتطلّب ذلك إعادة الضبط على الإعدادات الأصلية لجهاز الاختبار. يمكنك بعد ذلك الدخول إلى عملية الاستعادة اللاسلكية على Android أو عملية الاستعادة باستخدام كابل Google (للأجهزة المتوافقة).
الاستعادة من السحابة الإلكترونية
- دمج واجهة برمجة التطبيقات Block Store في تطبيقك التجريبي، ثم إرسال التطبيق التجريبي إلى "متجر Google Play"
- على الجهاز المصدر، استخدِم التطبيق التجريبي لاستدعاء Block Store API لتخزين
بياناتك، مع ضبط
shouldBackUpToCloudعلىtrue. - بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل Android O والإصدارات الأحدث، يمكنك تفعيل الاحتفاظ بنسخة احتياطية من Block Store في السحابة الإلكترونية يدويًا:
انتقِل إلى الإعدادات > Google > الاحتفاظ بنسخة احتياطية، ثم انقر على الزر "الاحتفاظ بنسخة احتياطية الآن".
- للتحقّق من نجاح عملية الاحتفاظ بنسخة احتياطية في السحابة الإلكترونية من خلال Block Store، يمكنك إجراء ما يلي:
- بعد انتهاء عملية الاحتفاظ بنسخة احتياطية، ابحث عن أسطر السجلّ التي تحمل العلامة "CloudSyncBpTkSvc".
- من المفترض أن تظهر لك أسطر مثل: "......, CloudSyncBpTkSvc: مزامنة result: SUCCESS, ..., حجم التحميل: XXX بايت ..."
- بعد الاحتفاظ بنسخة احتياطية على السحابة الإلكترونية من خلال Block Store، تكون هناك فترة "تهدئة" مدتها 5 دقائق. وخلال هذه الدقائق الخمس، لن يؤدي النقر على زر "الاحتفاظ بنسخة احتياطية الآن" إلى بدء عملية احتفاظ بنسخة احتياطية أخرى في السحابة الإلكترونية من خلال Block Store.
- للتحقّق من نجاح عملية الاحتفاظ بنسخة احتياطية في السحابة الإلكترونية من خلال Block Store، يمكنك إجراء ما يلي:
- أعِد ضبط جهاز الاختبار على الإعدادات الأصلية واتّبِع خطوات الاستعادة من السحابة الإلكترونية. اختَر لاستعادة تطبيقك التجريبي أثناء عملية الاستعادة. لمزيد من المعلومات حول عمليات الاستعادة من السحابة الإلكترونية، يُرجى الاطّلاع على عمليات الاستعادة المتوافقة من السحابة الإلكترونية.
- على جهاز الاختبار، استخدِم التطبيق الاختباري لاستدعاء واجهة Block Store API لاسترداد بياناتك.
- يجب التأكّد من أنّ وحدات البايت التي تم استردادها هي نفسها التي تم تخزينها في الجهاز المصدر.
متطلبات الجهاز
التشفير التام بين الأطراف
- يتوفّر التشفير التام بين الأطراف على الأجهزة التي تعمل بنظام التشغيل Android 9 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث.
- يجب أن يكون الجهاز مزوّدًا بقفل شاشة تم ضبطه باستخدام رقم تعريف شخصي أو نقش أو كلمة مرور ليتم تفعيل التشفير التام بين الأطراف وتشفير بيانات المستخدم بشكل صحيح.
Device to Device Restore Flow
تتطلب عملية الاستعادة من جهاز إلى جهاز أن يكون لديك جهاز مصدر وجهاز مستهدف. سيكون هذان هما الجهازان اللذان ينقلان البيانات.
يجب أن تعمل الأجهزة المصدر بنظام التشغيل Android 6 (المستوى 23 من واجهة برمجة التطبيقات) والإصدارات الأحدث لإجراء عملية الاحتفاظ بنسخة احتياطية.
استهدِف الأجهزة التي تعمل بالإصدار 9 من نظام التشغيل Android (المستوى 29 لواجهة برمجة التطبيقات) والإصدارات الأحدث لتتمكّن من استعادة البيانات.
يمكنك الاطّلاع على مزيد من المعلومات حول عملية الاستعادة من جهاز إلى آخر هنا.
عملية الاحتفاظ بنسخة احتياطية في السحابة الإلكترونية واستعادتها
يتطلّب الاحتفاظ بنسخة احتياطية على السحابة الإلكترونية واستعادتها جهازًا مصدرًا وجهاز اختبار.
يجب أن تعمل الأجهزة المصدر بنظام التشغيل Android 6 (المستوى 23 من واجهة برمجة التطبيقات) والإصدارات الأحدث لإجراء عملية الاحتفاظ بنسخة احتياطية.
تتوفّر أجهزة Target استنادًا إلى مورّديها. يمكن لأجهزة Pixel استخدام هذه الميزة من الإصدار Android 9 (المستوى 29 من واجهة برمجة التطبيقات)، ويجب أن تعمل جميع الأجهزة الأخرى بالإصدار Android 12 (المستوى 31 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث.