Tối ưu hoá chức năng tự động điền của ứng dụng

Ứng dụng dùng thành phần hiển thị chuẩn kết hợp được với khung tự động điền mà không cần phải có cấu hình đặc biệt. Bạn cũng có thể tối ưu hoá cách ứng dụng dùng khung này.

Thiết lập môi trường tự động điền

Phần này mô tả cách thiết lập chức năng tự động điền cơ bản cho ứng dụng.

Định cấu hình dịch vụ tự động điền

Bạn phải định cấu hình dịch vụ tự động điền trên thiết bị để ứng dụng có thể dùng khung tự động điền. Tuy hầu hết điện thoại và máy tính bảng chạy Android 8.0 (API cấp 26) trở lên có dịch vụ tự động điền, nhưng bạn nên dùng dịch vụ kiểm thử khi kiểm thử ứng dụng, chẳng hạn như dịch vụ tự động điền trong mẫu khung tự động điền của Android. Khi dùng trình mô phỏng, hãy đặt rõ ràng dịch vụ tự động điền, vì trình mô phỏng có thể không đi kèm dịch vụ mặc định.

Sau khi bạn cài đặt dịch vụ tự động điền kiểm thử qua ứng dụng mẫu, hãy bật dịch vụ tự động điền bằng cách chuyển đến mục Cài đặt > Hệ thống > Ngôn ngữ và nhập liệu > Nâng cao > Hỗ trợ nhập liệu > Dịch vụ tự động điền.

Để biết thêm thông tin về cách định cấu hình trình mô phỏng nhằm kiểm thử tính năng tự động điền, hãy xem phần Kiểm thử tính năng tự động điền trong ứng dụng.

Đưa ra gợi ý để tự động điền

Dịch vụ tự động điền dùng thông tin phỏng đoán để xác định loại của từng khung hiển thị. Tuy nhiên, nếu ứng dụng của bạn dựa vào thông tin phỏng đoán này, thì hành vi tự động điền có thể đột ngột thay đổi khi bạn cập nhật ứng dụng. Để đảm bảo dịch vụ tự động điền xác định đúng hệ số hình dạng của ứng dụng, hãy cung cấp gợi ý tự động điền.

Bạn có thể đặt gợi ý tự động điền bằng thuộc tính android:autofillHints. Ví dụ sau đây đặt một gợi ý về "password" trên EditText:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:autofillHints="password" />

Bạn cũng có thể đặt gợi ý theo phương thức lập trình bằng setAutofillHints() như trong ví dụ sau:

Kotlin

val password = findViewById<EditText>(R.id.password)
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD)

Java

EditText password = findViewById(R.id.password);
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);

Bao gồm hằng số gợi ý định sẵn

Khung tự động điền không xác thực các gợi ý; các gợi ý được chuyển nhưng không có sự thay đổi hay xác thực nào đối với dịch vụ tự động điền. Mặc dù bạn có thể dùng giá trị bất kỳ, nhưng các lớp (class) View và AndroidX HintConstants sẽ chứa danh sách hằng số gợi ý được hỗ trợ chính thức.

Khi kết hợp các hằng số này, bạn có thể tạo bố cục cho các trường hợp tự động điền phổ biến:

Thông tin đăng nhập vào tài khoản

Trên biểu mẫu đăng nhập, bạn có thể đưa các gợi ý thông tin đăng nhập vào tài khoản như AUTOFILL_HINT_USERNAMEAUTOFILL_HINT_PASSWORD.

Để tạo tài khoản mới hoặc khi người dùng đổi tên người dùng và mật khẩu, bạn có thể sử dụng AUTOFILL_HINT_NEW_USERNAMEAUTOFILL_HINT_NEW_PASSWORD.

Thông tin thẻ tín dụng

Khi yêu cầu thông tin thẻ tín dụng, bạn có thể sử dụng các gợi ý như AUTOFILL_HINT_CREDIT_CARD_NUMBERAUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE.

Đối với ngày hết hạn thẻ tín dụng, hãy thực hiện một trong các gợi ý sau:

Địa chỉ thực tế

Đối với các trường biểu mẫu địa chỉ thực tế, bạn có thể dùng những gợi ý sau:

Tên người

Khi yêu cầu tên người, bạn có thể dùng những gợi ý sau:

Số điện thoại

Đối với số điện thoại, bạn có thể dùng những gợi ý sau:

Mật khẩu một lần (OTP)

Đối với mật khẩu một lần trong một khung hiển thị, bạn có thể dùng AUTOFILL_HINT_SMS_OTP.

Khi sử dụng nhiều khung hiển thị mà trong đó mỗi khung hiển thị liên kết với một chữ số của OTP, bạn có thể dùng phương thức generateSmsOtpHintForCharacterPosition() để tạo gợi ý cho mỗi ký tự.

Đánh dấu các trường là quan trọng đối với tính năng tự động điền

Bạn có thể đưa các trường riêng lẻ vào ứng dụng của mình trong cấu trúc khung hiển thị cho mục đích tự động điền. Theo mặc định, các khung hiển thị sẽ sử dụng chế độ IMPORTANT_FOR_AUTOFILL_AUTO, qua đó cho phép Android dùng thông tin phỏng đoán để xác định xem một khung hiển thị có quan trọng đối với tính năng tự động điền hay không.

