如何使用Android O的自动填充框架

自动表单填充(通常简称为自动填充)是浏览器多年来支持的功能。 我们大多数人一直在使用它。 我认为,在填写注册表或完成结帐流程之类的任务期间,它是必不可少的。

Android的最新版本Android O为Android应用程序带来了类似的功能。 换句话说,Android现在可以帮助用户填写属于他们在设备上安装的所有应用程序的表格。 这是一个人们期待已久的功能,因为在小屏幕上使用虚拟键盘打字通常很麻烦。

作为应用程序开发人员,您可以使用新的自动填充框架来创建自己的自定义自动填充服务,该服务决定如何填充应用程序的输入字段。 在本教程中,我将向您展示如何进行。

先决条件

要遵循本教程,您需要:

1.创建一个新项目

启动Android Studio并创建一个活动为空的新项目。 当然,您必须记住在“ 目标Android设备”对话框中选择Android 7+

Target android devices dialog

该项目将需要一些属于Design Support Library的小部件,因此打开app模块的build.gradle文件,并向其添加以下compile依赖项:

compile 'com.android.support:design:26.+'

最后,按立即同步按钮以更新项目。

2.创建一个设置活动

在本教程中,我们将创建一个包含非常简单的自动填充服务的应用程序,该服务仅针对希望用户输入电子邮件地址的那些输入字段。 由于今天Google Play上几乎所有其他应用都要求提供电子邮件地址,因此该服务将非常有用。

我们的服务显然需要知道用户的电子邮件地址是什么。 因此,现在让我们建立一个活动,用户可以输入并保存两个电子邮件地址。

步骤1:定义布局

如您所料,活动的布局将包含两个EditText小部件,用户可以在其中键入他或她的电子邮件地址。 如果您希望它遵循Material Design的准则,则将EditText小部件放置在TextInputLayout容器内是个好主意。

此外,该布局必须具有用户可以按下以保存电子邮件地址的“ Button小部件。

您可以随意将小部件放置在所需的任何位置。 不过,现在,我建议您将它们全部放置在垂直方向的LinearLayout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/primary"
            android:hint="Your primary email address"
            android:inputType="textEmailAddress"/>
    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/secondary"
            android:hint="Your other email address"
            android:inputType="textEmailAddress"/>
    </android.support.design.widget.TextInputLayout>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/save_button"
        style="@style/Widget.AppCompat.Button.Colored"
        android:text="Save"
        android:onClick="saveEmailAddresses"/>

</LinearLayout>

在上面的代码中,您可以看到Button小部件具有指向方法的onClick属性。 单击Android Studio中此属性旁边的黄色灯泡,以在关联的Activity类中为其生成存根。

public void saveEmailAddresses(View view) {
    // More code will be added here
}

步骤2:保存电子邮件地址

我们将使用一个名为EMAIL_STORAGE的共享首选项文件来保存我们的数据。 您可以使用Activity类的getSharedPreferences()方法来访问文件。 此外,为了能够写入文件,必须调用其edit()方法,该方法会生成一个SharedPreferences.Editor对象。

因此,在saveEmailAddresses()方法内添加以下代码:

SharedPreferences.Editor editor = 
        getSharedPreferences("EMAIL_STORAGE", MODE_PRIVATE).edit();

要获取用户在EditText小部件中键入的电子邮件地址,您必须首先使用findViewById()方法获取对它们的引用,然后再调用其getText()方法。

String primaryEmailAddress = 
                ((EditText)findViewById(R.id.primary))
                            .getText().toString();
                            
String secondaryEmailAddress = 
                ((EditText)findViewById(R.id.secondary))
                            .getText().toString();

此时,您可以调用编辑器的putString()方法,将电子邮件地址作为两个键值对添加到首选项文件中。 完成此操作后,请不要忘记调用commit()方法以使更改永久生效。

editor.putString("PRIMARY_EMAIL", primaryEmailAddress);
editor.putString("SECONDARY_EMAIL", secondaryEmailAddress);
editor.commit();

步骤3:建立中继资料档案

我们在上一步中创建的settings活动目前仅是一个普通活动。 为了让Android平台知道这是自动填充服务的设置活动,我们必须创建一个元数据XML文件。

在项目的res / xml文件夹中创建一个名为email_address_filler.xml的新XML文件。 在其中添加<autofill-service>标记,并将其settingsActivity属性的值settingsActivityActivity类的名称。

<?xml version="1.0" encoding="utf-8"?>
<autofill-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.tutsplus.simplefill.MainActivity"/>

