สร้างบริการป้อนข้อความอัตโนมัติ

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

Android ช่วยให้คุณกรอกแบบฟอร์มได้ง่ายขึ้นด้วยเฟรมเวิร์กการป้อนข้อความอัตโนมัติที่มีให้ใช้งานใน Android 8.0 (API ระดับ 26) ขึ้นไป ผู้ใช้จะใช้ประโยชน์จากฟีเจอร์ป้อนข้อความอัตโนมัติได้ก็ต่อเมื่อมีแอปที่ให้บริการป้อนข้อความอัตโนมัติในอุปกรณ์เท่านั้น

หน้านี้แสดงวิธีใช้บริการป้อนข้อความอัตโนมัติในแอป หากคุณกำลังมองหาตัวอย่างโค้ดที่แสดงวิธีใช้บริการ โปรดดูตัวอย่าง AutofillFramework ใน Java หรือ Kotlin ดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการทำงานของบริการป้อนข้อความอัตโนมัติได้ที่หน้าข้อมูลอ้างอิงสำหรับคลาส AutofillService และ AutofillManager

การประกาศและสิทธิ์ของไฟล์ Manifest

แอปที่ให้บริการป้อนข้อความอัตโนมัติต้องมีประกาศที่อธิบายการใช้งานบริการ หากต้องการระบุประกาศ ให้ใส่องค์ประกอบ <service> ในไฟล์ Manifest ของแอป องค์ประกอบ <service> ต้องมีแอตทริบิวต์และองค์ประกอบต่อไปนี้

  • แอตทริบิวต์ android:name ที่ชี้ไปยังคลาสย่อยของ AutofillService ในแอปที่ใช้บริการ
  • android:permission แอตทริบิวต์ที่ประกาศสิทธิ์ BIND_AUTOFILL_SERVICE
  • องค์ประกอบ <intent-filter> ที่มีองค์ประกอบย่อย <action> ที่ต้องระบุการดำเนินการ android.service.autofill.AutofillService
  • องค์ประกอบ <meta-data> ไม่บังคับที่คุณสามารถใช้เพื่อระบุพารามิเตอร์การกําหนดค่าเพิ่มเติมสําหรับบริการ

ตัวอย่างต่อไปนี้แสดงการประกาศบริการป้อนข้อความอัตโนมัติ

<service
    android:name=".MyAutofillService"
    android:label="My Autofill Service"
    android:permission="android.permission.BIND_AUTOFILL_SERVICE">
    <intent-filter>
        <action android:name="android.service.autofill.AutofillService" />
    </intent-filter>
    <meta-data
        android:name="android.autofill"
        android:resource="@xml/service_configuration" />
</service>

องค์ประกอบ <meta-data> มีแอตทริบิวต์ android:resource ที่ชี้ไปยังทรัพยากร XML พร้อมรายละเอียดเพิ่มเติมเกี่ยวกับบริการ ทรัพยากร service_configuration ในตัวอย่างก่อนหน้านี้ระบุกิจกรรมที่อนุญาตให้ผู้ใช้กําหนดค่าบริการ ตัวอย่างต่อไปนี้แสดงทรัพยากร XML service_configuration

<autofill-service
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:settingsActivity="com.example.android.SettingsActivity" />

ดูข้อมูลเพิ่มเติมเกี่ยวกับทรัพยากร XML ได้ที่ภาพรวมของทรัพยากรแอป

ข้อความแจ้งให้เปิดใช้บริการ

ระบบจะใช้แอปเป็นบริการป้อนข้อความอัตโนมัติหลังจากที่แอปประกาศBIND_AUTOFILL_SERVICEสิทธิ์และผู้ใช้เปิดใช้ในการตั้งค่าอุปกรณ์ แอปจะยืนยันได้ว่าเป็นบริการที่เปิดใช้อยู่ในปัจจุบันหรือไม่โดยเรียกใช้เมธอด hasEnabledAutofillServices() ของคลาส AutofillManager

หากแอปไม่ใช่บริการป้อนข้อความอัตโนมัติปัจจุบัน แอปจะขอให้ผู้ใช้เปลี่ยนการตั้งค่าการป้อนข้อความอัตโนมัติได้โดยใช้ Intent ACTION_REQUEST_SET_AUTOFILL_SERVICE Intent จะแสดงผลค่า RESULT_OK หากผู้ใช้เลือกบริการป้อนข้อความอัตโนมัติที่ตรงกับแพ็กเกจของผู้เรียก

กรอกข้อมูลมุมมองของลูกค้า

บริการป้อนข้อความอัตโนมัติจะได้รับการร้องขอให้กรอกข้อมูลในมุมมองไคลเอ็นต์เมื่อผู้ใช้โต้ตอบกับแอปอื่นๆ หากบริการป้อนข้อความอัตโนมัติมีข้อมูลผู้ใช้ที่ตรงกับคำขอ บริการจะส่งข้อมูลในการตอบกลับ ระบบ Android จะแสดง UI การป้อนข้อความอัตโนมัติพร้อมข้อมูลที่มีอยู่ดังที่แสดงในรูปที่ 1

UI การป้อนข้อความอัตโนมัติ

รูปที่ 1 UI การป้อนข้อความอัตโนมัติที่แสดงชุดข้อมูล

เฟรมเวิร์กการป้อนข้อความอัตโนมัติจะกำหนดเวิร์กโฟลว์ในการกรอกข้อมูลในมุมมองที่ออกแบบมาเพื่อลดเวลาที่ระบบ Android ต้องเชื่อมโยงกับบริการป้อนข้อความอัตโนมัติ ในคำขอแต่ละรายการ ระบบ Android จะส่งออบเจ็กต์ AssistStructure ไปยังบริการโดยเรียกใช้เมธอด onFillRequest()