Tuy nhiên, có những trường hợp khung hiển thị, cấu trúc khung hiển thị hoặc toàn bộ hoạt động đều không quan trọng đối với tính năng tự động điền:

  • Trường CAPTCHA trong một hoạt động đăng nhập
  • Một khung hiển thị mà ở đó người dùng tạo nội dung, chẳng hạn như trình chỉnh sửa văn bản hoặc bảng tính
  • Khung hiển thị ở một số hoạt động trong trò chơi, chẳng hạn như các hoạt động thể hiện lối chơi

Bằng cách dùng thuộc tính android:importantForAutofill, bạn có thể đặt tầm quan trọng của khung hiển thị cho tính năng tự động điền:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:importantForAutofill="no" />

Giá trị của importantForAutofill có thể là bất kỳ giá trị nào sau đây:

auto
Cho phép hệ thống Android dùng thông tin phỏng đoán để xác định xem khung hiển thị này có quan trọng đối với tính năng tự động điền hay không.
no
Khung hiển thị này không quan trọng đối với tính năng tự động điền.
noExcludeDescendants
Thành phần hiển thị này và các thành phần hiển thị con không quan trọng đối với tính năng tự động điền.
yes
Thành phần hiển thị này rất quan trọng đối với tính năng tự động điền.
yesExcludeDescendants
Khung hiển thị này rất quan trọng đối với tính năng tự động điền, nhưng các khung hiển thị con trong đó thì không.

Bạn cũng có thể dùng phương thức setImportantForAutofill():

Kotlin

val captcha = findViewById<TextView>(R.id.captcha)
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO)

Java

TextView captcha = findViewById(R.id.captcha);
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);

Bạn có thể khai báo các trường hợp sử dụng mẫu trước đó không quan trọng đối với tính năng tự động điền như sau:

  • Trường CAPTCHA trong hoạt động đăng nhập: dùng android:importantForAutofill="no" hoặc IMPORTANT_FOR_AUTOFILL_NO để đánh dấu khung hiển thị này là không quan trọng.
  • Khung hiển thị mà ở đó người dùng tạo nội dung: dùng android:importantForAutofill="noExcludeDescendants" hoặc IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS để đánh dấu toàn bộ cấu trúc khung hiển thị là không quan trọng.
  • Khung hiển thị ở một số hoạt động trong trò chơi: dùng android:importantForAutofill="noExcludeDescendants" hoặc IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS để đánh dấu toàn bộ cấu trúc khung hiển thị là không quan trọng.

Liên kết dữ liệu ứng dụng di động với dữ liệu trang web

Các dịch vụ tự động điền như Tự động điền bằng Google (Autofill with Google) có thể chia sẻ dữ liệu đăng nhập của người dùng giữa các trình duyệt và thiết bị Android sau khi ứng dụng và trang web được liên kết. Khi người dùng chọn cùng một dịch vụ tự động điền trên cả hai nền tảng, thao tác đăng nhập vào ứng dụng web của bạn sẽ cung cấp thông tin đăng nhập để tự động điền khi họ đăng nhập vào ứng dụng Android tương ứng.

Để liên kết ứng dụng Android với trang web, bạn cần lưu trữ một Digital Asset Link (Đường liên kết đến tài sản kỹ thuật số) với chuỗi mối quan hệ delegate_permission/common.get_login_creds trên trang web. Sau đó, hãy khai báo mối liên kết này trong tệp AndroidManifest.xml của ứng dụng. Để biết hướng dẫn chi tiết về cách liên kết trang web với ứng dụng Android, hãy xem phần Bật tính năng tự động đăng nhập trên ứng dụng và trang web.

Hoàn tất quy trình tự động điền

Phần này mô tả các tình huống cụ thể mà bạn có thể từng bước cải thiện chức năng tự động điền cho người dùng ứng dụng.

Xác định xem bạn đã bật tính năng tự động điền hay chưa

Người dùng có thể bật hoặc tắt tính năng tự động điền cũng như thay đổi dịch vụ tự động điền bằng cách chuyển đến mục Cài đặt > Hệ thống > Ngôn ngữ và nhập liệu > Nâng cao > Hỗ trợ nhập liệu > Dịch vụ tự động điền. Ứng dụng không thể ghi đè các chế độ cài đặt tự động điền của người dùng, nhưng bạn có thể triển khai chức năng tự động điền bổ sung trong ứng dụng hoặc trong các khung hiển thị cụ thể của ứng dụng nếu người dùng có thể sử dụng tính năng tự động điền.

Ví dụ: TextView sẽ hiển thị một mục tự động điền trong trình đơn mục bổ sung nếu tính năng tự động điền được bật cho người dùng. Để kiểm tra xem tính năng tự động điền đã được bật cho người dùng hay chưa, hãy gọi phương thức isEnabled() của đối tượng AutofillManager.

Để đảm bảo người dùng có trải nghiệm đăng ký và đăng nhập tốt nhất mà không cần tự động điền, hãy triển khai tính năng Đăng nhập bằng một lần chạm.

