บล็อกร้านค้า

ผู้ใช้จำนวนมากยังคงจัดการข้อมูลเข้าสู่ระบบของตนเองเมื่อตั้งค่าอุปกรณ์ Android เครื่องใหม่ กระบวนการด้วยตนเองนี้อาจทำได้ยากและมักทำให้ผู้ใช้ได้รับประสบการณ์ที่ไม่ดี Block Store API ซึ่งเป็นไลบรารีที่ขับเคลื่อนโดยบริการ Google Play หาวิธีแก้ไขปัญหานี้ด้วยการให้แอปบันทึกข้อมูลเข้าสู่ระบบของผู้ใช้โดยไม่มีความซับซ้อนหรือความเสี่ยงด้านความปลอดภัยที่เกี่ยวข้องกับการบันทึกรหัสผ่านของผู้ใช้

Block Store API ทำให้แอปจัดเก็บข้อมูลที่เรียกใช้ได้ในภายหลังเพื่อตรวจสอบสิทธิ์ผู้ใช้ในอุปกรณ์เครื่องใหม่ได้อีกครั้ง วิธีนี้ช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ราบรื่นยิ่งขึ้นเนื่องจากไม่จำเป็นต้องเห็นหน้าจอลงชื่อเข้าใช้เมื่อเปิดแอปเป็นครั้งแรกในอุปกรณ์เครื่องใหม่

ประโยชน์ของการใช้ 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'
}

วิธีการทำงาน

Block Store ช่วยให้นักพัฒนาซอฟต์แวร์บันทึกและกู้คืนอาร์เรย์สูงสุด 16 ไบต์ได้ วิธีนี้ช่วยให้คุณสามารถบันทึกข้อมูลสำคัญเกี่ยวกับเซสชันของผู้ใช้ปัจจุบัน และสามารถบันทึกข้อมูลนี้ได้ตามต้องการ ข้อมูลนี้สามารถเข้ารหัสจากต้นทางถึงปลายทางได้ และโครงสร้างพื้นฐานที่รองรับ Block Store นั้นสร้างขึ้นจากโครงสร้างพื้นฐานของการสำรองข้อมูลและคืนค่า

คู่มือนี้จะกล่าวถึงกรณีการใช้งานโทเค็นของผู้ใช้ไปยัง Block Store ขั้นตอนต่อไปนี้จะสรุปวิธีการทำงานของแอปที่ใช้ Block Store

  1. ในระหว่างขั้นตอนการตรวจสอบสิทธิ์ของแอปหรือเมื่อใดก็ตามหลังจากนั้น คุณสามารถจัดเก็บโทเค็นการตรวจสอบสิทธิ์ของผู้ใช้เพื่อบล็อก Store เพื่อดึงข้อมูลในภายหลัง
  2. ระบบจะจัดเก็บโทเค็นไว้ในเครื่องและสำรองข้อมูลไปยังระบบคลาวด์ที่เข้ารหัสจากต้นทางถึงปลายทางได้ หากทำได้
  3. ระบบจะโอนข้อมูลเมื่อผู้ใช้เริ่มขั้นตอนการคืนค่าในอุปกรณ์เครื่องใหม่
  4. หากผู้ใช้กู้คืนแอปของคุณระหว่างขั้นตอนการกู้คืน แอปจะเรียกดูโทเค็นที่บันทึกไว้จาก Block Store ในอุปกรณ์เครื่องใหม่ได้

กำลังบันทึกโทเค็น

เมื่อผู้ใช้ลงชื่อเข้าใช้แอป คุณจะบันทึกโทเค็นการตรวจสอบสิทธิ์ที่สร้างให้ผู้ใช้รายดังกล่าวเพื่อบล็อก Store ได้ คุณสามารถจัดเก็บโทเค็นนี้โดยใช้ค่าคู่คีย์ที่ไม่ซ้ำกันซึ่งมีขนาดไม่เกิน 4 KB ต่อรายการ หากต้องการจัดเก็บโทเค็น ให้เรียกใช้ 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 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 ขึ้นไป และผู้ใช้ต้องตั้งค่าการล็อกหน้าจอ (PIN, รูปแบบ หรือรหัสผ่าน) ให้กับอุปกรณ์ คุณสามารถตรวจสอบว่าอุปกรณ์มีการเข้ารหัสหรือไม่โดยโทรไปที่ isEndToEndEncryptionAvailable()

ตัวอย่างต่อไปนี้แสดงวิธีตรวจสอบว่าการเข้ารหัสพร้อมใช้งานระหว่างการสำรองข้อมูลบนระบบคลาวด์หรือไม่

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 > การสำรองข้อมูล) ข้อมูลบล็อกใน Store จะยังคงอยู่ทั่วทั้งการถอนการติดตั้ง/ติดตั้งแอปอีกครั้ง

คุณสามารถทำตามขั้นตอนต่อไปนี้เพื่อทดสอบ

  1. ผสานรวม BlockStore API กับแอปทดสอบ
  2. ใช้แอปทดสอบเพื่อเรียกใช้ BlockStore API เพื่อจัดเก็บข้อมูล
  3. ถอนการติดตั้งแอปทดสอบแล้วติดตั้งแอปในอุปกรณ์เดียวกันอีกครั้ง
  4. ใช้แอปทดสอบเพื่อเรียกใช้ BlockStore API เพื่อเรียกข้อมูล
  5. โดยให้ยืนยันว่าไบต์ที่ดึงมาตรงกับข้อมูลที่เก็บไว้ก่อนถอนการติดตั้ง