บริการป้อนข้อความอัตโนมัติจะตรวจสอบว่าสามารถตอบสนองคำขอด้วยข้อมูลผู้ใช้ที่เก็บไว้ก่อนหน้านี้ได้หรือไม่ หากสามารถตอบสนองคําขอได้ บริการจะแพ็กเกจข้อมูลในออบเจ็กต์ Dataset บริการเรียกใช้เมธอด onSuccess() โดยส่งออบเจ็กต์ FillResponse ที่มีออบเจ็กต์ Dataset หากบริการไม่มีข้อมูลที่จะตอบสนองคําขอ ระบบจะส่ง null ไปยังเมธอด onSuccess()

บริการจะเรียกใช้เมธอด onFailure() แทนหากเกิดข้อผิดพลาดขณะประมวลผลคำขอ ดูคำอธิบายเวิร์กโฟลว์โดยละเอียดได้ที่คำอธิบายในAutofillServiceหน้าข้อมูลอ้างอิง

โค้ดต่อไปนี้แสดงตัวอย่างเมธอด onFillRequest()

Kotlin

override fun onFillRequest(
    request: FillRequest,
    cancellationSignal: CancellationSignal,
    callback: FillCallback
) {
    // Get the structure from the request
    val context: List<FillContext> = request.fillContexts
    val structure: AssistStructure = context[context.size - 1].structure

    // Traverse the structure looking for nodes to fill out
    val parsedStructure: ParsedStructure = parseStructure(structure)

    // Fetch user data that matches the fields
    val (username: String, password: String) = fetchUserData(parsedStructure)

    // Build the presentation of the datasets
    val usernamePresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1)
    usernamePresentation.setTextViewText(android.R.id.text1, "my_username")
    val passwordPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1)
    passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username")

    // Add a dataset to the response
    val fillResponse: FillResponse = FillResponse.Builder()
            .addDataset(Dataset.Builder()
                    .setValue(
                            parsedStructure.usernameId,
                            AutofillValue.forText(username),
                            usernamePresentation
                    )
                    .setValue(
                            parsedStructure.passwordId,
                            AutofillValue.forText(password),
                            passwordPresentation
                    )
                    .build())
            .build()

    // If there are no errors, call onSuccess() and pass the response
    callback.onSuccess(fillResponse)
}

data class ParsedStructure(var usernameId: AutofillId, var passwordId: AutofillId)

data class UserData(var username: String, var password: String)

Java

@Override
public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) {
    // Get the structure from the request
    List<FillContext> context = request.getFillContexts();
    AssistStructure structure = context.get(context.size() - 1).getStructure();

    // Traverse the structure looking for nodes to fill out
    ParsedStructure parsedStructure = parseStructure(structure);

    // Fetch user data that matches the fields
    UserData userData = fetchUserData(parsedStructure);

    // Build the presentation of the datasets
    RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
    usernamePresentation.setTextViewText(android.R.id.text1, "my_username");
    RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
    passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username");

    // Add a dataset to the response
    FillResponse fillResponse = new FillResponse.Builder()
            .addDataset(new Dataset.Builder()
                    .setValue(parsedStructure.usernameId,
                            AutofillValue.forText(userData.username), usernamePresentation)
                    .setValue(parsedStructure.passwordId,
                            AutofillValue.forText(userData.password), passwordPresentation)
                    .build())
            .build();

    // If there are no errors, call onSuccess() and pass the response
    callback.onSuccess(fillResponse);
}

class ParsedStructure {
    AutofillId usernameId;
    AutofillId passwordId;
}

class UserData {
    String username;
    String password;
}

บริการหนึ่งอาจมีชุดข้อมูลมากกว่า 1 ชุดที่ตรงกับคำขอ ในกรณีนี้ ระบบ Android จะแสดงตัวเลือกหลายรายการ (1 รายการสำหรับชุดข้อมูลแต่ละชุด) ใน UI การป้อนข้อความอัตโนมัติ ตัวอย่างโค้ดต่อไปนี้แสดงวิธีระบุชุดข้อมูลหลายชุดในการตอบกลับ

Kotlin

// Add multiple datasets to the response
val fillResponse: FillResponse = FillResponse.Builder()
        .addDataset(Dataset.Builder()
                .setValue(parsedStructure.usernameId,
                        AutofillValue.forText(user1Data.username), username1Presentation)
                .setValue(parsedStructure.passwordId,
                        AutofillValue.forText(user1Data.password), password1Presentation)
                .build())
        .addDataset(Dataset.Builder()
                .setValue(parsedStructure.usernameId,
                        AutofillValue.forText(user2Data.username), username2Presentation)
                .setValue(parsedStructure.passwordId,
                        AutofillValue.forText(user2Data.password), password2Presentation)
                .build())
        .build()

Java

// Add multiple datasets to the response
FillResponse fillResponse = new FillResponse.Builder()
        .addDataset(new Dataset.Builder()
                .setValue(parsedStructure.usernameId,
                        AutofillValue.forText(user1Data.username), username1Presentation)
                .setValue(parsedStructure.passwordId,
                        AutofillValue.forText(user1Data.password), password1Presentation)
                .build())
        .addDataset(new Dataset.Builder()
                .setValue(parsedStructure.usernameId,
                        AutofillValue.forText(user2Data.username), username2Presentation)
                .setValue(parsedStructure.passwordId,
                        AutofillValue.forText(user2Data.password), password2Presentation)
                .build())
        .build();

