חסימת החנות

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

משתמשים רבים עדיין מנהלים את פרטי הכניסה שלהם כשהם מגדירים מכשיר Android חדש. התהליך הידני הזה עלול להיות מאתגר ולרוב גורם לחוויית משתמש גרועה. ה-Block Store API, ספרייה שמופעלת על ידי שירותי Google Play, מנסה לפתור את הבעיה בכך שהיא מציעה לאפליקציות לשמור פרטי כניסה של משתמשים, ללא המורכבות או רמת האבטחה הכרוכה בשמירת סיסמאות של משתמשים.

ה-API של ה-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.2.0'
}

איך זה עובד

אפליקציית 'חנות חסימה' מאפשרת למפתחים לשמור ולשחזר עד מערכי 16 בייטים. כך תוכלו לשמור מידע חשוב בקשר לסשן הנוכחי של המשתמש, ותוכלו לשמור את המידע הזה בכל דרך שתרצו. הנתונים האלה יכולים להיות מוצפנים מקצה לקצה והתשתית שתומכת ב-Block Store מבוססת על התשתית של 'גיבוי ושחזור'.

המדריך הזה עוסק בתרחיש לדוגמה של שמירת אסימון של משתמש ב-Block Store. בשלבים הבאים מתואר איך אפליקציה שמשתמשת ב-Block Store תפעל:

  1. במהלך תהליך האימות של האפליקציה, או בכל שלב לאחר מכן, תוכלו לאחסן את אסימון האימות של המשתמש ל-Block Store כדי לאחזר אותו מאוחר יותר.
  2. האסימון יאוחסן באופן מקומי ואפשר יהיה לגבות אותו בענן, עם הצפנה מקצה לקצה.
  3. הנתונים מועברים כשהמשתמש מתחיל תהליך שחזור במכשיר חדש.
  4. אם המשתמש משחזר את האפליקציה בתהליך השחזור, האפליקציה יכולה לאחזר את האסימון השמור מ-Block Store במכשיר החדש.

שמירת האסימון מתבצעת

כשמשתמש נכנס לאפליקציה שלכם, אתם יכולים לשמור ב-Block Store את אסימון האימות שיצרתם בשבילו. אפשר לאחסן את האסימון הזה באמצעות ערך ייחודי של זוג מפתחות, עם ערך מקסימלי של 4KB לכל רשומה. כדי לאחסן את האסימון, קוראים ל-setBytes() ול-'setKey(/android/reference/com/google/android/gms/auth/blockstore/StoreBytesData.Builder.html#setKey(java.lang.String)' במופע של 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 Services מאמת את המשתמש קודם, ואז מאחזר את הנתונים שלכם ב-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 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() מקבלת את הערך True, היא מבצעת גיבוי תקופתי בענן של הבייטים המאוחסנים.

בדוגמה הבאה מוסבר איך מפעילים את הגיבוי בענן רק כשגיבוי בענן מוצפן.

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. משתמשים באפליקציית הבדיקה כדי להפעיל את ה-API של BlockStore כדי לאחזר את הנתונים שלכם.
  5. חשוב לוודא שהבייטים שאוחזרו זהים לנתונים המאוחסנים לפני הסרת ההתקנה.

מכשיר למכשיר

ברוב המקרים, יהיה צורך לאפס את מכשיר היעד להגדרות המקוריות. לאחר מכן תוכלו להזין את תהליך השחזור לצורך חיבור אלחוטי של Android או את שחזור הכבלים של Google (במכשירים נתמכים).

שחזור בענן

  1. משלבים את ה-API של Blockstore באפליקציית הבדיקה. צריך לשלוח את אפליקציית הבדיקה לחנות Play.
  2. במכשיר המקור, משתמשים באפליקציית הבדיקה כדי להפעיל את ה-Blockstore API כדי לאחסן את הנתונים שלכם, כאשר הערך BackBackToCloud מוגדר ל-True.
  3. במכשירים O ודגמים אחרים, ניתן להפעיל באופן ידני גיבוי של Cloud Store בענן: עוברים אל Settings (הגדרות) > Google > Backup (גיבוי > גיבוי) ולוחצים על הלחצן "Backup Now" (גיבוי עכשיו).
    1. כדי לוודא שהגיבוי בענן של Cloud Store בוצע בהצלחה, תוכלו:
      1. אחרי שהגיבוי מסתיים, מחפשים שורות ביומן עם התג 'CloudSyncBpTkSvc'.
      2. אתם אמורים לראות קווים כאלה: '......, CloudSyncBpTkSvc: תוצאה סנכרון: SUCCESS, ..., גודל העלאה: XXX בייטים ...'
    2. לאחר גיבוי בענן של 'חנות בענן', יש תקופת 'קירור' של 5 דקות. תוך 5 דקות, אם תלחצו על הלחצן 'להפעלת הגיבוי' לא יופעל גיבוי נוסף של Cloud Store בענן.
  4. מאפסים את מכשיר היעד להגדרות המקוריות ועוברים לתהליך שחזור בענן. בחרו לשחזר את אפליקציית הבדיקה בתהליך השחזור. מידע נוסף על תהליכי שחזור בענן זמין כאן.
  5. במכשיר היעד, משתמשים באפליקציית הבדיקה כדי להפעיל את ה-API של Blockstore כדי לאחזר את הנתונים שלכם.
  6. חשוב לוודא שהבייטים שאוחזרו זהים לנתונים המאוחסנים במכשיר המקור.

דרישות המכשיר

הצפנה מקצה לקצה

  • אפשר להשתמש בהצפנה מקצה לקצה במכשירים עם Android מגרסה 9 (API 29) ואילך.
  • כדי להפעיל הצפנה מקצה לקצה, במכשיר צריכה להיות נעילת מסך עם קוד אימות, קו ביטול נעילה או סיסמה.

תהליך שחזור מכשיר למכשיר

כדי לשחזר מכשיר למכשיר צריך שיהיה לך מכשיר מקור ומכשיר יעד. אלה הם שני המכשירים שמעבירים נתונים.

כדי לגבות, מכשירי המקור חייבים להיות Android 6 (API 23) ואילך.

צריך לטרגט מכשירים עם Android מגרסה 9 (API 29) ואילך, כך שניתן יהיה לשחזר אותם.

ניתן למצוא כאן מידע נוסף על תהליך שחזור המכשיר למכשיר.

תהליך גיבוי ושחזור בענן

כדי לבצע גיבוי ושחזור בענן צריך מכשיר מקור ומכשיר יעד.

כדי לגבות, מכשירי המקור חייבים להיות Android 6 (API 23) ואילך.

מכשירי Target נתמכים על סמך הספקים שלהם. מכשירי Pixel יכולים להשתמש בתכונה הזו מגרסת Android 9 (API 29), וכל המכשירים האחרים חייבים לכלול Android מגרסה 12 (API 31) ומעלה.