优化应用以支持自动填充

使用标准视图的应用无需特殊配置即可使用自动填充框架。您还可以优化应用与该框架的协作方式。

设置自动填充环境

本部分介绍如何为您的应用设置基本的自动填充功能。

配置自动填充服务

您的设备上必须配置自动填充服务,您的应用才能使用自动填充框架。尽管大多数运行 Android 8.0(API 级别 26)及更高版本的手机和平板电脑都附带自动填充服务,但我们建议您在测试应用时使用测试服务,例如 Android 自动填充框架示例中的自动填充服务。使用模拟器时,请明确设置自动填充服务,因为模拟器可能不附带默认服务。

从示例应用安装测试自动填充服务后,依次导航至 设置 > 系统 > 语言和输入法 > 高级 > 输入协助 > 自动填充服务,启用该服务。

如需详细了解如何配置模拟器以测试自动填充,请参阅使用自动填充测试您的应用

提供自动填充提示

自动填充服务会使用启发式方法来确定每个视图的类型。然而,如果您的应用依赖于这些启发式方法,随着应用的更新,自动填充行为可能会意外改变。为了确保自动填充服务正确识别您应用的外形规格,请提供自动填充提示。

您可以使用 android:autofillHints 属性设置自动填充提示。以下示例为 EditText 设置了 "password" 提示

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

您还可以使用 setAutofillHints() 方法以编程方式设置提示,如下例所示

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);

包含预定义提示常量

自动填充框架不会验证提示;它们会原封不动地传递给自动填充服务,不进行任何更改或验证。虽然您可以使用任何值,但 View 和 AndroidX HintConstants 类包含了官方支持的提示常量列表。

结合使用这些常量,您可以构建常见自动填充场景的布局

账号凭据

在登录表单中,您可以包含账号凭据提示,例如 AUTOFILL_HINT_USERNAMEAUTOFILL_HINT_PASSWORD

创建新账号或用户更改其用户名和密码时,您可以使用 AUTOFILL_HINT_NEW_USERNAMEAUTOFILL_HINT_NEW_PASSWORD

信用卡信息

请求信用卡信息时,您可以使用诸如 AUTOFILL_HINT_CREDIT_CARD_NUMBERAUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE 等提示。

对于信用卡有效期,请执行以下任一操作

实际地址

对于实际地址表单字段,您可以使用以下提示

姓名

请求姓名时,您可以使用以下提示

电话号码

对于电话号码,您可以使用以下提示

一次性密码 (OTP)

如果您在单个视图中输入一次性密码,可以使用 AUTOFILL_HINT_SMS_OTP

如果多个视图分别对应 OTP 的一个数字,您可以使用 generateSmsOtpHintForCharacterPosition() 方法生成按字符的提示。

将字段标记为对自动填充重要

您可以将应用中的各个字段包含在视图结构中,以便用于自动填充。默认情况下,视图使用 IMPORTANT_FOR_AUTOFILL_AUTO 模式,该模式允许 Android 使用其启发式方法来确定视图对于自动填充是否重要。

然而,在某些情况下,视图、视图结构或整个 Activity 对自动填充并不重要

  • 登录 Activity 中的 CAPTCHA 字段
  • 用户创建内容的视图,例如文本或电子表格编辑器
  • 游戏内某些 Activity 中的视图,例如显示游戏玩法的视图

您可以使用 android:importantForAutofill 属性设置视图对于自动填充的重要性

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

importantForAutofill 的值可以是以下任何一种

auto
让 Android 系统使用其启发式方法来确定该视图对于自动填充是否重要。
no
此视图对于自动填充不重要。
noExcludeDescendants
此视图及其子视图对于自动填充不重要。
yes
此视图对于自动填充重要。
yesExcludeDescendants
此视图对于自动填充重要,但其子视图对于自动填充不重要。

您还可以使用 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);