บริการป้อนข้อความอัตโนมัติสามารถไปยังออบเจ็กต์ ViewNode ใน AssistStructure เพื่อดึงข้อมูลป้อนข้อความอัตโนมัติที่จําเป็นในการดำเนินการตามคําขอ บริการจะเรียกข้อมูลป้อนข้อความอัตโนมัติได้โดยใช้เมธอดของคลาส ViewNode เช่น getAutofillId()

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

หากแอปไคลเอ็นต์ไม่ได้ระบุแอตทริบิวต์ autofillHints บริการต้องใช้วิธีการหาค่าประมาณของตนเองเพื่ออธิบายเนื้อหา บริการสามารถใช้เมธอดจากคลาสอื่นๆ เช่น getText() หรือ getHint() เพื่อรับข้อมูลเกี่ยวกับเนื้อหาของมุมมอง ดูข้อมูลเพิ่มเติมได้ที่ระบุคำแนะนำสำหรับการป้อนข้อความอัตโนมัติ

ตัวอย่างต่อไปนี้แสดงวิธีไปยังส่วนต่างๆ ของ AssistStructure และดึงข้อมูลป้อนข้อความอัตโนมัติจากออบเจ็กต์ ViewNode

Kotlin

fun traverseStructure(structure: AssistStructure) {
    val windowNodes: List<AssistStructure.WindowNode> =
            structure.run {
                (0 until windowNodeCount).map { getWindowNodeAt(it) }
            }

    windowNodes.forEach { windowNode: AssistStructure.WindowNode ->
        val viewNode: ViewNode? = windowNode.rootViewNode
        traverseNode(viewNode)
    }
}

fun traverseNode(viewNode: ViewNode?) {
    if (viewNode?.autofillHints?.isNotEmpty() == true) {
        // If the client app provides autofill hints, you can obtain them using
        // viewNode.getAutofillHints();
    } else {
        // Or use your own heuristics to describe the contents of a view
        // using methods such as getText() or getHint()
    }

    val children: List<ViewNode>? =
            viewNode?.run {
                (0 until childCount).map { getChildAt(it) }
            }

    children?.forEach { childNode: ViewNode ->
        traverseNode(childNode)
    }
}

Java

public void traverseStructure(AssistStructure structure) {
    int nodes = structure.getWindowNodeCount();

    for (int i = 0; i < nodes; i++) {
        WindowNode windowNode = structure.getWindowNodeAt(i);
        ViewNode viewNode = windowNode.getRootViewNode();
        traverseNode(viewNode);
    }
}

public void traverseNode(ViewNode viewNode) {
    if(viewNode.getAutofillHints() != null && viewNode.getAutofillHints().length > 0) {
        // If the client app provides autofill hints, you can obtain them using
        // viewNode.getAutofillHints();
    } else {
        // Or use your own heuristics to describe the contents of a view
        // using methods such as getText() or getHint()
    }

    for(int i = 0; i < viewNode.getChildCount(); i++) {
        ViewNode childNode = viewNode.getChildAt(i);
        traverseNode(childNode);
    }
}

บันทึกข้อมูลผู้ใช้

บริการป้อนข้อความอัตโนมัติต้องใช้ข้อมูลผู้ใช้เพื่อกรอกข้อมูลในมุมมองในแอป เมื่อผู้ใช้กรอกข้อมูลในมุมมองด้วยตนเอง ระบบจะแจ้งให้บันทึกข้อมูลไปยังบริการป้อนข้อความอัตโนมัติปัจจุบัน ดังที่แสดงในรูปที่ 2

UI บันทึกการป้อนข้อความอัตโนมัติ

รูปที่ 2 UI บันทึกการป้อนข้อความอัตโนมัติ

หากต้องการบันทึกข้อมูล บริการต้องระบุว่าสนใจจัดเก็บข้อมูลไว้ใช้ในอนาคต ก่อนที่ระบบ Android จะส่งคำขอบันทึกข้อมูล จะมีคำขอป้อนข้อมูลซึ่งบริการมีโอกาสป้อนข้อมูลมุมมอง หากต้องการระบุว่าสนใจที่จะบันทึกข้อมูล บริการจะใส่ออบเจ็กต์ SaveInfo ในคำตอบสำหรับคำขอป้อนข้อมูล ออบเจ็กต์ SaveInfo ต้องมีข้อมูลต่อไปนี้เป็นอย่างน้อย

  • ประเภทข้อมูลผู้ใช้ที่บันทึกไว้ ดูรายการค่า SAVE_DATA ที่พร้อมใช้งานได้ที่ SaveInfo
  • ชุดมุมมองขั้นต่ำที่ต้องเปลี่ยนแปลงเพื่อทริกเกอร์คําขอบันทึก เช่น แบบฟอร์มการเข้าสู่ระบบมักจะกำหนดให้ผู้ใช้อัปเดตมุมมอง username และ password เพื่อเรียกให้แสดงคำขอบันทึก

ออบเจ็กต์ SaveInfo จะเชื่อมโยงกับออบเจ็กต์ FillResponse ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้

Kotlin

override fun onFillRequest(
    request: FillRequest,
    cancellationSignal: CancellationSignal,
    callback: FillCallback
) {
    ...
    // Builder object requires a non-null presentation
    val notUsed = RemoteViews(packageName, android.R.layout.simple_list_item_1)

    val fillResponse: FillResponse = FillResponse.Builder()
            .addDataset(
                    Dataset.Builder()
                            .setValue(parsedStructure.usernameId, null, notUsed)
                            .setValue(parsedStructure.passwordId, null, notUsed)
                            .build()
            )
            .setSaveInfo(
                    SaveInfo.Builder(
                            SaveInfo.SAVE_DATA_TYPE_USERNAME or SaveInfo.SAVE_DATA_TYPE_PASSWORD,
                            arrayOf(parsedStructure.usernameId, parsedStructure.passwordId)
                    ).build()
            )
            .build()
    ...
}

