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

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

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

หากแอปไม่ใช่บริการป้อนข้อความอัตโนมัติปัจจุบัน แอปจะขอให้ผู้ใช้ เปลี่ยนการตั้งค่าการป้อนข้อความอัตโนมัติได้โดยใช้ ACTION_REQUEST_SET_AUTOFILL_SERVICE Intent 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 จะแสดงตัวเลือกหลายรายการ ซึ่งมีตัวเลือกหนึ่งสำหรับชุดข้อมูลแต่ละชุดใน 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 การบันทึกการป้อนข้อความอัตโนมัติได้โดยใช้ SaveInfo.FLAG_DELAY_SAVE แฟล็ก

หากตั้งค่าสถานะนี้ ระบบจะไม่ทริกเกอร์ 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 เพิ่มเติมเป็น ออบเจ็กต์ 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 เพื่อรอรับผลลัพธ์รหัส SMS เมื่อพร้อมใช้งานSmsCodeRetriever.SMS_CODE_RETRIEVED_ACTION
  4. โทรหา startSmsCodeRetriever ใน SmsCodeAutofillClient เพื่อเริ่มฟังรหัสแบบใช้ครั้งเดียวที่ส่งผ่าน SMS หากผู้ใช้ให้สิทธิ์แก่บริการป้อนข้อความอัตโนมัติเพื่อดึงรหัสแบบครั้งเดียวจาก SMS ระบบจะค้นหาข้อความ SMS ที่ได้รับในช่วง 1-5 นาทีที่ผ่านมา

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

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

เปิดใช้การป้อนข้อความอัตโนมัติใน Chrome

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

เปิดใช้การป้อนข้อความอัตโนมัติใน Chrome

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

นักพัฒนาแอปสามารถทำสิ่งต่อไปนี้เพื่อช่วยให้ผู้ใช้เปิดปุ่มสลับได้

  • ค้นหาการตั้งค่า Chrome และดูว่าผู้ใช้ต้องการใช้บริการป้อนข้อความอัตโนมัติของบุคคลที่สามหรือไม่
  • Deep Link ไปยังหน้าการตั้งค่า Chrome ที่ผู้ใช้สามารถเปิดใช้บริการป้อนข้อความอัตโนมัติของบุคคลที่สามได้

อ่านการตั้งค่า Chrome

แอปใดก็ได้อ่านได้ว่า Chrome ใช้โหมดป้อนข้อความอัตโนมัติของบุคคลที่สามที่อนุญาตให้ใช้ การป้อนข้อความอัตโนมัติของ Android หรือไม่ Chrome ใช้ ContentProvider ของ Android เพื่อสื่อสารข้อมูลดังกล่าว ประกาศในไฟล์ Manifest ของ Android ว่าคุณต้องการอ่านการตั้งค่าจากช่องใด

<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
<queries>
 <!-- To Query Chrome Beta: -->
 <package android:name="com.chrome.beta" />

 <!-- To Query Chrome Stable: -->
 <package android:name="com.android.chrome" />
</queries>

จากนั้นใช้ ContentResolver ของ Android เพื่อขอข้อมูลดังกล่าวโดยสร้าง URI เนื้อหา ดังนี้

Kotlin

val CHROME_CHANNEL_PACKAGE = "com.android.chrome" // Chrome Stable.
val CONTENT_PROVIDER_NAME = ".AutofillThirdPartyModeContentProvider"
val THIRD_PARTY_MODE_COLUMN = "autofill_third_party_state"
val THIRD_PARTY_MODE_ACTIONS_URI_PATH = "autofill_third_party_mode"

val uri = Uri.Builder()
    .scheme(ContentResolver.SCHEME_CONTENT)
    .authority(CHROME_CHANNEL_PACKAGE + CONTENT_PROVIDER_NAME)
    .path(THIRD_PARTY_MODE_ACTIONS_URI_PATH)
    .build()

val cursor = contentResolver.query(
    uri,
    arrayOf(THIRD_PARTY_MODE_COLUMN), // projection
    null, // selection
    null, // selectionArgs
    null  // sortOrder
)

if (cursor == null) {
  // Terminate now! Older versions of Chromium don't provide this information.
}

cursor?.use { // Use the safe call operator and the use function for auto-closing
    if (it.moveToFirst()) { // Check if the cursor has any rows
        val index = it.getColumnIndex(THIRD_PARTY_MODE_COLUMN)
        if (index != -1) { // Check if the column exists
          val value = it.getInt(index)
          if (0 == value) {
              // 0 means that the third party mode is turned off. Chrome uses its built-in
              // password manager. This is the default for new users.
          } else {
              // 1 means that the third party mode is turned on. Chrome uses forwards all
              // autofill requests to Android Autofill. Users have to opt-in for this.
          }
        } else {
          // Handle the case where the column doesn't exist.  Log a warning, perhaps.
          Log.w("Autofill", "Column $THIRD_PARTY_MODE_COLUMN not found in cursor")
        }
    }
} // The cursor is automatically closed here

