Android 8.0 AutoFill自动填写框架实践

1.构建表单界面

TextInputEditText 添加 android:importantForAutofill="yes"

"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
                android:background="@color/white">
​
    "match_parent"
        android:layout_height="wrap_content">
​
        "@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Username"
            android:importantForAutofill="yes"/>
    "match_parent"
        android:layout_height="wrap_content">
​
        "@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Password"
            android:importantForAutofill="yes"
            android:selectAllOnFocus="false"
            android:singleLine="true"/>
    "@+id/login"
        style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Login"/>
​
复制代码

2.处理表单

使用SharedPreferences将用户信息储存

package com.iwakeup.learnandroid.Fragment;
​
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
​
import com.google.android.material.button.MaterialButton;
import com.iwakeup.learnandroid.R;
import com.iwakeup.learnandroid.impl.BaseFragment;
​
import androidx.fragment.app.Fragment;
​
public class AutoFilFragment extends Fragment implements BaseFragment {
​
    EditText username,password;
    MaterialButton login;
​
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.fragment_autofill,container,false);
        initView(view);
        return view;
    }
​
    @Override
    public void initView(View view) {
        username=view.findViewById(R.id.username);
        password=view.findViewById(R.id.password);
        login=view.findViewById(R.id.login);
        login.setOnClickListener(loginC);
    }
​
    View.OnClickListener loginC =new View.OnClickListener() {
        @Override
        public void onClick(View view) {
​
            SharedPreferences sp=getActivity().getSharedPreferences("user",Context.MODE_PRIVATE);
            SharedPreferences.Editor editor=sp.edit();
            editor.putString("username",username.getText().toString());
            editor.putString("password",password.getText().toString());
            editor.apply();
            
        }
    };
​
​
}
​复制代码

3.构建AutoFillService

重写 onFillRequest()onSaveRequest

​
public class MyAutoFillService extends AutofillService {
    List viewNodeList;
    
    @Override
    public void onFillRequest(FillRequest fillRequest, CancellationSignal cancellationSignal, FillCallback fillCallback) {
        List context = fillRequest.getFillContexts();
        AssistStructure structure = context.get(context.size() - 1).getStructure();
​
        viewNodeList = new ArrayList<>();
​
        traverseStructure(structure,viewNodeList);
​
        SharedPreferences sharedPreferences=getSharedPreferences("user",MODE_PRIVATE);
        String  spusername=sharedPreferences.getString("username",null);
        String  sppassword=sharedPreferences.getString("password",null);
​
​
        //加载自动填充的布局,可更换为自定义View
        RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
        usernamePresentation.setTextViewText(android.R.id.text1, spusername);
        RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
        passwordPresentation.setTextViewText(android.R.id.text1, sppassword);
​
​
        ParsedStructure parsedStructure=new ParsedStructure();
        parsedStructure.setUsernameId(viewNodeList.get(0).getAutofillId());
        parsedStructure.setPasswordId(viewNodeList.get(1).getAutofillId());
        
        //构建填充的数据
       FillResponse fillResponse = new FillResponse.Builder()
                    .addDataset(new Dataset.Builder()
                            .setValue(ParsedStructure.usernameId,
                                    AutofillValue.forText(spusername), usernamePresentation)
                            .setValue(ParsedStructure.passwordId,
                                    AutofillValue.forText(sppassword), passwordPresentation)
                            .build())
                    .build();
            fillCallback.onSuccess(fillResponse);
​
​
    }
​
    @Override
    public void onSaveRequest(SaveRequest saveRequest, SaveCallback saveCallback) {
​
        // Get the structure from the request
        List context = saveRequest.getFillContexts();
        AssistStructure structure = context.get(context.size() - 1).getStructure();
​
        // Traverse the structure looking for data to save
        traverseStructure(structure, viewNodeList);
​
        // Persist the data, if there are no errors, call onSuccess()
        saveCallback.onSuccess();
​
    }
​
​
    public void traverseStructure(AssistStructure structure, List viewNodeList) {
        int nodes = structure.getWindowNodeCount();
​
        for (int i = 0; i < nodes; i++) {
            AssistStructure.WindowNode windowNode = structure.getWindowNodeAt(i);
            AssistStructure.ViewNode viewNode = windowNode.getRootViewNode();
            traverseNode(viewNode,viewNodeList);
        }
    }
​
    public void traverseNode(AssistStructure.ViewNode viewNode, List viewNodeList) {
        if(viewNode.getAutofillHints() != null && viewNode.getAutofillHints().length > 0) {
            // If the client app provides autofill hints, you can obtain them using:
            // viewNode.getAutofillHints();
            return;
        } else {
            // Or use your own heuristics to describe the contents of a view
            // using methods such as getText() or getHint().
           
            //遍历EditText布局
            if (viewNode.getClassName().contains("EditText")) {
                String viewId = viewNode.getIdEntry();
                if (viewId != null && (viewId.contains("username") || viewId.contains("username") || viewId.contains("password"))) {
                   
                    //添加到list
                    viewNodeList.add(viewNode);
                 
                    return;
                }
            }
​
​
        }
​
        for(int i = 0; i < viewNode.getChildCount(); i++) {
            AssistStructure.ViewNode childNode = viewNode.getChildAt(i);
            traverseNode(childNode, viewNodeList);
        }
    }
​
    static class ParsedStructure {
          static AutofillId usernameId;
          static AutofillId passwordId;
​
        public  AutofillId getPasswordId() {
            return passwordId;
        }
​
        public  void setPasswordId(AutofillId passwordId) {
            ParsedStructure.passwordId = passwordId;
        }
​
        public AutofillId getUsernameId() {
             return usernameId;
         }
​
         public void setUsernameId(AutofillId usernameId) {
             this.usernameId = usernameId;
         }
     }
​复制代码

4.清单声明和权限

".MyAutofillService"
    android:label="My Autofill Service"
    android:permission="android.permission.BIND_AUTOFILL_SERVICE">
    
        "android.service.autofill.AutofillService" />
    
    "android.autofill"
        android:resource="@xml/service_configuration" />
复制代码
"http://schemas.android.com/apk/res/android"
  android:settingsActivity="com.example.android.SettingsActivity" />复制代码

5.在设备上启用该服务

最后手机中设置一下:设置 > 系统 > 语言和输入 > 高级 > 输入帮助 > 自动填充服务>复制代码


你可能感兴趣的:(Android 8.0 AutoFill自动填写框架实践)