Java

@Override
public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) {
    ...
    // Builder object requires a non-null presentation
    RemoteViews notUsed = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);

    FillResponse fillResponse = new FillResponse.Builder()
            .addDataset(new Dataset.Builder()
                    .setValue(parsedStructure.usernameId, null, notUsed)
                    .setValue(parsedStructure.passwordId, null, notUsed)
                    .build())
            .setSaveInfo(new SaveInfo.Builder(
                    SaveInfo.SAVE_DATA_TYPE_USERNAME | SaveInfo.SAVE_DATA_TYPE_PASSWORD,
                    new AutofillId[] {parsedStructure.usernameId, parsedStructure.passwordId})
                    .build())
            .build();
    ...
}

บริการป้อนข้อความอัตโนมัติสามารถใช้ตรรกะเพื่อเก็บข้อมูลผู้ใช้ไว้ในเมธอด onSaveRequest() ซึ่งมักจะเรียกใช้หลังจากกิจกรรมของไคลเอ็นต์เสร็จสิ้นหรือเมื่อแอปไคลเอ็นต์เรียก commit() โค้ดต่อไปนี้แสดงตัวอย่างเมธอด onSaveRequest()

Kotlin

override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
    // Get the structure from the request
    val context: List<FillContext> = request.fillContexts
    val structure: AssistStructure = context[context.size - 1].structure

    // Traverse the structure looking for data to save
    traverseStructure(structure)

    // Persist the data - if there are no errors, call onSuccess()
    callback.onSuccess()
}

Java

@Override
public void onSaveRequest(SaveRequest request, SaveCallback callback) {
    // Get the structure from the request
    List<FillContext> context = request.getFillContexts();
    AssistStructure structure = context.get(context.size() - 1).getStructure();

    // Traverse the structure looking for data to save
    traverseStructure(structure);

    // Persist the data - if there are no errors, call onSuccess()
    callback.onSuccess();
}

บริการป้อนข้อความอัตโนมัติต้องเข้ารหัสข้อมูลที่ละเอียดอ่อนก่อนที่จะเก็บไว้ อย่างไรก็ตาม ข้อมูลผู้ใช้อาจรวมถึงป้ายกำกับหรือข้อมูลที่ไม่ใช่ข้อมูลที่ละเอียดอ่อน เช่น บัญชีผู้ใช้อาจมีป้ายกำกับที่ทําเครื่องหมายข้อมูลว่าเป็นบัญชีงานหรือส่วนตัว บริการต้องไม่เข้ารหัสป้ายกำกับ การไม่เข้ารหัสป้ายกำกับจะทำให้บริการต่างๆ ใช้ป้ายกำกับในมุมมองการนำเสนอได้หากผู้ใช้ไม่ได้ตรวจสอบสิทธิ์ จากนั้นบริการจะแทนที่ป้ายกำกับด้วยข้อมูลจริงได้หลังจากที่ผู้ใช้ตรวจสอบสิทธิ์แล้ว

เลื่อน UI การบันทึกการป้อนข้อความอัตโนมัติ

ตั้งแต่ Android 10 เป็นต้นไป หากคุณใช้หน้าจอหลายหน้าจอเพื่อใช้เวิร์กโฟลว์การป้อนข้อความอัตโนมัติ เช่น หน้าจอหนึ่งสำหรับช่องชื่อผู้ใช้และอีกหน้าจอสำหรับรหัสผ่าน คุณสามารถเลื่อนเวลาการบันทึก UI การป้อนข้อความอัตโนมัติได้โดยใช้ Flag SaveInfo.FLAG_DELAY_SAVE

หากตั้งค่า Flag นี้ ระบบจะไม่ทริกเกอร์ UI บันทึกการป้อนข้อความอัตโนมัติเมื่อมีการบันทึกบริบทการป้อนข้อความอัตโนมัติที่เชื่อมโยงกับการตอบกลับ SaveInfo แต่คุณสามารถใช้กิจกรรมแยกต่างหากภายในงานเดียวกันเพื่อส่งคําขอการบรรจุในอนาคต แล้วแสดง UI ผ่านคําขอบันทึก ดูข้อมูลเพิ่มเติมได้ที่ SaveInfo.FLAG_DELAY_SAVE

ต้องมีการตรวจสอบสิทธิ์ผู้ใช้

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

  • ข้อมูลผู้ใช้ในแอปต้องปลดล็อกโดยใช้รหัสผ่านหลักหรือการสแกนลายนิ้วมือ
  • คุณต้องปลดล็อกชุดข้อมูลที่ต้องการ เช่น รายละเอียดบัตรเครดิต โดยใช้รหัสยืนยันบัตร (CVC)

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

ตัวอย่างโค้ดต่อไปนี้แสดงวิธีระบุว่าคําขอต้องได้รับการตรวจสอบสิทธิ์

Kotlin

val authPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply {
    setTextViewText(android.R.id.text1, "requires authentication")
}
val authIntent = Intent(this, AuthActivity::class.java).apply {
    // Send any additional data required to complete the request
    putExtra(MY_EXTRA_DATASET_NAME, "my_dataset")
}

val intentSender: IntentSender = PendingIntent.getActivity(
        this,
        1001,
        authIntent,
        PendingIntent.FLAG_CANCEL_CURRENT
).intentSender

// Build a FillResponse object that requires authentication
val fillResponse: FillResponse = FillResponse.Builder()
        .setAuthentication(autofillIds, intentSender, authPresentation)
        .build()

