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

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

设置自动填充环境

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

配置自动填充服务

您的应用必须在您的设备上配置自动填充服务才能使用自动填充框架。尽管大多数运行 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()方法取消当前自动填充上下文。如果您有一个按钮可以清除登录页面上的字段,这将非常有用。

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

选择器可以通过提供一个用户界面来使用自动填充,该用户界面允许用户更改存储日期或时间数据的字段的值。例如,在信用卡表单中,日期选择器允许用户输入或更改其信用卡的过期日期。但是,当选择器不可见时,您必须使用另一个视图(例如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()必须不执行任何操作。

以下情况需要其他步骤才能在框架内正常工作:

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

可编辑的自定义视图

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

自定义视图包含敏感数据

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

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

自动填充框架默认情况下假设所有数据都是敏感的。您可以标记不敏感的数据。

为了标记视图是否包含敏感数据,请实现onProvideAutofillStructure()并调用setDataIsSensitive()方法,对象为ViewStructure

下面的代码示例演示如何将视图结构中的数据标记为非敏感数据

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)的视图也类似。例如,一个基于当前年份动态创建年份的微调器(用于信用卡有效期字段),可以实现getAutofillOptions()方法(Adapter接口),以提供年份列表。

使用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参数,您的应用可以将其与虚拟视图一起使用。可用的状态定义为回调中的常量

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

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()中创建。

您可以使用AutofillFramework示例中的HeuristicsService并将其配置为需要填充响应身份验证来验证应用在自动填充服务需要身份验证时的行为。您还可以使用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的值。