Buộc thực hiện yêu cầu tự động điền

Đôi khi, bạn cần buộc thực hiện một yêu cầu tự động điền để phản hồi hành động của người dùng. Ví dụ: TextView cung cấp một mục trong trình đơn tự động điền khi người dùng chạm và giữ trên khung hiển thị. Mã ví dụ sau đây cho thấy cách buộc thực hiện một yêu cầu tự động điền:

Kotlin

fun eventHandler(view: View) {
    val afm = requireContext().getSystemService(AutofillManager::class.java)
    afm?.requestAutofill(view)
}

Java

public void eventHandler(View view) {
    AutofillManager afm = context.getSystemService(AutofillManager.class);
    if (afm != null) {
        afm.requestAutofill(view);
    }
}

Bạn cũng có thể dùng phương thức cancel() để huỷ ngữ cảnh tự động điền hiện tại. Cách này có thể hữu ích nếu có nút xoá các trường trên trang đăng nhập.

Sử dụng đúng loại tự động điền cho dữ liệu thông qua phần điều khiển bộ chọn

Bộ chọn có thể hữu ích đối với tính năng tự động điền do cung cấp một giao diện người dùng cho phép họ thay đổi giá trị của trường lưu trữ dữ liệu ngày hoặc giờ. Ví dụ: trong biểu mẫu thẻ tín dụng, bộ chọn ngày cho phép người dùng nhập hoặc thay đổi ngày hết hạn của thẻ tín dụng. Tuy nhiên, bạn phải dùng khung hiển thị khác, chẳng hạn như EditText, để cho thấy dữ liệu khi bộ chọn không xuất hiện.

Theo dự kiến ban đầu, đối tượng EditText sẽ có dữ liệu tự động điền thuộc loại AUTOFILL_TYPE_TEXT. Nếu đang dùng loại dữ liệu khác, thì bạn nên tạo khung hiển thị tuỳ chỉnh kế thừa từ EditText và triển khai các phương thức cần thiết để xử lý loại dữ liệu tương ứng. Ví dụ: nếu bạn có trường ngày, hãy triển khai các phương thức có logic xử lý chính xác những giá trị thuộc loại AUTOFILL_TYPE_DATE.

Khi bạn chỉ định loại dữ liệu tự động điền, dịch vụ tự động điền có thể tạo bản trình bày phù hợp cho dữ liệu xuất hiện trong khung hiển thị. Để biết thêm thông tin, hãy xem phần Sử dụng bộ chọn có tính năng tự động điền.

Hoàn tất ngữ cảnh tự động điền

Khung tự động điền sẽ lưu dữ liệu mà người dùng nhập vào để sử dụng sau này bằng cách đưa ra thông báo "Save for autofill?" ("Lưu để tự động điền?") sau khi ngữ cảnh tự động điền hoàn tất. Thường thì ngữ cảnh tự động điền sẽ hoàn tất khi một hoạt động kết thúc. Tuy nhiên, trong một số trường hợp, bạn cần thông báo rõ ràng cho khung này; ví dụ: nếu bạn đang dùng cùng một hoạt động nhưng nhiều mảnh cho cả màn hình đăng nhập và màn hình nội dung. Trong những trường hợp như vậy, bạn có thể hoàn tất ngữ cảnh một cách rõ ràng bằng cách gọi AutofillManager.commit().

Hỗ trợ khung hiển thị tuỳ chỉnh

Các thành phần hiển thị tuỳ chỉnh có thể chỉ định siêu dữ liệu xuất hiện cho khung tự động điền bằng cách sử dụng API tự động điền. Một số thành phần hiển thị hoạt động như một vùng chứa thành phần con ảo, chẳng hạn như các thành phần hiển thị chứa giao diện người dùng hiển thị OpenGL. Các khung hiển thị này phải dùng API để xác định cấu trúc của thông tin dùng trong ứng dụng thì mới có thể hoạt động với khung tự động điền.

Nếu ứng dụng của bạn dùng khung hiển thị tuỳ chỉnh, hãy xem xét các trường hợp sau:

  • Khung hiển thị tuỳ chỉnh có cấu trúc khung hiển thị chuẩn hay cấu trúc khung hiển thị mặc định.
  • Khung hiển thị tuỳ chỉnh có cấu trúc ảo hay cấu trúc khung hiển thị không có sẵn cho khung tự động điền.

Khung hiển thị tuỳ chỉnh có cấu trúc khung hiển thị chuẩn

Khung hiển thị tuỳ chỉnh có thể xác định siêu dữ liệu mà tính năng tự động điền cần để hoạt động. Hãy đảm bảo khung hiển thị tuỳ chỉnh quản lý siêu dữ liệu một cách phù hợp để dùng được khung tự động điền. Khung hiển thị tuỳ chỉnh của bạn phải thực hiện các hành động sau:

  • Xử lý giá trị tự động điền mà khung gửi đến ứng dụng.
  • Cung cấp loại và giá trị tự động điền cho khung.

Khi tính năng tự động điền được kích hoạt, khung tự động điền sẽ gọi autofill() trên khung hiển thị rồi gửi giá trị mà khung hiển thị đó phải dùng. Hãy triển khai autofill() để chỉ định cách khung hiển thị tuỳ chỉnh xử lý giá trị tự động điền.