现在,您可以运行该应用程序,输入两个电子邮件地址,然后按保存按钮以保存它们。

Settings activity running

3.创建自动填充服务

任何扩展抽象AutoFillService类的类都可以用作自动填充服务。 因此,首先使用File> New> Java Class创建一个新的Java类 。 在弹出的对话框中,将类命名为EmailAddressFiller ,并确保将Superclass字段的值设置为AutoFillService

Create new class dialog

Android Studio现在将提示您为两种抽象方法生成存根: onSaveRequest()onFillRequest() 。 在本教程中,我们将仅关注onFillRequest()方法,只要用户打开包含输入字段的任何应用程序的活动,该方法就会自动调用。

@Override
public void onFillRequest(AssistStructure assistStructure, 
                          Bundle bundle,
                          CancellationSignal cancellationSignal,
                          FillCallback fillCallback) {

    // More code goes here

}

步骤1:分析视图层次结构

自动填充服务需要分析应用程序的用户界面,并确定其可以填充的输入字段。 这就是为什么onFillRequest()方法接收AssistStructure对象的原因,该对象包含有关当前在屏幕上可见的所有小部件的详细信息。 更确切地说,它包含一个ViewNode对象树。

如果您从未见过这样的树,建议您使用uiautomatorviewer工具(它是Android SDK的一部分)来分析一些应用程序的布局层次结构。 例如,以下是Android默认邮件应用的布局层次结构:

View hierarchy of default mail app

自然地,要分析树的所有节点,您需要一种递归方法。 现在创建一个:

void identifyEmailFields(AssistStructure.ViewNode node, 
                     List<AssistStructure.ViewNode> emailFields) {
    // More code goes here
}

如您所见,此方法有一个ViewNode和一个List作为其参数。 我们将使用List存储所有需要电子邮件地址的输入字段。

您现在可能想知道如何以编程方式判断输入字段是否需要电子邮件地址。 好吧,实际上没有可以遵循的万无一失的方法。 现在,我们将假定所有应用程序开发人员始终向其输入字段提供有意义的资源ID。 基于该假设,我们可以简单地选择资源ID包含诸如“ email”和“ username”之类的字符串的所有输入字段。

因此,将以下代码添加到该方法:

if(node.getClassName().contains("EditText")) {
    String viewId = node.getIdEntry();
    if(viewId!=null && (viewId.contains("email") 
                        || viewId.contains("username"))) {
        emailFields.add(node);
        return;
    }
}

接下来,每当我们遇到一个ViewNode包含多个对象ViewNode对象,我们必须递归调用identifyEmailFields()方法来分析它的所有儿童。 以下代码向您展示了如何:

for(int i=0; i<node.getChildCount();i++) {
    identifyEmailFields(node.getChildAt(i), emailFields);
}

此时,我们可以在onFillRequest() identifyEmailFields()方法内调用onFillRequest()方法,并将视图层次结构的根节点传递给它。

// Create an empty list
List<AssistStructure.ViewNode> emailFields = new ArrayList<>();

// Populate the list
identifyEmailFields(assistStructure
                    .getWindowNodeAt(0)
                    .getRootViewNode(), emailFields);

如果我们的服务无法识别电子邮件的任何输入字段,则不应执行任何操作。 因此,向其添加以下代码:

if(emailFields.size() == 0)
    return;

步骤2:创建并填充远程视图

如果我们的服务确实确定了可以填充的输入字段,则必须填充一个下拉列表,该列表将显示在输入字段下方。 但是,这样做并不是一件容易的事,因为输入字段和下拉列表都不属于我们的应用程序。

要填充下拉列表,我们必须使用RemoteViews对象。 顾名思义, RemoteViews对象是可以在另一个应用程序中显示的视图的集合。

要初始化RemoteViews对象,您需要一个布局XML文件。 让我们创建一个现在称为email_suggestion.xml的文件 。 目前,它只能包含一个TextView小部件以显示电子邮件地址。

因此,将以下代码添加到email_suggestion.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/email_suggestion_item"
    android:textSize="18sp"
    android:textStyle="bold"
    android:padding="5dp">
</TextView>

现在,您可以返回onFillRequest()方法并创建两个RemoteViews对象:一个用于主电子邮件,另一个用于辅助电子邮件。

RemoteViews rvPrimaryEmail = 
            new RemoteViews(getPackageName(), 
                            R.layout.email_suggestion);
                            
RemoteViews rvSecondaryEmail = 
            new RemoteViews(getPackageName(),
                            R.layout.email_suggestion);