Java

RemoteViews authPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
authPresentation.setTextViewText(android.R.id.text1, "requires authentication");
Intent authIntent = new Intent(this, AuthActivity.class);

// Send any additional data required to complete the request
authIntent.putExtra(MY_EXTRA_DATASET_NAME, "my_dataset");
IntentSender intentSender = PendingIntent.getActivity(
                this,
                1001,
                authIntent,
                PendingIntent.FLAG_CANCEL_CURRENT
        ).getIntentSender();

// Build a FillResponse object that requires authentication
FillResponse fillResponse = new FillResponse.Builder()
        .setAuthentication(autofillIds, intentSender, authPresentation)
        .build();

เมื่อกิจกรรมทำตามขั้นตอนการตรวจสอบสิทธิ์เสร็จแล้ว กิจกรรมจะต้องเรียกใช้เมธอด setResult() โดยส่งค่า RESULT_OK และตั้งค่า EXTRA_AUTHENTICATION_RESULT เพิ่มเติมให้กับออบเจ็กต์ FillResponse ที่มีชุดข้อมูลที่สร้างขึ้น โค้ดต่อไปนี้แสดงตัวอย่างวิธีแสดงผลลัพธ์เมื่อขั้นตอนการตรวจสอบสิทธิ์เสร็จสมบูรณ์

Kotlin

// The data sent by the service and the structure are included in the intent
val datasetName: String? = intent.getStringExtra(MY_EXTRA_DATASET_NAME)
val structure: AssistStructure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE)
val parsedStructure: ParsedStructure = parseStructure(structure)
val (username, password) = fetchUserData(parsedStructure)

// Build the presentation of the datasets
val usernamePresentation =
        RemoteViews(packageName, android.R.layout.simple_list_item_1).apply {
            setTextViewText(android.R.id.text1, "my_username")
        }
val passwordPresentation =
        RemoteViews(packageName, android.R.layout.simple_list_item_1).apply {
            setTextViewText(android.R.id.text1, "Password for my_username")
        }

// Add the dataset to the response
val fillResponse: FillResponse = FillResponse.Builder()
        .addDataset(Dataset.Builder()
                .setValue(
                        parsedStructure.usernameId,
                        AutofillValue.forText(username),
                        usernamePresentation
                )
                .setValue(
                        parsedStructure.passwordId,
                        AutofillValue.forText(password),
                        passwordPresentation
                )
                .build()
        ).build()

val replyIntent = Intent().apply {
    // Send the data back to the service
    putExtra(MY_EXTRA_DATASET_NAME, datasetName)
    putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse)
}

setResult(Activity.RESULT_OK, replyIntent)

Java

Intent intent = getIntent();

// The data sent by the service and the structure are included in the intent
String datasetName = intent.getStringExtra(MY_EXTRA_DATASET_NAME);
AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
ParsedStructure parsedStructure = parseStructure(structure);
UserData userData = fetchUserData(parsedStructure);

// Build the presentation of the datasets
RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
usernamePresentation.setTextViewText(android.R.id.text1, "my_username");
RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username");

// Add the dataset to the response
FillResponse fillResponse = new FillResponse.Builder()
        .addDataset(new Dataset.Builder()
                .setValue(parsedStructure.usernameId,
                        AutofillValue.forText(userData.username), usernamePresentation)
                .setValue(parsedStructure.passwordId,
                        AutofillValue.forText(userData.password), passwordPresentation)
                .build())
        .build();

Intent replyIntent = new Intent();

// Send the data back to the service
replyIntent.putExtra(MY_EXTRA_DATASET_NAME, datasetName);
replyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse);

setResult(RESULT_OK, replyIntent);

ในกรณีที่ต้องปลดล็อกชุดข้อมูลบัตรเครดิต บริการจะแสดง UI ที่ขอ CVC คุณสามารถซ่อนข้อมูลไว้จนกว่าจะปลดล็อกชุดข้อมูลได้โดยแสดงข้อมูลสำเร็จรูป เช่น ชื่อธนาคารและตัวเลข 4 หลักสุดท้ายของหมายเลขบัตรเครดิต ตัวอย่างต่อไปนี้แสดงวิธีกำหนดให้ต้องตรวจสอบสิทธิ์สำหรับชุดข้อมูลและซ่อนข้อมูลจนกว่าผู้ใช้จะระบุ CVC

Kotlin

// Parse the structure and fetch payment data
val parsedStructure: ParsedStructure = parseStructure(structure)
val paymentData: Payment = fetchPaymentData(parsedStructure)

// Build the presentation that shows the bank and the last four digits of the
// credit card number, such as 'Bank-1234'
val maskedPresentation: String = "${paymentData.bank}-" +
        paymentData.creditCardNumber.substring(paymentData.creditCardNumber.length - 4)
val authPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply {
    setTextViewText(android.R.id.text1, maskedPresentation)
}

// Prepare an intent that displays the UI that asks for the CVC
val cvcIntent = Intent(this, CvcActivity::class.java)
val cvcIntentSender: IntentSender = PendingIntent.getActivity(
        this,
        1001,
        cvcIntent,
        PendingIntent.FLAG_CANCEL_CURRENT
).intentSender

// Build a FillResponse object that includes a Dataset that requires authentication
val fillResponse: FillResponse = FillResponse.Builder()
        .addDataset(
                Dataset.Builder()
                        // The values in the dataset are replaced by the actual
                        // data once the user provides the CVC
                        .setValue(parsedStructure.creditCardId, null, authPresentation)
                        .setValue(parsedStructure.expDateId, null, authPresentation)
                        .setAuthentication(cvcIntentSender)
                        .build()
        ).build()