Khung hiển thị cần chỉ định loại và giá trị tự động điền bằng cách ghi đè phương thức getAutofillType()getAutofillValue() tương ứng.

Cuối cùng, tính năng tự động điền không được điền vào khung hiển thị này nếu người dùng không thể cung cấp giá trị cho khung hiển thị ở trạng thái hiện tại (ví dụ: nếu khung hiển thị bị tắt). Trong những trường hợp như vậy, getAutofillType() phải trả về AUTOFILL_TYPE_NONE, getAutofillValue() phải trả về nullautofill() không được làm gì cả.

Các trường hợp sau đây yêu cầu thêm một số bước để hoạt động chính xác trong khung:

  • Bạn có thể chỉnh sửa thành phần hiển thị tuỳ chỉnh.
  • Thành phần hiển thị tuỳ chỉnh chứa dữ liệu nhạy cảm.

Bạn có thể chỉnh sửa khung hiển thị tuỳ chỉnh

Nếu chỉnh sửa được khung hiển thị, hãy thông báo cho khung tự động điền về các thay đổi bằng cách gọi notifyValueChanged() trên đối tượng AutofillManager.

Khung hiển thị tuỳ chỉnh chứa dữ liệu nhạy cảm

Nếu một khung hiển thị chứa thông tin nhận dạng cá nhân (PII) như địa chỉ email, số thẻ tín dụng và mật khẩu, thì khung hiển thị đó phải được đánh dấu là nhạy cảm.

Nhìn chung, những khung hiển thị có nội dung được lấy từ các tài nguyên tĩnh thì không chứa dữ liệu nhạy cảm, còn những khung hiển thị có nội dung được đặt theo phương thức động thì có thể chứa dữ liệu nhạy cảm. Ví dụ: nhãn chứa nội dung nhập tên người dùng của bạn thì không chứa dữ liệu nhạy cảm, còn nhãn chứa nội dung Xin chào, John thì có chứa dữ liệu nhạy cảm.

Lưu ý: Khung tự động điền giả định rằng mọi dữ liệu đều nhạy cảm theo mặc định. Bạn có thể đánh dấu dữ liệu không nhạy cảm.

Để đánh dấu khung hiển thị là có/không chứa dữ liệu nhạy cảm, hãy triển khai onProvideAutofillStructure() rồi gọi setDataIsSensitive() trên đối tượng ViewStructure.

Mã ví dụ sau đây cho thấy cách đánh dấu dữ liệu trong cấu trúc khung hiển thị là không nhạy cảm:

Kotlin

override fun onProvideAutofillStructure(structure: ViewStructure, flags: Int) {
    super.onProvideAutofillStructure(structure, flags)

    structure.setDataIsSensitive(false)
}

Java

@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
    super.onProvideAutofillStructure(structure, flags);

    structure.setDataIsSensitive(false);
}

Nếu khung hiển thị chỉ chấp nhận những giá trị định sẵn, thì bạn có thể sử dụng phương thức setAutofillOptions() để đặt các tuỳ chọn có thể dùng để tự động điền vào khung hiển thị này. Cụ thể, những khung hiển thị có loại tự động điền là AUTOFILL_TYPE_LIST phải sử dụng phương thức này vì dịch vụ tự động điền có thể hoạt động hiệu quả hơn nếu biết các tuỳ chọn dùng để điền vào khung hiển thị.

Những khung hiển thị dùng trình chuyển đổi, chẳng hạn như Spinner, cũng có cách hoạt động tương tự. Ví dụ: một vòng quay cung cấp những năm được tạo theo phương thức động (dựa trên năm hiện tại) để dùng trong các trường hết hạn của thẻ tín dụng có thể triển khai phương thức getAutofillOptions() của giao diện Adapter nhằm cung cấp danh sách năm.

Những khung hiển thị dùng ArrayAdapter cũng có thể cung cấp danh sách giá trị. ArrayAdapter tự động đặt các tuỳ chọn tự động điền cho những tài nguyên tĩnh. Nếu bạn cung cấp giá trị theo phương thức động, hãy ghi đè getAutofillOptions().

Khung hiển thị tuỳ chỉnh có cấu trúc ảo

Khung tự động điền cần có một cấu trúc khung hiển thị thì mới chỉnh sửa và lưu được thông tin trong giao diện người dùng của ứng dụng. Khung sẽ không dùng được cấu trúc khung hiển thị trong các trường hợp sau:

  • Ứng dụng dùng một công cụ kết xuất hình ảnh cấp thấp, chẳng hạn như OpenGL, để kết xuất giao diện người dùng.
  • Ứng dụng dùng một thực thể của Canvas để vẽ giao diện người dùng.