Java

final String CHROME_CHANNEL_PACKAGE = "com.android.chrome";  // Chrome Stable.
final String CONTENT_PROVIDER_NAME = ".AutofillThirdPartyModeContentProvider";
final String THIRD_PARTY_MODE_COLUMN = "autofill_third_party_state";
final String THIRD_PARTY_MODE_ACTIONS_URI_PATH = "autofill_third_party_mode";

final Uri uri = new Uri.Builder()
                  .scheme(ContentResolver.SCHEME_CONTENT)
                  .authority(CHROME_CHANNEL_PACKAGE + CONTENT_PROVIDER_NAME)
                  .path(THIRD_PARTY_MODE_ACTIONS_URI_PATH)
                  .build();

final Cursor cursor = getContentResolver().query(
                  uri,
                  /*projection=*/new String[] {THIRD_PARTY_MODE_COLUMN},
                  /*selection=*/ null,
                  /*selectionArgs=*/ null,
                  /*sortOrder=*/ null);

if (cursor == null) {
  // Terminate now! Older versions of Chromium don't provide this information.
}

cursor.moveToFirst(); // Retrieve the result;

int index = cursor.getColumnIndex(THIRD_PARTY_MODE_COLUMN);

if (0 == cursor.getInt(index)) {
  // 0 means that the third party mode is turned off. Chrome uses its built-in
  // password manager. This is the default for new users.
} else {
  // 1 means that the third party mode is turned on. Chrome uses forwards all
  // autofill requests to Android Autofill. Users have to opt-in for this.
}

หากต้องการ Deep Link ไปยังหน้าการตั้งค่า Chrome ที่ผู้ใช้สามารถเปิดใช้บริการป้อนข้อความอัตโนมัติของบุคคลที่สามได้ ให้ใช้ Intent ของ Android อย่าลืมกำหนดค่าการดำเนินการและหมวดหมู่ตามที่แสดงในตัวอย่างนี้

Kotlin

val autofillSettingsIntent = Intent(Intent.ACTION_APPLICATION_PREFERENCES)
autofillSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT)
autofillSettingsIntent.addCategory(Intent.CATEGORY_APP_BROWSER)
autofillSettingsIntent.addCategory(Intent.CATEGORY_PREFERENCE)

// Invoking the intent with a chooser allows users to select the channel they
// want to configure. If only one browser reacts to the intent, the chooser is
// skipped.
val chooser = Intent.createChooser(autofillSettingsIntent, "Pick Chrome Channel")
startActivity(chooser)

// If the caller knows which Chrome channel they want to configure,
// they can instead add a package hint to the intent, e.g.
val specificChromeIntent = Intent(Intent.ACTION_APPLICATION_PREFERENCES) // Create a *new* intent
specificChromeIntent.addCategory(Intent.CATEGORY_DEFAULT)
specificChromeIntent.addCategory(Intent.CATEGORY_APP_BROWSER)
specificChromeIntent.addCategory(Intent.CATEGORY_PREFERENCE)
specificChromeIntent.setPackage("com.android.chrome") // Set the package on the *new* intent
startActivity(specificChromeIntent) // Start the *new* intent

Java

Intent autofillSettingsIntent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES);
autofillSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
autofillSettingsIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
autofillSettingsIntent.addCategory(Intent.CATEGORY_PREFERENCE);

// Invoking the intent with a chooser allows users to select the channel they
// want to configure. If only one browser reacts to the intent, the chooser is
// skipped.
Intent chooser = Intent.createChooser(autofillSettingsIntent, "Pick Chrome Channel");
startActivity(chooser);

// If the caller knows which Chrome channel they want to configure,
// they can instead add a package hint to the intent, e.g.
autofillSettingsIntent.setPackage("com.android.chrome");
startActivity(autofillSettingsInstent);

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

ผสานรวมกับแป้นพิมพ์
ตั้งแต่ 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_SAVE_ON_ALL_VIEWS_INVISIBLE หรือเรียกใช้เมธอด setTrigger() FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE จะตั้งค่าโดยค่าเริ่มต้นเมื่อ ใช้โหมดความเข้ากันได้
  • ค่าข้อความของโหนดอาจไม่พร้อมใช้งานในเมธอด onSaveRequest(SaveRequest, SaveCallback)

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