RemoteViews对象中的TextView小部件必须显示我们之前存储在共享首选项文件中的两个电子邮件地址。 要打开文件,请再次使用getSharedPreferences()方法。 打开后,您可以使用其getString()方法获取两个电子邮件地址。

最后,要设置远程TextView小部件的内容,必须使用setTextViewText()方法。

// Load the email addresses from preferences
SharedPreferences sharedPreferences = 
                getSharedPreferences("EMAIL_STORAGE", MODE_PRIVATE);

String primaryEmail = 
                sharedPreferences.getString("PRIMARY_EMAIL", "");
String secondaryEmail = 
                sharedPreferences.getString("SECONDARY_EMAIL", "");

// Update remote TextViews
rvPrimaryEmail.setTextViewText(R.id.email_suggestion_item, 
                               primaryEmail);
rvSecondaryEmail.setTextViewText(R.id.email_suggestion_item,
                                 secondaryEmail);

步骤3:建立资料集

现在,我们可以使用远程视图来创建可自动发送到任何应用程序的数据集。 为避免本教程过长,我们将仅为遇到的第一个电子邮件输入字段创建数据集。 以下代码显示了如何仅选择第一个电子邮件输入字段:

AssistStructure.ViewNode emailField = emailFields.get(0);

自动填充数据集不过是Dataset类的实例,可以使用Dataset.Builder类进行构建。

当用户选择我们的服务在下拉列表中显示的电子邮件地址之一时,它必须使用Dataset.Builder类的setValue()方法设置关联输入字段的内容。 但是,不能将ViewNode对象传递给setValue()方法。 实际上,它需要一个自动填充标识符,必须通过调用ViewNode对象的getAutoFillId()方法来获取该ViewNode

此外,要指定必须写入输入字段的文本,必须使用AutoFillValue.forText()方法。 以下代码向您展示了如何:

Dataset primaryEmailDataSet = 
            new Dataset.Builder(rvPrimaryEmail)
                        .setValue(
                            emailField.getAutoFillId(),
                            AutoFillValue.forText(primaryEmail)
                        ).build();

Dataset secondaryEmailDataSet = 
            new Dataset.Builder(rvSecondaryEmail)
                        .setValue(
                            emailField.getAutoFillId(),
                            AutoFillValue.forText(secondaryEmail)
                        ).build();

在将数据集发送到应用程序之前,必须将它们添加到FillResponse对象,该对象可以使用FillResponse.Builder类进行构建。 调用其addDataset()方法两次以添加两个数据集。

一旦FillResponse对象是准备好了,把它作为一个参数传递给onSuccess()的方法FillCallback对象,这是的参数之一onFillRequest()方法。

FillResponse response = new FillResponse.Builder()
                            .addDataset(primaryEmailDataSet)
                            .addDataset(secondaryEmailDataSet)
                            .build();

fillCallback.onSuccess(response);

步骤4:更新清单

与所有服务一样,自动填充服务也必须在项目的AndroidManifest.xml文件中声明。 这样做时,必须确保它受到android.permission.BIND_AUTO_FILL权限的保护。

此服务还需要一个<intent-filter>标记,以使其能够响应android.service.autofill.AutoFillService操作,以及一个<meta-data>标记,该标记指向我们在上一步中创建的元数据XML文件。 。

因此,将以下行添加到清单文件中:

<service android:name=".EmailAddressFiller"
    android:permission="android.permission.BIND_AUTO_FILL">
    <meta-data android:name="android.autofill"
        android:resource="@xml/email_address_filler"/>
    <intent-filter>
        <action android:name="android.service.autofill.AutoFillService"/>
    </intent-filter>
</service>

我们的自动填充服务和应用现已准备就绪。 生成项目并在您的设备上安装该应用程序。

4.激活并使用自动填充服务

要激活自动填充服务,请打开设备的“设置”应用,然后导航至“ 应用和通知”>“高级”>“默认应用”>“自动填充”应用 。 在下一个屏幕中,从可用的自动填充应用列表中选择您的应用。

Autofill app selection screen

现在,您可以打开任何要求输入电子邮件地址的应用程序,以查看自动填充服务的运行情况。 例如,这是您在Instagram和Pinterest的登录屏幕上看到的内容:

Autofill suggestions displayed for two popular apps

结论

现在,您知道如何为Android创建和使用自定义自动填充服务。 随意扩展它以支持其他常见字段,例如名字或电话号码。 您也可以尝试使用其他属性(例如标签和提示)来标识输入字段。

翻译自: https://code.tutsplus.com/tutorials/how-to-use-android-os-autofill-framework--cms-28811

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值