Trong những trường hợp như vậy, bạn có thể chỉ định cấu trúc khung hiển thị bằng cách triển khai onProvideAutofillVirtualStructure() rồi làm theo các bước sau:

  1. Tăng số lượng khung hiển thị con của cấu trúc khung hiển thị bằng cách gọi addChildCount().
  2. Thêm khung hiển thị con bằng cách gọi newChild().
  3. Đặt mã tự động điền cho khung hiển thị con bằng cách gọi setAutofillId().
  4. Đặt các thuộc tính có liên quan, chẳng hạn như loại và giá trị tự động điền.
  5. Nếu dữ liệu trong khung hiển thị con ảo là nhạy cảm, hãy chuyển true đến setDataIsSensitive(); nếu không, hãy chuyển false.

Đoạn mã sau đây cho biết cách tạo khung hiển thị con mới trong cấu trúc ảo:

Kotlin

override fun onProvideAutofillVirtualStructure(structure: ViewStructure, flags: Int) {

    super.onProvideAutofillVirtualStructure(structure, flags)

    // Create a new child in the virtual structure.
    structure.addChildCount(1)
    val child = structure.newChild(childIndex)

    // Set the autofill ID for the child.
    child.setAutofillId(structure.autofillId!!, childVirtualId)

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue)
    child.setAutofillType(childAutofillType)

    // Some children can provide a list of values, such as when the child is
    // a spinner.
    val childAutofillOptions = arrayOf<CharSequence>("option1", "option2")
    child.setAutofillOptions(childAutofillOptions)

    // Just like other types of views, mark the data as sensitive when
    // appropriate.
    val sensitive = !contentIsSetFromResources()
    child.setDataIsSensitive(sensitive)
}

Java

@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {

    super.onProvideAutofillVirtualStructure(structure, flags);

    // Create a new child in the virtual structure.
    structure.addChildCount(1);
    ViewStructure child =
            structure.newChild(childIndex);

    // Set the autofill ID for the child.
    child.setAutofillId(structure.getAutofillId(), childVirtualId);

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue);
    child.setAutofillType(childAutofillType);

    // Some children can provide a list of values, such as when the child is
    // a spinner.
    CharSequence childAutofillOptions[] = { "option1", "option2" };
    child.setAutofillOptions(childAutofillOptions);

    // Just like other types of views, mark the data as sensitive when
    // appropriate.
    boolean sensitive = !contentIsSetFromResources();
    child.setDataIsSensitive(sensitive);
}

Khi các phần tử trong cấu trúc ảo thay đổi, hãy thông báo cho khung bằng cách thực hiện những tác vụ sau:

  • Nếu tiêu điểm bên trong khung hiển thị con thay đổi, hãy gọi notifyViewEntered()notifyViewExited() trên đối tượng AutofillManager.
  • Nếu giá trị của khung hiển thị con thay đổi, hãy gọi notifyValueChanged() trên đối tượng AutofillManager.
  • Nếu hệ phân cấp khung hiển thị không còn nữa vì người dùng đã hoàn tất một bước trong quy trình công việc, chẳng hạn như khi họ đăng nhập bằng biểu mẫu đăng nhập, hãy gọi commit() trên đối tượng AutofillManager.
  • Nếu hệ phân cấp khung hiển thị không hợp lệ vì người dùng đã huỷ một bước trong quy trình công việc, chẳng hạn như khi họ nhấn vào nút xoá biểu mẫu đăng nhập, hãy gọi cancel() trên đối tượng AutofillManager.

Sử dụng lệnh gọi lại trên sự kiện tự động điền

Nếu ứng dụng của bạn cung cấp các khung hiển thị tự động hoàn thành riêng, thì bạn cần có cơ chế yêu cầu ứng dụng bật hoặc tắt những khung hiển thị đó nhằm ứng phó với các thay đổi về khả năng tự động điền trên giao diện người dùng. Khung tự động điền cung cấp cơ chế này ở dạng AutofillCallback.

Lớp này cung cấp phương thức onAutofillEvent(View, int) mà ứng dụng sẽ gọi sau khi sự thay đổi về trạng thái tự động điền liên kết với một khung hiển thị. Ngoài ra còn có một phiên bản nạp chồng của phương thức này, bao gồm cả tham số childId mà ứng dụng của bạn có thể dùng với khung hiển thị ảo. Các trạng thái hiện có được xác định là hằng số trong lệnh gọi lại.

Bạn có thể đăng ký một lệnh gọi lại bằng phương thức registerCallback() của lớp AutofillManager. Mã ví dụ sau đây cho thấy cách khai báo một lệnh gọi lại cho các sự kiện tự động điền:

Kotlin

val afm = context.getSystemService(AutofillManager::class.java)

afm?.registerCallback(object : AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead.
    override fun onAutofillEvent(view: View, event: Int) {
        super.onAutofillEvent(view, event)
        when (event) {
            EVENT_INPUT_HIDDEN -> {
                // The autofill affordance associated with the view was hidden.
            }
            EVENT_INPUT_SHOWN -> {
                // The autofill affordance associated with the view was shown.
            }
            EVENT_INPUT_UNAVAILABLE -> {
                // Autofill isn't available.
            }
        }

    }
})

Java

AutofillManager afm = getContext().getSystemService(AutofillManager.class);