ระหว่างอุปกรณ์

ในกรณีส่วนใหญ่ การดำเนินการนี้ต้องมีการรีเซ็ตอุปกรณ์เป้าหมายเป็นค่าเริ่มต้น คุณสามารถป้อนขั้นตอนการคืนค่า Android แบบไร้สายหรือการคืนค่าสายของ Google (สำหรับอุปกรณ์ที่รองรับ)

การคืนค่าระบบคลาวด์

  1. ผสานรวม Blockstore API กับแอปทดสอบ คุณต้องส่งแอปทดสอบไปยัง Play Store
  2. ในอุปกรณ์ต้นทาง ให้ใช้แอปทดสอบเพื่อเรียกใช้ Blockstore API เพื่อจัดเก็บข้อมูล โดยตั้งค่า ifBackUpToCloud เป็น "จริง"
  3. สำหรับอุปกรณ์ O ขึ้นไป คุณสามารถเรียกใช้การสำรองข้อมูลในระบบคลาวด์ของ Block Store ได้ด้วยตนเอง โดยไปที่การตั้งค่า > Google > การสำรองข้อมูล คลิกปุ่ม "สำรองข้อมูลทันที"
    1. หากต้องการยืนยันว่าการสำรองข้อมูลในระบบคลาวด์ของ Block Store สำเร็จ ให้ทำดังนี้
      1. หลังจากสำรองข้อมูลเสร็จแล้ว ให้ค้นหาบรรทัดในบันทึกที่มีแท็ก "CloudSyncBpTkSvc"
      2. คุณควรเห็นบรรทัดที่มีลักษณะเช่นนี้: "......, CloudSyncBpTkSvc: ซิงค์ ผลลัพธ์: สำเร็จ, ..., ขนาดที่อัปโหลด: XXX ไบต์ ..."
    2. หลังจากสำรองข้อมูลในระบบคลาวด์ของ Block Store แล้ว จะมีระยะเวลา "พัก" 5 นาที ภายใน 5 นาทีนั้น การคลิกปุ่ม "สำรองข้อมูลทันที" จะไม่เรียกใช้การสำรองข้อมูลระบบคลาวด์ "บล็อกสโตร์" อีก
  4. รีเซ็ตอุปกรณ์เป้าหมายเป็นค่าเริ่มต้นและดำเนินการตามขั้นตอนการคืนค่าในระบบคลาวด์ เลือกเพื่อคืนค่าแอปทดสอบในระหว่างขั้นตอนการคืนค่า โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับขั้นตอนการคืนค่าระบบคลาวด์ที่หัวข้อขั้นตอนการคืนค่าระบบคลาวด์ที่รองรับ
  5. ในอุปกรณ์เป้าหมาย ให้ใช้แอปทดสอบเพื่อเรียกใช้ Blockstore API เพื่อดึงข้อมูลของคุณ
  6. ตรวจสอบว่าไบต์ที่ดึงมาตรงกับข้อมูลที่เก็บไว้ในอุปกรณ์ต้นทาง

ข้อกำหนดของอุปกรณ์

การเข้ารหัสจากต้นทางถึงปลายทาง

  • การเข้ารหัสจากต้นทางถึงปลายทางใช้ได้ในอุปกรณ์ที่ใช้ Android 9 (API 29) ขึ้นไป
  • อุปกรณ์จะต้องตั้งค่าการล็อกหน้าจอด้วย PIN, รูปแบบ หรือรหัสผ่านเพื่อเปิดใช้การเข้ารหัสจากต้นทางถึงปลายทางและเข้ารหัสข้อมูลของผู้ใช้อย่างถูกต้อง

ขั้นตอนการคืนค่าระหว่างอุปกรณ์

ในการคืนค่าอุปกรณ์ คุณจะต้องมีอุปกรณ์ต้นทางและอุปกรณ์เป้าหมาย อุปกรณ์ 2 เครื่องที่กำลังโอนข้อมูล

อุปกรณ์ต้นทางต้องใช้ Android 6 (API 23) ขึ้นไปเพื่อสำรองข้อมูล

กำหนดเป้าหมายอุปกรณ์ที่ใช้ Android 9 (API 29) ขึ้นไปเพื่อให้สามารถคืนค่าได้

ดูข้อมูลเพิ่มเติมเกี่ยวกับขั้นตอนการคืนค่าอุปกรณ์ไปยังอุปกรณ์ได้ที่นี่

ขั้นตอนการกู้คืนและสำรองข้อมูลในระบบคลาวด์

การสำรองและกู้คืนข้อมูลในระบบคลาวด์จะต้องมีอุปกรณ์ต้นทางและอุปกรณ์เป้าหมาย

อุปกรณ์ต้นทางต้องใช้ Android 6 (API 23) ขึ้นไปเพื่อสำรองข้อมูล

ระบบรองรับอุปกรณ์ที่กำหนดเป้าหมายโดยอิงตามผู้ให้บริการ อุปกรณ์ Pixel ใช้ฟีเจอร์นี้ได้จาก Android 9 (API 29) และอุปกรณ์อื่นๆ ทั้งหมดต้องใช้ Android 12 (API 31) ขึ้นไป