您可以如下声明前面的示例用例对自动填充不重要

  • 登录 Activity 中的 CAPTCHA 字段:使用 android:importantForAutofill="no"IMPORTANT_FOR_AUTOFILL_NO 将此视图标记为不重要。
  • 用户创建内容的视图:使用 android:importantForAutofill="noExcludeDescendants"IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 将整个视图结构标记为不重要。
  • 游戏内某些 Activity 中的视图:使用 android:importantForAutofill="noExcludeDescendants"IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 将整个视图结构标记为不重要。

关联网站和移动应用数据

自动填充服务(例如“通过 Google 自动填充”)在应用和网站关联后,可以在浏览器和 Android 设备之间共享用户登录数据。当用户在两个平台上选择相同的自动填充服务时,登录您的 Web 应用后,其登录凭据便可在登录相应的 Android 应用时用于自动填充。

要将您的 Android 应用与您的网站关联,请在您的网站上托管一个包含 delegate_permission/common.get_login_creds 关系的 数字资产链接。然后,在应用的 AndroidManifest.xml 文件中声明该关联。有关如何将您的网站与 Android 应用关联的详细说明,请参阅在应用和网站之间启用自动登录

完成自动填充工作流程

本部分介绍了一些特定场景,您可以在这些场景中采取措施,以改善应用用户的自动填充功能体验。

确定自动填充是否已启用

用户可以通过依次导航到 设置 > 系统 > 语言和输入法 > 高级 > 输入协助 > 自动填充服务 来启用或停用自动填充以及更改自动填充服务。您的应用无法覆盖用户的自动填充设置,但如果用户可以使用自动填充功能,您可以在应用中或应用的特定视图中实现额外的自动填充功能。

例如,如果用户启用了自动填充,TextView 会在溢出菜单中显示一个自动填充条目。要检查用户是否启用了自动填充,请调用 AutofillManager 对象的 isEnabled() 方法。

为了确保您的注册和登录体验对未启用自动填充的用户进行了优化,请实现单触登录

强制执行自动填充请求

有时,您需要强制触发自动填充请求以响应用户操作。例如,当用户在视图上执行触摸并长按操作时,TextView 会提供一个自动填充菜单项。以下代码示例展示了如何强制执行自动填充请求

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);
    }
}

您还可以使用 cancel() 方法取消当前的自动填充上下文。如果您有一个按钮用于清除登录页面上的字段,此方法会很有用。

对选择器控件中的数据使用正确的自动填充类型

选择器通过提供允许用户更改存储日期或时间数据的字段值的界面,可以与自动填充一起使用。例如,在信用卡表单中,日期选择器允许用户输入或更改其信用卡的有效期。但是,在选择器不可见时,您必须使用另一个视图(例如 EditText)来显示数据。

一个 EditText 对象原生期望类型为 AUTOFILL_TYPE_TEXT 的自动填充数据。如果您使用的是不同类型的数据,请创建一个继承自 EditText 的自定义视图,并实现处理相应类型数据所需的方法。例如,如果您有一个日期字段,请实现能够正确处理类型为 AUTOFILL_TYPE_DATE 的值的方法。

当您指定自动填充数据类型时,自动填充服务可以创建视图中显示数据的适当表示形式。如需了解详情,请参阅将选择器与自动填充结合使用

完成自动填充上下文

自动填充框架通过在自动填充上下文完成后显示“保存以自动填充?”对话框来保存用户输入以供将来使用。通常,当 Activity 完成时,自动填充上下文也就完成了。然而,在某些情况下,您需要明确通知框架,例如,如果您对登录和内容屏幕使用相同的 Activity 但不同的 Fragment。在这种情况下,您可以通过调用 AutofillManager.commit() 明确完成上下文。

支持自定义视图

自定义视图可以使用自动填充 API 指定向自动填充框架公开的元数据。有些视图充当虚拟子项的容器,例如包含 OpenGL 渲染界面的视图。这些视图必须在使用 API 来指定应用中使用信息的结构后,才能与自动填充框架配合使用。

如果您的应用使用自定义视图,请考虑以下场景

  • 自定义视图提供标准视图结构,或默认视图结构。
  • 自定义视图具有虚拟结构,即自动填充框架无法使用的视图结构。