afm.registerCallback(new AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead.
    @Override
    public void onAutofillEvent(@NonNull View view, int event) {
        super.onAutofillEvent(view, event);
        switch (event) {
            case EVENT_INPUT_HIDDEN:
                // The autofill affordance associated with the view was hidden.
                break;
            case EVENT_INPUT_SHOWN:
                // The autofill affordance associated with the view was shown.
                break;
            case EVENT_INPUT_UNAVAILABLE:
                // Autofill isn't available.
                break;
        }
    }
});

Khi bạn cần loại bỏ lệnh gọi lại, hãy dùng phương thức unregisterCallback().

Tuỳ chỉnh tính năng tự động điền đối tượng có thể vẽ được làm nổi bật

Khi khung hiển thị được tự động điền, nền tảng này sẽ kết xuất một Drawable trên khung hiển thị đó để cho biết rằng nội dung khung hiển thị được tự động điền. Theo mặc định, đối tượng có thể vẽ này là một hình chữ nhật đồng nhất có màu trong suốt và tối hơn đôi chút so với màu của giao diện dùng để vẽ nền. Bạn không cần thay đổi đối tượng có thể vẽ, nhưng có thể tuỳ chỉnh bằng cách ghi đè mục android:autofilledHighlight của giao diện mà ứng dụng hoặc hoạt động dùng, như trong ví dụ sau:

res/values/styles.xml

<resources>
    <style name="MyAutofilledHighlight" parent="...">
        <item name="android:autofilledHighlight">@drawable/my_drawable</item>
    </style>
</resources>

res/drawable/my_drawable.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#4DFF0000" />
</shape>

AndroidManifest.xml

<application ...
    android:theme="@style/MyAutofilledHighlight">
<!-- or -->
<activity ...
    android:theme="@style/MyAutofilledHighlight">

Xác thực để tự động điền

Để hoàn tất được các trường trong ứng dụng, dịch vụ tự động điền có thể yêu cầu người dùng xác thực. Khi đó, hệ thống Android sẽ khởi chạy hoạt động xác thực của dịch vụ trong ngăn xếp của hoạt động.

Bạn không cần cập nhật ứng dụng để hỗ trợ tính năng xác thực vì quá trình này diễn ra trong dịch vụ. Tuy nhiên, bạn phải đảm bảo cấu trúc thành phần hiển thị của hoạt động được giữ nguyên khi hoạt động bắt đầu lại (ví dụ: bằng cách tạo cấu trúc thành phần hiển thị trong onCreate() thay vì trong onStart() hoặc onResume()).

Để xác minh cách hoạt động của ứng dụng khi một dịch vụ tự động điền yêu cầu xác thực, bạn có thể dùng HeuristicsService trên mẫu AutofillFramework và định cấu hình dịch vụ này nhằm yêu cầu phải xác thực phản hồi điền. Bạn cũng có thể dùng mẫu BadViewStructureCreationSignInActivity để mô phỏng vấn đề này.

Chỉ định mã tự động điền cho thành phần hiển thị tuần hoàn

Các vùng chứa sử dụng lại khung hiển thị (chẳng hạn như lớp RecyclerView) rất hữu ích đối với những ứng dụng cần hiện danh sách phần tử di chuyển dựa trên tập dữ liệu lớn. Khi vùng chứa di chuyển, hệ thống sử dụng lại các khung hiển thị trong bố cục, nhưng sau đó những khung hiển thị này sẽ chứa nội dung mới.

Nếu người dùng điền vào nội dung ban đầu của khung hiển thị được sử dụng lại, thì dịch vụ tự động điền sẽ giữ nguyên ý nghĩa logic của các khung hiển thị bằng mã tự động điền. Sự cố sẽ xảy ra khi hệ thống sử dụng lại các khung hiển thị trong bố cục, các mã nhận dạng logic của khung hiển thị vẫn giữ nguyên, khiến dữ liệu người dùng tự động điền không chính xác liên kết với một mã tự động điền.

Để giải quyết vấn đề này trên các thiết bị chạy Android 9 (API cấp 28) trở lên, bạn có thể quản lý rõ ràng mã tự động điền của những khung hiển thị mà RecyclerView dùng bằng các phương thức mới sau đây:

  • Phương thức getNextAutofillId() nhận một mã tự động điền mới dành riêng cho hoạt động.
  • Phương thức setAutofillId() đặt mã tự động điền logic duy nhất của khung hiển thị này trong hoạt động.

Giải quyết các vấn đề đã biết

Phần này trình bày giải pháp cho các vấn đề đã biết trong khung tự động điền.

Tính năng tự động điền khiến ứng dụng gặp sự cố trên Android 8.0, 8.1

Trên Android 8.0 (API cấp 26) và 8.1 (API cấp 27), tính năng tự động điền có thể khiến ứng dụng gặp sự cố trong một số trường hợp. Để giải quyết các vấn đề tiềm ẩn, hãy gắn thẻ bất kỳ khung hiển thị nào không được tự động điền bằng importantForAutofill=no. Bạn cũng có thể gắn thẻ toàn bộ hoạt động bằng importantForAutofill=noExcludeDescendants.

Không dùng hộp thoại đã đổi kích thước cho tính năng tự động điền