Java

// Parse the structure and fetch payment data
ParsedStructure parsedStructure = parseStructure(structure);
Payment paymentData = fetchPaymentData(parsedStructure);

// Build the presentation that shows the bank and the last four digits of the
// credit card number, such as 'Bank-1234'
String maskedPresentation = paymentData.bank + "-" +
    paymentData.creditCardNumber.subString(paymentData.creditCardNumber.length - 4);
RemoteViews authPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
authPresentation.setTextViewText(android.R.id.text1, maskedPresentation);

// Prepare an intent that displays the UI that asks for the CVC
Intent cvcIntent = new Intent(this, CvcActivity.class);
IntentSender cvcIntentSender = PendingIntent.getActivity(
        this,
        1001,
        cvcIntent,
        PendingIntent.FLAG_CANCEL_CURRENT
).getIntentSender();

// Build a FillResponse object that includes a Dataset that requires authentication
FillResponse fillResponse = new FillResponse.Builder()
        .addDataset(new Dataset.Builder()
                // The values in the dataset are replaced by the actual
                // data once the user provides the CVC
                .setValue(parsedStructure.creditCardId, null, authPresentation)
                .setValue(parsedStructure.expDateId, null, authPresentation)
                .setAuthentication(cvcIntentSender)
                .build())
        .build();

เมื่อกิจกรรมตรวจสอบ CVC แล้ว ก็ควรเรียกใช้เมธอด setResult() โดยส่งค่า RESULT_OK และตั้งค่า EXTRA_AUTHENTICATION_RESULT extra เป็นออบเจ็กต์ Dataset ที่มีหมายเลขบัตรเครดิตและวันที่หมดอายุ ชุดข้อมูลใหม่จะแทนที่ชุดข้อมูลที่ต้องตรวจสอบสิทธิ์ และระบบจะป้อนข้อมูลพร็อพเพอร์ตี้ทันที โค้ดต่อไปนี้แสดงตัวอย่างวิธีแสดงผลชุดข้อมูลเมื่อผู้ใช้ระบุ CVC

Kotlin

// Parse the structure and fetch payment data.
val parsedStructure: ParsedStructure = parseStructure(structure)
val paymentData: Payment = fetchPaymentData(parsedStructure)

// Build a non-null RemoteViews object to use as the presentation when
// creating the Dataset object. This presentation isn't actually used, but the
// Builder object requires a non-null presentation.
val notUsed = RemoteViews(packageName, android.R.layout.simple_list_item_1)

// Create a dataset with the credit card number and expiration date.
val responseDataset: Dataset = Dataset.Builder()
        .setValue(
                parsedStructure.creditCardId,
                AutofillValue.forText(paymentData.creditCardNumber),
                notUsed
        )
        .setValue(
                parsedStructure.expDateId,
                AutofillValue.forText(paymentData.expirationDate),
                notUsed
        )
        .build()

val replyIntent = Intent().apply {
    putExtra(EXTRA_AUTHENTICATION_RESULT, responseDataset)
}

Java

// Parse the structure and fetch payment data.
ParsedStructure parsedStructure = parseStructure(structure);
Payment paymentData = fetchPaymentData(parsedStructure);

// Build a non-null RemoteViews object to use as the presentation when
// creating the Dataset object. This presentation isn't actually used, but the
// Builder object requires a non-null presentation.
RemoteViews notUsed = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);

// Create a dataset with the credit card number and expiration date.
Dataset responseDataset = new Dataset.Builder()
        .setValue(parsedStructure.creditCardId,
                AutofillValue.forText(paymentData.creditCardNumber), notUsed)
        .setValue(parsedStructure.expDateId,
                AutofillValue.forText(paymentData.expirationDate), notUsed)
        .build();

Intent replyIntent = new Intent();
replyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, responseDataset);

จัดระเบียบข้อมูลเป็นกลุ่มที่สมเหตุสมผล

บริการป้อนข้อความอัตโนมัติต้องจัดระเบียบข้อมูลเป็นกลุ่มตามตรรกะซึ่งแยกแนวคิดออกจากโดเมนต่างๆ ในหน้านี้ กลุ่มเชิงตรรกะเหล่านี้เรียกว่าพาร์ติชัน รายการต่อไปนี้แสดงตัวอย่างทั่วไปของพาร์ติชันและช่อง

  • ข้อมูลเข้าสู่ระบบ ซึ่งรวมถึงช่องชื่อผู้ใช้และรหัสผ่าน
  • ที่อยู่ ซึ่งประกอบด้วยช่องถนน เมือง รัฐ และรหัสไปรษณีย์
  • ข้อมูลการชำระเงิน ซึ่งรวมถึงช่องหมายเลขบัตรเครดิต วันที่หมดอายุ และรหัสยืนยัน

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

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

พาร์ติชัน ฟิลด์ 1 ฟิลด์ 2
ข้อมูลรับรอง work_username work_password
personal_username personal_password
ที่อยู่ work_street work_city
personal_street personal_city

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

บริการจะระบุช่องที่เป็นต้นทางของคําขอได้โดยเรียกใช้เมธอด isFocused()ขณะที่ไปยังออบเจ็กต์ AssistStructure ซึ่งช่วยให้บริการเตรียม FillResponse ที่มีข้อมูลพาร์ติชันที่เหมาะสมได้

ป้อนรหัส SMS แบบใช้ครั้งเดียวโดยอัตโนมัติ

บริการป้อนข้อความอัตโนมัติสามารถช่วยผู้ใช้ในการกรอกรหัสแบบครั้งเดียวที่ส่งทาง SMS โดยใช้ SMS Retriever API

