Android Oreo:我应该怎么做才能将我的应用程序发布为自动填充服务提供商?

Android Oreo: what should I do to publish my app as an Autofill service provider?

我是密码管理器应用程序的独立开发者。我应该怎么做,或者我应该实施什么 (interface/API/Service),使我的应用程序成为自动填充服务提供商(在 Android Oreo API >= 26 的设备中)?

我看了各种相关的文档,但是就是看不懂怎么操作。我错过了什么吗?

目前我看到只有知名的密码管理器支持此功能:

欢迎任何提示。

像往常一样,Google 自己的 examples repository provides a good starting point for learning the Autofill Framework's API, and covers much more material than I can fit into an answer. Here's an overview of the key concepts. From the description in the documentation,我们想要创建一个自动填充 服务 来处理来自其他应用程序(客户端)的请求存储和检索自动填充字段数据。

首先,我们需要创建一个服务提供者class来履行这个契约。我们可以扩展基础AutofillService class

import android.service.autofill.AutofillService;
...
public class MyAutofillService extends AutofillService {
    ...
    @Override
    public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
        FillCallback callback) { ... }

    @Override
    public void onSaveRequest(SaveRequest request, SaveCallback callback) { ... }
}

服务的 onFillRequest() and onSaveRequest() methods are the most significant for our understanding. The Android system calls onFillRequest() to determine if our service can autofill fields for a particular activity, and gives the method a FillRequest,其中包含我们的服务将检查可填写字段的上下文和视图信息。服务完成后,它会使用适当的自动填充数据调用提供的 callback

这里非常简要概述了为 FillRequest 提供自动填充建议所需的基本步骤:

@Override
public void onFillRequest(FillRequest request, CancellationSignal signal, FillCallback callback) {
    List<FillContext> contexts = request.getFillContexts();
    AssistStructure structure = contexts.get(contexts.size() - 1);
    WindowNode windowNode = structure.getWindowNodeAt(0);
    ViewNode viewNode = windowNode.getRootViewNode(); // pretend this is an EditText

    String suggestionText = "This will appear in the autofill list for 'viewNode'.";
    RemoteViews suggestion = new RemoteViews(getPackageName(), R.layout.autofill_suggestion);
    suggestion.setTextViewText(R.id.autofill_suggestion, suggestionText);

    Dataset suggestionDataset = new Dataset.Builder(suggestion) 
        .setValue(viewNode.getAutoFillId(), AutofillValue.forText(suggestionText))
        .build();

    FillResponse response = new FillResponse.Builder() 
        .addDataset(suggestionDataset)
        .build();

    callback.onSuccess(response);
}

正如我们所见,自动填充 API 需要大量代码才能为我们预先知道的 View 提供单个静态自动填充建议——该示例假设 viewNode 是我们要为其提供自动填充建议的文本输入字段。实际上,这个例子太简单了,但我想清楚地展示最小实现。对于每个 WindowNode,我们需要遍历根 ViewNode and each of its children to find each of the input fields that our service wishes to provide autofill data for, and then create a RemoteViews and Dataset that contains the autofill suggestion for each field that we'll add to the FillResponse using FillResponse.Builder.addDataset() 的视图树。此示例未显示用于为 RemoteViews 创建建议显示项的 R.layout.autofill_suggestion TextView 的纯 XML 布局。

类似地,当用户想要将数据保存在 activity 的字段中以供将来完成请求时,Android 调用 onSaveRequest() 并注入我们的 SaveRequest服务用于查找要记住的自动填充数据。

每个方法的具体实现将取决于我们的应用程序提供的自动填充数据的类型。自动填充服务必须认真检查每个字段的特征并仔细select一套适当的自动填充建议,以避免将用户的数据泄露给恶意客户端 activity(见评论)。特别是对于密码管理器,我们需要特别注意正确验证服务的用户并在请求和保存自动填充数据时提供一组安全的建议。

我们现在可以 register the service 在项目 AndroidManifest.xml<application> 块中:

<service
    android:name=".MyAutofillService"
    android:label="Multi-Dataset Autofill Service"
    android:permission="android.permission.BIND_AUTOFILL_SERVICE">
    <meta-data
        android:name="android.autofill"
        android:resource="@xml/multidataset_service" />

    <intent-filter>
        <action android:name="android.service.autofill.AutofillService" />
    </intent-filter>
</service>

如图所示,这将我们的自动填充服务绑定为出现在问题中显示的自动填充服务列表中的可用选项。 android:name 属性必须与我们的 AutofillService class 的名称匹配,并且我们的应用程序必须声明 BIND_AUTOFILL_SERVICE 权限。将 android:label 的值更改为适合该服务的名称(例如,"Autofill with Password Manager")。或者,在字符串资源中设置它。另请注意,我们应该提供一个 "settings" activity 用于配置我们在 <meta‑data> 中为 android.autofill 指定的服务:

<autofill-service android:settingsActivity="foo.bar.SettingsActivity" />

然后,用户可以从他们的设备设置中启用我们的自动填充服务。我们可以在设置或首次启动期间广播 ACTION_REQUEST_SET_AUTOFILL_SERVICE 意图,以帮助用户找到此屏幕。