Trong Android 8.1 (API cấp 27) trở xuống, nếu một khung hiển thị ở hộp thoại đổi kích thước sau khi xuất hiện, thì khung hiển thị đó sẽ không được dùng để tự động điền. Những khung hiển thị như vậy không được đưa vào đối tượng AssistStructure mà hệ thống Android gửi đến dịch vụ tự động điền. Do đó, dịch vụ này không thể điền vào các khung hiển thị.

Để giải quyết vấn đề này, hãy thay thế thuộc tính token của các tham số cửa sổ hộp thoại bằng thuộc tính token của hoạt động tạo hộp thoại. Sau khi bạn xác thực rằng tính năng tự động điền đã bật, hãy lưu các tham số cửa sổ trong phương thức onWindowAttributesChanged() của lớp kế thừa từ Dialog. Tiếp đến, hãy thay thế thuộc tính token của các tham số đã lưu bằng thuộc tính token của hoạt động mẹ trong phương thức onAttachedToWindow().

Đoạn mã sau đây cho thấy một lớp triển khai giải pháp:

Kotlin

class MyDialog(context: Context) : Dialog(context) {

    // Used to store the dialog window parameters.
    private var token: IBinder? = null

    private val isDialogResizedWorkaroundRequired: Boolean
        get() {
            if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
                return false
            }
            val autofillManager = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                context.getSystemService(AutofillManager::class.java)
            } else {
                null
            }
            return autofillManager?.isEnabled ?: false
        }

    override fun onWindowAttributesChanged(params: WindowManager.LayoutParams) {
        if (params.token == null && token != null) {
            params.token = token
        }

        super.onWindowAttributesChanged(params)
    }

    override fun onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired) {
            token = ownerActivity!!.window.attributes.token
        }

        super.onAttachedToWindow()
    }

}

Java

public class MyDialog extends Dialog {

    public MyDialog(Context context) {
        super(context);
    }

    // Used to store the dialog window parameters.
    private IBinder token;

    @Override
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (params.token == null && token != null) {
            params.token = token;
        }

        super.onWindowAttributesChanged(params);
    }

    @Override
    public void onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired()) {
            token = getOwnerActivity().getWindow().getAttributes().token;
        }

        super.onAttachedToWindow();
    }

    private boolean isDialogResizedWorkaroundRequired() {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O
                || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
            return false;
        }
        AutofillManager autofillManager =
                null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            autofillManager = getContext().getSystemService(AutofillManager.class);
        }
        return autofillManager != null && autofillManager.isEnabled();
    }

}

Để tránh các hoạt động không cần thiết, đoạn mã sau đây cho biết cách kiểm tra xem tính năng tự động điền có được hỗ trợ trong thiết bị và cho người dùng hiện tại hay không, cũng như có bắt buộc phải thực hiện giải pháp này hay không:

Kotlin

// AutofillExtensions.kt

fun Context.isDialogResizedWorkaroundRequired(): Boolean {
    // After the issue is resolved on Android, check whether the
    // workaround is still required for the current device.
    return isAutofillAvailable()
}

fun Context.isAutofillAvailable(): Boolean {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        // The autofill framework is available on Android 8.0
        // or higher.
        return false
    }

    val afm = getSystemService(AutofillManager::class.java)
    // Return true if autofill is supported by the device and enabled
    // for the current user.
    return afm != null && afm.isEnabled
}

Java

public class AutofillHelper {

    public static boolean isDialogResizedWorkaroundRequired(Context context) {
        // After the issue is resolved on Android, check whether the
        // workaround is still required for the current device.
        return isAutofillAvailable(context);
    }

    public static boolean isAutofillAvailable(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // The autofill framework is available on Android 8.0
            // or higher.
            return false;
        }

        AutofillManager afm = context.getSystemService(AutofillManager.class);
        // Return true if autofill is supported by the device and enabled
        // for the current user.
        return afm != null && afm.isEnabled();
    }
}

Kiểm thử tính năng tự động điền trong ứng dụng

Sau khi bạn tối ưu hoá ứng dụng để dùng được các dịch vụ tự động điền, hãy kiểm thử xem ứng dụng có hoạt động như dự kiến với dịch vụ tự động điền hay không.

Bạn nên kiểm thử ứng dụng bằng trình mô phỏng hoặc thiết bị thực chạy Android 8.0 (API cấp 26) trở lên. Để biết thêm thông tin về cách tạo trình mô phỏng, hãy xem bài viết Tạo và quản lý thiết bị ảo.

Cài đặt dịch vụ tự động điền

Để kiểm thử được tính năng tự động điền trong ứng dụng của mình, bạn cần cài đặt một ứng dụng khác cung cấp dịch vụ tự động điền. Tuy có thể dùng ứng dụng bên thứ ba cho mục đích này, nhưng sẽ dễ dàng hơn nếu bạn dùng mẫu dịch vụ tự động điền do không cần đăng ký dịch vụ bên thứ ba nào.

Bạn có thể dùng mẫu khung tự động điền của Android trong Java để kiểm thử các dịch vụ tự động điền trong ứng dụng. Ứng dụng mẫu cung cấp dịch vụ tự động điền và lớp ứng dụng Activity mà bạn có thể sử dụng để kiểm thử quy trình công việc trước khi dùng trong ứng dụng. Trang này đề cập đến ứng dụng mẫu android-AutofillFramework.