คุณต้องมีคุณสมบัติตรงตามข้อกำหนดต่อไปนี้จึงจะใช้ฟีเจอร์นี้ได้

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

บริการป้อนข้อความอัตโนมัติสามารถใช้ SmsCodeAutofillClient ซึ่งพร้อมใช้งานโดยเรียกใช้ SmsCodeRetriever.getAutofillClient() จากบริการ Google Play 19.0.56 ขึ้นไป

ขั้นตอนหลักในการใช้ API นี้ในบริการป้อนข้อความอัตโนมัติมีดังนี้

  1. ในบริการป้อนข้อความอัตโนมัติ ให้ใช้ hasOngoingSmsRequest จาก SmsCodeAutofillClient เพื่อดูว่ามีคำขอที่ใช้งานอยู่สำหรับชื่อแพ็กเกจของแอปพลิเคชันที่คุณกรอกข้อความอัตโนมัติอยู่หรือไม่ บริการป้อนข้อความอัตโนมัติของคุณต้องแสดงข้อความแจ้งคำแนะนำก็ต่อเมื่อค่านี้แสดงผลเป็น false
  2. ในบริการป้อนข้อความอัตโนมัติ ให้ใช้ checkPermissionState จาก SmsCodeAutofillClient เพื่อตรวจสอบว่าบริการป้อนข้อความอัตโนมัติมีสิทธิ์ป้อนรหัสแบบครั้งเดียวโดยอัตโนมัติหรือไม่ สถานะสิทธิ์นี้อาจเป็น NONE, GRANTED หรือ DENIED บริการป้อนข้อความอัตโนมัติต้องแสดงข้อความแจ้งคำแนะนำสำหรับรัฐ NONE และ GRANTED
  3. ในกิจกรรมการตรวจสอบสิทธิ์แบบป้อนข้อความอัตโนมัติ ให้ใช้สิทธิ์ SmsRetriever.SEND_PERMISSION เพื่อลงทะเบียน BroadcastReceiver ที่รอรับ SmsCodeRetriever.SMS_CODE_RETRIEVED_ACTION เพื่อรับผลลัพธ์รหัส SMS เมื่อพร้อมใช้งาน
  4. โทรหา startSmsCodeRetriever ใน SmsCodeAutofillClient เพื่อเริ่มฟังรหัสแบบใช้ครั้งเดียวที่ส่งทาง SMS หากผู้ใช้ให้สิทธิ์บริการป้อนข้อความอัตโนมัติของคุณในการดึงรหัสแบบครั้งเดียวจาก SMS ระบบจะค้นหาข้อความ SMS ที่ได้รับในช่วง 1-5 นาทีที่ผ่านมา

    หากบริการป้อนข้อความอัตโนมัติต้องขอสิทธิ์จากผู้ใช้เพื่ออ่านรหัสแบบครั้งเดียว Task ที่ startSmsCodeRetriever แสดงอาจไม่สำเร็จและแสดง ResolvableApiException ในกรณีนี้ คุณต้องเรียกใช้เมธอด ResolvableApiException.startResolutionForResult() เพื่อแสดงกล่องโต้ตอบความยินยอมสําหรับคําขอสิทธิ์

  5. รับผลลัพธ์รหัส SMS จาก Intent แล้วแสดงรหัส SMS เป็นการตอบกลับแบบป้อนข้อความอัตโนมัติ

สถานการณ์การป้อนข้อความอัตโนมัติขั้นสูง

ผสานรวมกับแป้นพิมพ์
ตั้งแต่ Android 11 เป็นต้นไป แพลตฟอร์มจะอนุญาตให้แป้นพิมพ์และเครื่องมือแก้ไขวิธีป้อนข้อมูลอื่นๆ (IME) แสดงคำแนะนำการป้อนข้อความอัตโนมัติในบรรทัดแทนการใช้เมนูแบบเลื่อนลง ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่บริการป้อนข้อความอัตโนมัติรองรับฟังก์ชันการทำงานนี้ได้ที่หัวข้อผสานรวมการป้อนข้อความอัตโนมัติกับแป้นพิมพ์
จัดชุดข้อมูลเป็นหน้า
คำตอบการเติมข้อความอัตโนมัติขนาดใหญ่อาจเกินขนาดธุรกรรมที่อนุญาตของออบเจ็กต์ Binder ที่แสดงถึงออบเจ็กต์ระยะไกลที่จําเป็นสําหรับประมวลผลคําขอ หากต้องการป้องกันไม่ให้ระบบ Android แสดงข้อยกเว้นในสถานการณ์เหล่านี้ คุณสามารถทำให้ FillResponse มีขนาดไม่ใหญ่โดยการเพิ่มออบเจ็กต์ Dataset ไม่เกิน 20 รายการในแต่ละครั้ง หากคำตอบต้องใช้ชุดข้อมูลเพิ่ม คุณสามารถเพิ่มชุดข้อมูลที่จะแจ้งให้ผู้ใช้ทราบว่ามีข้อมูลเพิ่มเติมและดึงชุดข้อมูลกลุ่มถัดไปเมื่อเลือก ดูข้อมูลเพิ่มเติมได้ที่ addDataset(Dataset)
บันทึกข้อมูลที่แยกออกเป็นหลายหน้าจอ