具有标准视图结构的自定义视图

自定义视图可以定义自动填充正常工作所需的元数据。确保您的自定义视图正确管理元数据,以便与自动填充框架配合使用。您的自定义视图必须执行以下操作

  • 处理框架发送到您应用的自动填充值。
  • 向框架提供自动填充类型和值。

触发自动填充时,自动填充框架会在您的视图上调用 autofill(),并发送您的视图必须使用的值。实现 autofill() 以指定自定义视图如何处理自动填充值。

您的视图必须分别通过重写 getAutofillType()getAutofillValue() 方法来指定自动填充类型和值。

最后,如果用户无法在当前状态下为视图提供值(例如,视图被禁用),则自动填充不应填充该视图。在这种情况下,getAutofillType() 必须返回 AUTOFILL_TYPE_NONEgetAutofillValue() 必须返回 null,并且 autofill() 必须不执行任何操作。

以下情况需要采取额外步骤才能在框架内正常工作

  • 自定义视图是可编辑的。
  • 自定义视图包含敏感数据。

自定义视图是可编辑的

如果视图是可编辑的,请通过在 AutofillManager 对象上调用 notifyValueChanged() 来通知自动填充框架有关更改。

自定义视图包含敏感数据

如果视图包含电子邮件地址、信用卡号和密码等个人身份信息 (PII),则必须将其标记为敏感信息。

一般来说,内容来自静态资源的视图不包含敏感数据,而内容动态设置的视图可能包含敏感数据。例如,包含请输入您的用户名的标签不包含敏感数据,而包含你好,John的标签则包含敏感数据。

自动填充框架默认假定所有数据都是敏感的。您可以将不敏感的数据标记出来。

要标记视图是否包含敏感数据,请实现 onProvideAutofillStructure(),并在 ViewStructure 对象上调用 setDataIsSensitive()

以下代码示例展示了如何将视图结构中的数据标记为不敏感

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);
}

如果视图只接受预定义值,您可以使用 setAutofillOptions() 方法设置可用于自动填充视图的选项。特别是自动填充类型为 AUTOFILL_TYPE_LIST 的视图必须使用此方法,因为如果自动填充服务知道可用于填充视图的选项,其效果会更好。

使用适配器(例如 Spinner)的视图情况类似。例如,一个根据当前年份动态创建年份并在信用卡有效期字段中使用的微调框可以实现 Adapter 接口的 getAutofillOptions() 方法来提供年份列表。

使用 ArrayAdapter 的视图也可以提供值列表。ArrayAdapter 会自动为静态资源设置自动填充选项。如果您动态提供值,请重写 getAutofillOptions()

具有虚拟结构的自定义视图

自动填充框架需要视图结构才能编辑和保存应用界面中的信息。在以下情况下,框架无法获取视图结构

  • 应用使用低级渲染引擎(例如 OpenGL)渲染界面。
  • 应用使用 Canvas 实例绘制界面。

在这些情况下,您可以通过实现 onProvideAutofillVirtualStructure() 并遵循以下步骤来指定视图结构

  1. 通过调用 addChildCount() 增加视图结构的子项计数。
  2. 通过调用 newChild() 添加子项。
  3. 通过调用 setAutofillId() 设置子项的自动填充 ID。
  4. 设置相关属性,例如自动填充值和类型。
  5. 如果虚拟子项中的数据是敏感的,则向 setDataIsSensitive() 传递 true;否则,传递 false

以下代码段展示了如何在虚拟结构中创建新子项

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);
}

当虚拟结构中的元素发生变化时,通过执行以下任务通知框架

  • 如果子项内的焦点发生变化,请在 AutofillManager 对象上调用 notifyViewEntered()notifyViewExited()
  • 如果子项的值发生变化,请在 AutofillManager 对象上调用 notifyValueChanged()
  • 如果视图层级结构因用户完成工作流程中的某个步骤(例如使用登录表单登录)而不再可用,请在 AutofillManager 对象上调用 commit()
  • 如果视图层级结构因用户取消工作流程中的某个步骤(例如用户点按清除登录表单的按钮)而无效,请在 AutofillManager 对象上调用 cancel()

