优化您的应用以实现自动填充

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

设置自动填充环境

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

配置自动填充服务

您的应用必须在设备上配置自动填充服务才能使用自动填充框架。虽然大多数运行 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 使用其启发式方法来确定视图是否对自动填充很重要。

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

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

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

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

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

关联网站和移动应用程序数据

在应用程序和网站关联后,诸如使用 Google 的自动填充之类的自动填充服务可以在浏览器和 Android 设备之间共享用户登录数据。当用户在两个平台上选择相同的自动填充服务时,登录到您的网络应用程序将使他们的登录凭据在他们登录到相应的 Android 应用程序时可供自动填充使用。

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

完成自动填充工作流程

本部分介绍了您可以采取措施来改善应用程序用户自动填充功能的特定场景。

确定是否启用了自动填充

用户可以通过导航到 **设置** > **系统** > **语言和输入** > **高级** > **输入辅助** > **自动填充服务** 来启用或禁用自动填充,以及更改自动填充服务。您的应用程序无法覆盖用户的自动填充设置,但如果自动填充对用户可用,您可以实现应用程序中的其他自动填充功能,或在应用程序的特定视图中实现。

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

为了确保您的注册和登录体验针对没有自动填充的用户进行了优化,请实现 一键式登录

强制自动填充请求

有时您需要强制自动填充请求以响应用户的操作而发生。例如,当用户在视图上执行触摸并按住操作时,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() 方法取消当前的自动填充上下文。这在您有一个按钮清除登录页面上的字段时很有用。

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

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

一个 EditText 对象本机预期类型为 AUTOFILL_TYPE_TEXT 的自动填充数据。如果您使用的是其他类型的数据,请创建一个从 EditText 继承并实现处理相应数据类型所需方法的自定义视图。例如,如果您有一个日期字段,请实现带有正确处理类型为 AUTOFILL_TYPE_DATE 的值的方法。

当您指定自动填充数据类型时,自动填充服务可以创建在视图中显示的数据的适当表示形式。有关更多信息,请参阅 将选择器与自动填充一起使用

完成自动填充上下文

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

对自定义视图的支持

自定义视图可以使用自动填充 API 来指定暴露给自动填充框架的元数据。一些视图充当虚拟子视图的容器,例如包含 OpenGL 渲染的 UI 的视图。这些视图必须使用 API 来指定应用程序中使用信息的结构,然后才能与自动填充框架一起使用。

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

  • 自定义视图提供一个标准视图结构或一个默认视图结构。
  • 自定义视图具有虚拟结构或自动填充框架不可用的视图结构。

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

自定义视图可以定义自动填充工作所需的元数据。确保您的自定义视图正确管理元数据以与自动填充框架一起使用。您的自定义视图必须采取以下操作

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

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

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

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

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

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

可编辑的自定义视图

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

自定义视图包含敏感数据

如果视图包含个人身份信息 (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()

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

自动填充框架在可以编辑和保存应用程序 UI 中的信息之前需要一个视图结构。在以下情况下,框架无法访问视图结构

  • 应用程序使用低级渲染引擎(例如OpenGL)来渲染 UI。
  • 应用程序使用Canvas实例来绘制 UI。

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

  1. 通过调用addChildCount()增加视图结构的子元素数量。
  2. 通过调用newChild()添加子元素。
  3. 通过调用setAutofillId()为子元素设置自动填充 ID。
  4. 设置相关属性,例如自动填充值和类型。
  5. 如果虚拟子元素中的数据是敏感的,请将true传递给setDataIsSensitive();否则,请传递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()

使用自动填充事件的回调

如果您的应用程序提供自己的自动完成视图,您需要一个机制来告诉应用程序在 UI 自动填充功能发生变化时启用或禁用视图。自动填充框架以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

当视图被自动填充时,平台会在视图上渲染一个Drawable,以指示视图内容是自动填充的。默认情况下,此 Drawable 是一个具有半透明颜色的实心矩形,该颜色比主题用于绘制背景的颜色略暗。Drawable 不需要更改,但可以通过重写应用程序或活动使用的主题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 系统将在您的活动堆栈中启动服务的身份验证活动。

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

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

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

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

如果回收视图的初始内容被填充,自动填充服务将使用其自动填充 ID 来保留视图的逻辑意义。当系统在布局中重新使用视图时,视图的逻辑 ID 保持不变,这会导致错误的自动填充用户数据与自动填充 ID 相关联,从而产生问题。

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

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

解决已知问题

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

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

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

调整大小的对话框未被视为自动填充目标

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

为了解决此问题,请将对话框窗口参数的token属性替换为创建对话框的活动的token属性。在验证自动填充已启用后,将窗口参数保存在继承自Dialog的类的onWindowAttributesChanged()方法中。然后,在onAttachedToWindow()方法中,将保存的参数的token属性替换为父活动的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. 打开您的应用,并转到包含要测试的视图的活动。
  2. 点击需要填充的视图。
  3. 系统将显示自动填充 UI,其中包含可用于填充视图的数据集,如图 1 所示。
  4. 点击包含要使用的数据集的数据集。该视图将显示先前存储在服务中的数据。
Autofill UI displaying "dataset-2" as an available dataset
图 1. 显示可用数据集的自动填充 UI。

如果 Android 没有显示自动填充 UI,您可以尝试以下故障排除选项:

  • 检查应用中的视图是否在 android:autofillHints 属性中使用了正确的值。有关属性的可能值的列表,请参阅 View 类中以 AUTOFILL_HINT 开头的常量。
  • 检查 android:importantForAutofill 属性是否在需要填充的视图上设置为除 no 之外的值,或者在该视图或其任何父视图上设置为除 noExcludeDescendants 之外的值。