แอปมักแยกข้อมูลผู้ใช้ในหลายหน้าจอในกิจกรรมเดียวกัน โดยเฉพาะในกิจกรรมที่ใช้สร้างบัญชีผู้ใช้ใหม่ เช่น หน้าจอแรกจะขอชื่อผู้ใช้ และหากชื่อผู้ใช้นั้นใช้ได้ หน้าจอที่ 2 จะขอรหัสผ่าน ในกรณีเหล่านี้ บริการป้อนข้อความอัตโนมัติต้องรอจนกว่าผู้ใช้จะป้อนข้อมูลในทั้ง 2 ช่องก่อนจึงจะแสดง UI บันทึกข้อความอัตโนมัติได้ ทําตามขั้นตอนต่อไปนี้เพื่อจัดการสถานการณ์ดังกล่าว

  1. ในคำขอกรอกข้อมูลแรก ให้เพิ่มกลุ่มสถานะไคลเอ็นต์ในการตอบกลับซึ่งมีรหัสป้อนข้อความอัตโนมัติของฟิลด์บางส่วนที่แสดงในหน้าจอ
  2. ในคำขอป้อนข้อมูลครั้งที่ 2 ให้ดึงข้อมูลกลุ่มสถานะไคลเอ็นต์ รับรหัสป้อนอัตโนมัติที่ตั้งค่าไว้ในคำขอก่อนหน้าจากสถานะไคลเอ็นต์ และเพิ่มรหัสเหล่านี้และธง FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE ลงในออบเจ็กต์ SaveInfo ที่ใช้ในการตอบกลับครั้งที่ 2
  3. ในคําขอบันทึก ให้ใช้ออบเจ็กต์ FillContext ที่เหมาะสมเพื่อรับค่าของแต่ละช่อง บริบทการโฆษณาจะอยู่ที่ 1 รายการต่อคำขอโฆษณา

ดูข้อมูลเพิ่มเติมได้ที่บันทึกเมื่อข้อมูลมีการแยกออกเป็นหลายหน้าจอ

ระบุตรรกะการเริ่มต้นและการสร้างใหม่สำหรับคำขอแต่ละรายการ

ทุกครั้งที่มีคำขอป้อนข้อความอัตโนมัติ ระบบ Android จะเชื่อมโยงกับบริการและเรียกใช้เมธอด onConnected() เมื่อบริการประมวลผลคําขอแล้ว ระบบ Android จะเรียกใช้เมธอด onDisconnected() และยกเลิกการเชื่อมโยงกับบริการ คุณสามารถใช้ onConnected() เพื่อระบุโค้ดที่จะทำงานก่อนประมวลผลคำขอ และ onDisconnected() เพื่อระบุโค้ดที่จะทำงานหลังจากประมวลผลคำขอ

ปรับแต่ง UI การบันทึกการป้อนข้อความอัตโนมัติ

บริการป้อนข้อความอัตโนมัติสามารถปรับแต่ง UI ของการเก็บข้อมูลป้อนข้อความอัตโนมัติเพื่อช่วยผู้ใช้ตัดสินใจว่าต้องการอนุญาตให้บริการบันทึกข้อมูลหรือไม่ บริการสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่บันทึกไว้ผ่านข้อความธรรมดาหรือผ่านมุมมองที่กำหนดเอง บริการยังเปลี่ยนลักษณะที่ปรากฏของปุ่มที่ยกเลิกคำขอบันทึกและรับการแจ้งเตือนเมื่อผู้ใช้แตะปุ่มดังกล่าวได้ด้วย ดูข้อมูลเพิ่มเติมได้ที่หน้าอ้างอิง SaveInfo

โหมดความเข้ากันได้

โหมดความเข้ากันได้ช่วยให้บริการป้อนข้อความอัตโนมัติใช้โครงสร้างเสมือนจริงสำหรับการช่วยเหลือพิเศษเพื่อวัตถุประสงค์ในการป้อนข้อความอัตโนมัติได้ ซึ่งมีประโยชน์อย่างยิ่งในการระบุฟังก์ชันการป้อนข้อความอัตโนมัติในเบราว์เซอร์ที่ไม่ได้ใช้ API การป้อนข้อความอัตโนมัติอย่างชัดเจน

หากต้องการทดสอบบริการป้อนข้อความอัตโนมัติโดยใช้โหมดความเข้ากันได้ ให้เพิ่มเบราว์เซอร์หรือแอปที่ต้องใช้โหมดความเข้ากันได้ลงในรายการที่อนุญาตอย่างชัดเจน คุณสามารถตรวจสอบว่าแพ็กเกจใดอยู่ในรายการที่อนุญาตแล้วโดยเรียกใช้คําสั่งต่อไปนี้

$ adb shell settings get global autofill_compat_mode_allowed_packages

หากแพ็กเกจที่คุณทดสอบไม่อยู่ในรายการ ให้เพิ่มโดยเรียกใช้คำสั่งต่อไปนี้ โดยที่ pkgX คือแพ็กเกจของแอป

$ adb shell settings put global autofill_compat_mode_allowed_packages pkg1[resId1]:pkg2[resId1,resId2]

หากแอปเป็นเบราว์เซอร์ ให้ใช้ resIdx เพื่อระบุรหัสทรัพยากรของช่องป้อนข้อมูลที่มี URL ของหน้าที่แสดงผล

โหมดความเข้ากันได้มีข้อจํากัดต่อไปนี้

  • คำขอบันทึกจะทริกเกอร์เมื่อบริการใช้ Flag FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE หรือเรียกใช้เมธอด setTrigger() FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE จะถูกตั้งค่าไว้โดยค่าเริ่มต้นเมื่อใช้โหมดความเข้ากันได้
  • ค่าข้อความของโหนดอาจไม่พร้อมใช้งานในวิธี onSaveRequest(SaveRequest, SaveCallback)

ดูข้อมูลเพิ่มเติมเกี่ยวกับโหมดความเข้ากันได้ รวมถึงข้อจำกัดที่เกี่ยวข้องได้ที่ข้อมูลอ้างอิงคลาส AutofillService