使用自动填充事件回调

如果您的应用提供了自己的自动完成视图,您需要一种机制来告知应用根据界面自动填充的易用性变化启用或停用这些视图。自动填充框架以 AutofillCallback 的形式提供了这种机制。

此类提供了 onAutofillEvent(View, int) 方法,该方法在与视图关联的自动填充状态发生变化后由应用调用。此方法还有一个重载版本,其中包含一个 childId 参数,您的应用可以与虚拟视图一起使用。可用状态在回调中定义为常量

您可以使用 AutofillManager 类的 registerCallback() 方法注册回调。以下代码示例展示了如何声明自动填充事件的回调

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;
        }
    }
});

需要移除回调时,请使用 unregisterCallback() 方法。

自定义自动填充高亮可绘制对象

视图被自动填充时,平台会在视图上方渲染一个 Drawable,以表明视图内容已自动填充。默认情况下,此可绘制对象是一个实心矩形,其半透明颜色比用于绘制背景的主题颜色略深。无需更改此可绘制对象,但可以通过重写应用或 Activity 使用的主题android:autofilledHighlight 项进行自定义,如本例所示

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">

自动填充身份验证

自动填充服务可能要求用户在服务完成应用中的字段之前进行身份验证,在这种情况下,Android 系统会作为您的 Activity 堆栈的一部分启动该服务的身份验证 Activity。

您无需更新您的应用即可支持身份验证,因为身份验证发生在服务内部。但是,您必须确保 Activity 重启时其视图结构得到保留,例如通过在 onCreate() 中创建视图结构,而不是在 onStart()onResume() 中创建。

您可以通过使用 AutofillFramework 示例中的 HeuristicsService,并将其配置为需要填充响应身份验证,来验证您的应用在自动填充服务需要身份验证时的行为。您还可以使用 BadViewStructureCreationSignInActivity 示例来模拟此问题。

将自动填充 ID 分配给回收视图

回收视图的容器(例如 RecyclerView 类)对于需要基于大型数据集显示滚动元素列表的应用很有用。随着容器滚动,系统会重用布局中的视图,但这些视图随后会包含新内容。

如果回收视图的初始内容被填充,自动填充服务会使用其自动填充 ID 保留视图的逻辑含义。当系统重用布局中的视图时,如果视图的逻辑 ID 保持不变,就会出现问题,导致错误的自动填充用户数据与自动填充 ID 关联。

为了解决 Android 9(API 级别 28)及更高版本设备上的此问题,请使用以下方法明确管理 RecyclerView 使用的视图的自动填充 ID

  • getNextAutofillId() 方法获取一个 Activity 独有的新自动填充 ID。
  • 使用 setAutofillId() 方法设置此视图在 Activity 中唯一的逻辑自动填充 ID。

解决已知问题

本部分介绍了自动填充框架中的已知问题的解决方法。

自动填充导致应用在 Android 8.0、8.1 上崩溃

在 Android 8.0(API 级别 26)和 8.1(API 级别 27)中,自动填充在某些场景下可能导致您的应用崩溃。为了解决潜在问题,请使用 importantForAutofill=no 标记任何未自动填充的视图。您也可以使用 importantForAutofill=noExcludeDescendants 标记整个 Activity。

大小调整后的对话框不计入自动填充范围

在 Android 8.1(API 级别 27)及更低版本中,如果对话框中的视图在显示后被调整大小,则该视图不计入自动填充范围。这些视图不包含在 Android 系统发送给自动填充服务的 AssistStructure 对象中。因此,服务无法填充这些视图。

要解决此问题,请将对话框窗口参数的 token 属性替换为创建对话框的 Activity 的 token 属性。验证自动填充已启用后,将窗口参数保存在继承自 Dialog 的类的 onWindowAttributesChanged() 方法中。然后,在 onAttachedToWindow() 方法中,将保存参数的 token 属性替换为父 Activity 的 token 属性。

