משתמשים רבים עדיין מנהלים את פרטי הכניסה שלהם כשהם מגדירים מכשיר חדש עם מערכת Android. התהליך הידני הזה עלול להיות מסובך ולרוב הוא פוגע בחוויית המשתמש. ממשק Block Store API, ספרייה שמבוססת על Google Play Services, נועד לפתור את הבעיה הזו. הוא מספק לאפליקציות דרך לשמור פרטי כניסה של משתמשים בלי הסיכון הביטחוני או המורכבות שקשורים לשמירת סיסמאות של משתמשים.
ממשק Block Store API מאפשר לאפליקציה לאחסן נתונים שהיא יכולה לאחזר מאוחר יותר כדי לאמת מחדש משתמשים במכשיר חדש. כך המשתמשים נהנים מחוויה חלקה יותר, כי הם לא צריכים לראות מסך כניסה כשהם מפעילים את האפליקציה בפעם הראשונה במכשיר החדש.
היתרונות של שימוש ב-Block Store כוללים:
- פתרון מוצפן לאחסון אישורים למפתחים. פרטי הכניסה מוצפנים מקצה לקצה כשזה אפשרי.
- שמירת טוקנים במקום שמות משתמש וסיסמאות.
- מצמצמים את החיכוך בתהליכי הכניסה.
- חוסכים מהמשתמשים את הטרחה של ניהול סיסמאות מורכבות.
- Google מאמתת את הזהות של המשתמש.
לפני שמתחילים
כדי להכין את האפליקציה, פועלים לפי השלבים בקטעים הבאים.
הגדרת האפליקציה
בקובץ build.gradle
ברמת הפרויקט, צריך לכלול את מאגר Maven של Google בקטעים buildscript
ו-allprojects
:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
מוסיפים את התלות ב-Google Play services עבור Block Store API
אל קובץ ה-Gradle build של המודול, שבדרך כלל נמצא בנתיב 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 את אסימון האימות שאתם יוצרים עבורו. אפשר לאחסן את הטוקן הזה באמצעות זוג ערכים ייחודי של מפתח, עם מגבלה של 4KB לכל רשומה. כדי לאחסן את האסימון, קוראים ל-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_KEY
can be used in theRetrieveBytesRequest
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
. אם המדיניות setShouldBackupToCloud()
מוגדרת כ-True, Block Store יגבה מעת לעת לענן את הבייטים המאוחסנים.
בדוגמה הבאה אפשר לראות איך להפעיל גיבוי בענן רק כשהגיבוי בענן מוצפן מקצה לקצה:
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 API באפליקציית הבדיקה.
- משתמשים באפליקציית הבדיקה כדי להפעיל את Block Store API ולאחסן את הנתונים.
- מסירים את אפליקציית הבדיקה ומתקינים מחדש את האפליקציה באותו מכשיר.
- משתמשים באפליקציית הבדיקה כדי להפעיל את Block Store API ולאחזר את הנתונים.
- מוודאים שהבייטים שאוחזרו זהים לבייטים שנשמרו לפני ההסרה.
ממכשיר למכשיר
ברוב המקרים, תצטרכו לאפס את מכשיר היעד להגדרות המקוריות. אחרי כן, תוכלו להזין את תהליך השחזור האלחוטי של Android או את תהליך השחזור באמצעות כבל של Google (במכשירים נתמכים).
שחזור מהענן
- משלבים את Block Store API באפליקציית הבדיקה. צריך לשלוח את אפליקציית הבדיקה לחנות Play.
- במכשיר המקור, משתמשים באפליקציית הבדיקה כדי להפעיל את Block Store API ולאחסן את הנתונים, כאשר
shouldBackUpToCloud
מוגדר ל-true
. - במכשירים עם Android בגרסה O ומעלה, אפשר להפעיל גיבוי בענן של Block Store באופן ידני: עוברים אל הגדרות > Google > גיבוי ולוחצים על הלחצן 'גיבוי עכשיו'.
- כדי לוודא שגיבוי Block Store בענן הצליח, אפשר:
- אחרי שהגיבוי מסתיים, מחפשים שורות יומן עם התג CloudSyncBpTkSvc.
- אמורות להופיע שורות כמו: “......, CloudSyncBpTkSvc: sync result: SUCCESS, ..., uploaded size: XXX bytes ...”
- אחרי גיבוי בענן של Block Store, יש תקופת צינון של 5 דקות. במהלך 5 הדקות האלה, לחיצה על הלחצן 'גיבוי עכשיו' לא תפעיל גיבוי נוסף של Block Store בענן.
- כדי לוודא שגיבוי Block Store בענן הצליח, אפשר:
- אפסו את מכשיר היעד להגדרות המקוריות ובצעו שחזור מהענן. בוחרים באפשרות לשחזור אפליקציית הבדיקה במהלך תהליך השחזור. מידע נוסף על תהליכי שחזור בענן זמין במאמר תהליכי שחזור בענן שנתמכים.
- במכשיר היעד, משתמשים באפליקציית הבדיקה כדי להפעיל את Block store API ולאחזר את הנתונים.
- מוודאים שהבייטים שאוחזרו זהים לבייטים שנשמרו במכשיר המקור.
דרישות לגבי מכשירים
הצפנה מקצה לקצה
- הצפנה מקצה לקצה נתמכת במכשירים עם Android 9 (API 29) ומעלה.
- כדי להפעיל הצפנה מקצה לקצה ולהצפין את נתוני המשתמש בצורה נכונה, צריך להגדיר במכשיר נעילת מסך באמצעות קוד אימות, קו ביטול נעילה או סיסמה.
תהליך השחזור ממכשיר למכשיר
כדי לשחזר ממכשיר למכשיר, צריך מכשיר מקור ומכשיר יעד. אלה יהיו שני המכשירים שמעבירים נתונים.
במכשירי המקור צריכה להיות מותקנת מערכת Android מגרסה 6 (API 23) ואילך כדי לגבות את הנתונים.
מכשירים לטירגוט עם Android מגרסה 9 (API 29) ומעלה, כדי לאפשר שחזור.
כאן אפשר למצוא מידע נוסף על תהליך השחזור ממכשיר למכשיר.
תהליך העבודה של גיבוי ושחזור בענן
כדי לגבות ולשחזר את הנתונים בענן, צריך מכשיר מקור ומכשיר יעד.
במכשירי המקור צריכה להיות מותקנת מערכת Android מגרסה 6 (API 23) ואילך כדי לגבות את הנתונים.
יש תמיכה במכשירים מטורגטים על סמך הספקים שלהם. במכשירי Pixel אפשר להשתמש בתכונה הזו מגרסה Android 9 (API 29) ומעלה, ובכל המכשירים האחרים אפשר להשתמש בה מגרסה Android 12 (API 31) ומעלה.