Sau khi cài đặt ứng dụng, hãy bật dịch vụ tự động điền trong phần cài đặt hệ thống của trình mô phỏng bằng cách chuyển đến mục Cài đặt > Hệ thống > Ngôn ngữ và nhập liệu > Nâng cao > Hỗ trợ nhập liệu > Dịch vụ tự động điền.

Phân tích yêu cầu về dữ liệu

Để kiểm thử dịch vụ tự động điền trong ứng dụng, dịch vụ này cần có dữ liệu thì mới điền được vào ứng dụng. Dịch vụ này cũng cần nắm rõ loại dữ liệu dự kiến trong các khung hiển thị của ứng dụng. Ví dụ: nếu ứng dụng có khung hiển thị cần điền tên người dùng, thì dịch vụ này phải có tập dữ liệu chứa tên người dùng và một số cơ chế để biết rằng khung hiển thị cần đến dữ liệu như vậy.

Cho dịch vụ biết loại dữ liệu dự kiến trong các khung hiển thị bằng cách đặt thuộc tính android:autofillHints. Một số dịch vụ dùng thông tin phỏng đoán tinh vi để xác định loại dữ liệu, nhưng có những dịch vụ khác (chẳng hạn như ứng dụng mẫu này) lại dựa vào việc nhà phát triển cung cấp thông tin đó. Dịch vụ tự động điền sẽ hoạt động hiệu quả hơn trong ứng dụng nếu bạn đặt thuộc tính android:autofillHints ở những khung hiển thị phù hợp cho tính năng tự động điền.

Chạy bài kiểm thử

Sau khi phân tích các yêu cầu về dữ liệu, bạn có thể chạy bài kiểm thử, bao gồm cả hoạt động lưu dữ liệu kiểm thử vào dịch vụ tự động điền và kích hoạt tính năng tự động điền trong ứng dụng.

Lưu dữ liệu vào dịch vụ

Để lưu dữ liệu đang hoạt động vào dịch vụ tự động điền, hãy làm như sau:

  1. Mở ứng dụng chứa khung hiển thị cần đến loại dữ liệu bạn muốn dùng trong quá trình kiểm thử. Ứng dụng mẫu android-AutofillFramework cung cấp giao diện người dùng với các thành phần hiển thị cần đến một số loại dữ liệu, chẳng hạn như số thẻ tín dụng và tên người dùng.
  2. Nhấn vào khung hiển thị lưu giữ loại dữ liệu bạn cần.
  3. Nhập một giá trị vào khung hiển thị.
  4. Nhấn vào nút xác nhận, chẳng hạn như Sign in (Đăng nhập) hoặc Submit (Gửi). Thường thì bạn phải gửi biểu mẫu trước khi dịch vụ lưu dữ liệu.
  5. Xác minh yêu cầu quyền từ hộp thoại của hệ thống. Hộp thoại của hệ thống cho biết tên dịch vụ đang hoạt động và hỏi xem đây có phải là dịch vụ bạn muốn dùng trong quá trình kiểm thử hay không. Nếu bạn muốn dùng dịch vụ này, hãy nhấn vào Save (Lưu).

Nếu Android không hiện hộp thoại cấp quyền hoặc nếu dịch vụ đó không phải là dịch vụ bạn muốn dùng trong quá trình kiểm thử, hãy kiểm tra trong phần cài đặt hệ thống để đảm bảo dịch vụ đó đang hoạt động.

Kích hoạt tính năng tự động điền trong ứng dụng

Để kích hoạt tính năng tự động điền trong ứng dụng, hãy làm như sau:

  1. Mở ứng dụng rồi chuyển đến hoạt động có khung hiển thị mà bạn muốn kiểm thử.
  2. Nhấn vào khung hiển thị cần điền vào.
  3. Hệ thống sẽ hiện giao diện người dùng tự động điền, trong đó chứa các tập dữ liệu có thể điền vào khung hiển thị, như ở Hình 1.
  4. Nhấn vào tập dữ liệu chứa dữ liệu mà bạn muốn dùng. Khung hiển thị sẽ hiện dữ liệu đã lưu trữ trước đó trong dịch vụ.
Giao diện người dùng tự động điền cho thấy "dataset-2" dưới dạng tập dữ liệu hiện có
Hình 1. Giao diện người dùng tự động điền cho thấy các tập dữ liệu hiện có.

Nếu Android không hiện giao diện người dùng tự động điền, thì bạn có thể thử các phương án khắc phục sự cố sau đây:

  • Kiểm tra các khung hiển thị trong ứng dụng để đảm bảo dùng đúng giá trị ở thuộc tính android:autofillHints. Để biết danh sách giá trị có thể xuất hiện cho thuộc tính này, hãy xem các hằng số có tiền tố AUTOFILL_HINT trong lớp View.
  • Kiểm tra để đảm bảo thuộc tính android:importantForAutofill được đặt thành một giá trị không phải là no trên khung hiển thị cần điền vào hoặc thành một giá trị không phải là noExcludeDescendants trên khung hiển thị đó hay trên một trong số những khung hiển thị mẹ tương ứng.