以下代码段展示了一个实现此解决方法类的示例

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();
    }

}

为避免不必要的操作,以下代码段展示了如何检查设备是否支持自动填充,以及当前用户是否已启用自动填充,以及是否需要此解决方法

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();
    }
}

使用自动填充测试您的应用

优化应用以与自动填充服务配合使用后,请测试其是否能与自动填充服务按预期工作。

使用运行 Android 8.0(API 级别 26)或更高版本的模拟器或物理设备测试您的应用。如需详细了解如何创建模拟器,请参阅创建和管理虚拟设备

安装自动填充服务

在使用自动填充测试您的应用之前,您需要安装另一个提供自动填充服务的应用。为此,您可以使用第三方应用,但使用示例自动填充服务会更容易,这样您就不需要注册第三方服务。

您可以使用Java 中的 Android 自动填充框架示例来测试您的应用与自动填充服务的配合情况。示例应用提供了自动填充服务和客户端 Activity 类,您可以在将其与您的应用一起使用之前测试工作流程。本页面引用的是 android-AutofillFramework 示例应用。

安装应用后,依次导航至模拟器的系统设置中的 设置 > 系统 > 语言和输入法 > 高级 > 输入协助 > 自动填充服务,启用自动填充服务。

分析数据要求

要使用自动填充服务测试您的应用,服务需要拥有可用于填充应用的数据。服务还需要了解您的应用视图中期望的数据类型。例如,如果您的应用有一个视图期望输入用户名,服务必须有一个包含用户名的数据集,并且能够知道该视图期望此类数据。

通过设置 android:autofillHints 属性,告知服务您的视图中期望的数据类型。有些服务使用复杂的启发式方法来确定数据类型,但其他服务(例如示例应用)则依赖开发者提供此信息。如果您在与自动填充相关的视图中设置了 android:autofillHints 属性,您的应用将更好地与自动填充服务协同工作。

运行测试

分析数据要求后,您可以运行测试,包括在自动填充服务中保存测试数据以及在应用中触发自动填充。

在服务中保存数据

要在当前处于活动状态的自动填充服务中保存数据,请执行以下操作

  1. 打开一个应用,其中包含一个视图,该视图期望您在测试期间要使用的数据类型。android-AutofillFramework 示例应用提供了一个 UI,其中包含期望输入多种类型数据的视图,例如信用卡号和用户名。
  2. 点按包含所需数据类型的视图。
  3. 在视图中输入一个值。
  4. 点按确认按钮,例如登录提交。服务通常需要在您提交表单后才能保存数据。
  5. 验证系统对话框中的权限请求。系统对话框会显示当前处于活动状态的服务名称,并询问这是否是您要在测试中使用的服务。如果您想使用此服务,请点按保存

如果 Android 未显示权限对话框,或者该服务并非您要在测试中使用的服务,请检查该服务是否在系统设置中处于活动状态。

在应用中触发自动填充

要在您的应用中触发自动填充,请执行以下操作

  1. 打开您的应用,然后转到包含您要测试视图的 Activity。
  2. 点按需要填充的视图。
  3. 系统会显示自动填充界面,其中包含可以填充该视图的数据集,如图 1 所示。
  4. 点按包含您要使用的数据的数据集。视图会显示之前存储在服务中的数据。
Autofill UI displaying "dataset-2" as an available dataset
图 1. 显示可用数据集的自动填充界面。

如果 Android 未显示自动填充界面,您可以尝试以下故障排除选项

  • 检查您的应用中的视图在 android:autofillHints 属性中使用了正确的值。如需了解该属性的可能值列表,请参阅 View 类中带有 AUTOFILL_HINT 前缀的常量。
  • 检查需要填充的视图的 android:importantForAutofill 属性是否设置为除 no 以外的值,或者在视图或其某个父项上设置为除 noExcludeDescendants 以外的值。