
示例工程教程【免費下載鏈接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_項目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus點擊查看免費下載導讀本文以 cw-omnibus 倉庫中的 AutoFill/AFClient/README.markdown 為核心剖析一個「配置了 Autofill 支持的 Activity」客戶端示例它如何在三個EditText上通過android:autofillHints標注用戶名、口令與信用卡號三類字段以及配套的AutoFillLogger服務端示例如何接收并記錄這些填充請求。讀完本文你將掌握 Android Autofill 框架的客戶端接入方式布局標注、表單提交、結果頁回顯理解服務端AutofillService的回調(diào)與SaveInfo配置并能在 API 26 設備上完整跑通「服務端日志 客戶端表單」的聯(lián)調(diào)鏈路。Autofill 框架回顧客戶端與服務端的分工Android 8.0API 26引入了系統(tǒng)級 Autofill 框架其參與者分為兩類客戶端Client即普通的 App例如本倉庫中的AFClient。客戶端不需要在AndroidManifest.xml中做任何 autofill 聲明也不需要持有AutofillManager的強引用——它只需要在View上標注android:autofillHintsautofill 提示剩下的「何時詢問、如何填充、何時保存」全部交由系統(tǒng)框架與用戶選擇的 autofill 服務完成。服務端Service即用戶通過「設置 → 系統(tǒng) → 語言與輸入法 → 高級 → 自動填充服務」選中的第三方服務例如本倉庫中的AutoFillLogger。它繼承android.service.autofill.AutofillService實現(xiàn)onFillRequest()與onSaveRequest()負責解析 AssistStructure、決定填充內(nèi)容與保存策略。AFClient與AutoFillLogger在 AutoFill/ 目錄下成對出現(xiàn)正好構成一次完整的 autofill 通信閉環(huán)AFClient 提供帶標注的表單AutoFillLogger 把每次填充請求的完整視圖結構記錄為 JSON 日志。AFClient 布局用 autofillHints 標注可填充視圖AFClient 的主界面定義在 activity_main.xml 中是一個典型的「用戶名 口令 信用卡號 保存按鈕」表單根布局為ConstraintLayout。與普通表單布局最大的差異是每個輸入框上的 autofill 標注EditText android:idid/username android:layout_width0dp android:layout_heightwrap_content android:autofillHintsusername android:ems10 android:inputTypetextPersonName android:hintstring/hint_username app:layout_constraintTop_toTopOfparent ... / EditText android:idid/passphrase android:layout_width0dp android:layout_heightwrap_content android:autofillHintspassword android:ems10 android:inputTypetextPassword android:hintstring/hint_passphrase app:layout_constraintTop_toBottomOfid/username ... / EditText android:idid/cc android:layout_width0dp android:layout_heightwrap_content android:autofillHintscreditCardNumber android:ems10 android:inputTypetextPersonName android:hintstring/hint_credit_card_number app:layout_constraintTop_toBottomOfid/passphrase ... / Button android:idid/save android:layout_widthwrap_content android:layout_heightwrap_content android:textstring/btn_save app:layout_constraintRight_toRightOfparent app:layout_constraintTop_toBottomOfid/cc /這里有幾個關鍵點android:autofillHints是 API 26 的View屬性可填任意字符串但只有與平臺標準 hint 匹配的值才會被AutofillManager與填充服務正確歸類。本例使用了三個標準值username、password、creditCardNumber。平臺的View類還定義了AUTOFILL_HINT_*常量族覆蓋電子郵件地址、電話號碼、郵編、收貨地址等常見類型使用標準值可讓任意合格的 autofill 服務包括系統(tǒng)內(nèi)置服務與第三方如 Google 服務都能正確識別字段語義。android:inputType是 autofill 之外的另一層語義標注username用textPersonName、passphrase用textPassword同時起到鍵盤掩碼作用。兩套屬性獨立存在inputType決定輸入法與文本顯示行為autofillHints決定 autofill 服務如何理解該字段。沒有為 EditText 設置importantForAutofill默認值auto下框架會根據(jù)autofillHints等條件自動決定該視圖是否參與 autofill本例全部字段都參與了。若想顯式禁用某個視圖的自動填充可在對應視圖上設android:importantForAutofillno。布局中出現(xiàn)的三個 hint 字符串username/password/creditCardNumber在 strings.xml 中分別對應hint_usernameUsername、hint_passphrasePassphrase、hint_credit_card_numberCredit card number即界面上顯示的占位提示文本與 autofill 標注語義一致。MainActivity收集表單數(shù)據(jù)并跳轉MainActivity.java 的onCreate()完成三件事綁定三個EditText、給「Save」按鈕掛點擊監(jiān)聽、在監(jiān)聽器中調(diào)用ResultActivity.login()final EditText username(EditText)findViewById(R.id.username); final EditText passphrase(EditText)findViewById(R.id.passphrase); final EditText cc(EditText)findViewById(R.id.cc); findViewById(R.id.save).setOnClickListener(new View.OnClickListener() { Override public void onClick(View view) { if (ResultActivity.login(MainActivity.this, username.getText().toString(), passphrase.getText().toString(), cc.getText().toString())) { finish(); } else { Toast.makeText(MainActivity.this, R.string.msg_invalid, Toast.LENGTH_LONG).show(); } } });流程很直接點擊 Save 后校驗口令實際邏輯在ResultActivity的靜態(tài)方法中通過則銷毀當前頁并進入結果頁否則用msg_invalidInvalid credentials, please try again提示用戶。注意這個示例沒有真正發(fā)起網(wǎng)絡請求——它的目的是演示 autofill 填充與數(shù)據(jù)流轉而不是做真實登錄。從 autofill 的角度看MainActivity本身沒有任何 autofill 相關代碼這正是客戶端接入模型的核心填充邏輯完全由系統(tǒng)框架與用戶選擇的填充服務接管App 只需要把視圖標注做好。ResultActivity展示“登錄”結果ResultActivity.java 同時承擔了兩件事校驗邏輯與結果回顯。靜態(tài)方法login()內(nèi)置了口令常量SEKRIT_PASSPHRASEpasswordprivate static final String SEKRIT_PASSPHRASEpassword; private static final String EXTRA_USERNAMEusername; private static final String EXTRA_CCcc; static boolean login(Context ctxt, String username, String passphrase, String cc) { if (passphrase.equals(SEKRIT_PASSPHRASE)) { Intent inew Intent(ctxt, ResultActivity.class) .putExtra(EXTRA_USERNAME, username) .putExtra(EXTRA_CC, cc); ctxt.startActivity(i); return(true); } return(false); }只有當用戶輸入的口令等于password時才跳轉否則返回false由 MainActivity 彈 Toast。ResultActivity.onCreate()從 Intent 中取出username與cc兩個 extra回顯到 activity_result.xml 中兩個TextViewid/username、id/cc上??诹畋旧聿粋鹘o結果頁只作為校驗憑據(jù)。AndroidManifest.xml中對兩個 Activity 的聲明同樣樸素MainActivity帶MAIN/LAUNCHER過濾器ResultActivity作為普通頁面——再次印證客戶端接入 autofill 無需任何 manifest 配置。autofillHints 與數(shù)據(jù)類型從服務端視角看字段語義要理解 AFClient 里三個 hint 的價值可以對照配套示例 AutoFillLoggerService.java 中的SaveInfo構造private static final int SAVE_DATA_ALLSaveInfo.SAVE_DATA_TYPE_GENERIC | SaveInfo.SAVE_DATA_TYPE_ADDRESS | SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD | SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS | SaveInfo.SAVE_DATA_TYPE_PASSWORD | SaveInfo.SAVE_DATA_TYPE_USERNAME;服務端把SaveInfo支持的全部六類數(shù)據(jù)通用、地址、信用卡、電子郵件、口令、用戶名用位或合并為SAVE_DATA_ALL表示「這些類型的字段都值得保存」。AFClient 的三個 hint 正好落入其中三類客戶端 autofillHints對應 SaveInfo 數(shù)據(jù)類型字段語義usernameSAVE_DATA_TYPE_USERNAME用戶名passwordSAVE_DATA_TYPE_PASSWORD口令creditCardNumberSAVE_DATA_TYPE_CREDIT_CARD信用卡號SaveInfo.Builder的構造參數(shù)new AutofillId[] { first }是「必需字段」其余通過setOptionalIds(ids.toArray(...))標記為可選ids集合來自collectViewIds()對 AssistStructure 的遞歸遍歷——凡是getAutofillHints()!null的視圖節(jié)點都會被收集private AutofillId collectViewIds(AssistStructure.ViewNode node, SetAutofillId ids) { AutofillId resultnull; if (node.getAutofillHints()!null node.getAutofillHints().length0) { resultnode.getAutofillId(); ids.add(result); } for (int i0; inode.getChildCount(); i) { AutofillId tempcollectViewIds(node.getChildAt(i), ids); if (resultnull) resulttemp; } return(result); }這從實現(xiàn)上驗證了autofillHints的語義hint 是客戶端向 autofill 框架暴露字段語義的唯一途徑服務端正是靠讀取這些 hint 來判斷「屏幕上哪些視圖值得填充/保存」。AFClient 標注的字段在 AutoFillLogger 的服務端日志里會被完整呈現(xiàn)。配套服務端 AutoFillLogger一個只記錄數(shù)據(jù)的 autofill 服務AutoFillLogger 展示了AutofillService的完整接線方式是理解 AFClient 如何被「服務」的關鍵參照。Manifest 聲明AndroidManifest.xml要求服務持有系統(tǒng)簽名權限android.permission.BIND_AUTOFILL綁定android.autofill元數(shù)據(jù)并聲明標準 intent filterservice android:name.AutoFillLoggerService android:permissionandroid.permission.BIND_AUTOFILL meta-data android:nameandroid.autofill android:resourcexml/autofill_service / intent-filter action android:nameandroid.service.autofill.AutofillService / /intent-filter /service服務配置文件autofill_service.xml通過settingsActivity指向一個 Activity供用戶在系統(tǒng)設置里點擊該服務時打開autofill-service xmlns:androidhttp://schemas.android.com/apk/res/android android:settingsActivitycom.commonsware.android.autofill.logger.MainActivity/兩個核心回調(diào)onFillRequest()遍歷request.getFillContexts()收集每個AssistStructure把帶 hint 的AutofillId匯總成SaveInfo與FillResponse隨后創(chuàng)建fill-*.json臨時文件交給 DumpThread 子線程把整個視圖結構序列化為 JSON。填充請求期間平臺會把當時界面的 AssistStructure包含所有帶 autofill 標注視圖的 id、hint、文本等交給服務端。onSaveRequest()當用戶完成表單交互、框架判定需要保存時回調(diào)AutoFillLogger 把SaveRequest與客戶端狀態(tài)同樣 dump 成save-*.json。JSON 寫入后通過MediaScannerConnection.scanFile()暴露給媒體庫日志落在getExternalCacheDir()下的autofilllogger_yyyyMMdd-HHmmss目錄方便開發(fā)者取回分析。此外MainActivityListActivity 子類在用戶點擊服務的設置入口時會檢查AutofillManagerAutofillManager afgetSystemService(AutofillManager.class); if (af.isAutofillSupported()) { if (af.hasEnabledAutofillServices()) { // 已啟用直接提示并退出 } else { Uri uriUri.parse(package:getPackageName()); Intent inew Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE, uri); startActivityForResult(i, REQUEST_ID); } } else { // 提示設備不支持 autofill }這演示了如何引導用戶啟用自己的 autofill 服務Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE會拉起系統(tǒng)設置里的「自動填充服務」選擇頁選中后以RESULT_OK返回。構建與運行設備要求與聯(lián)調(diào)步驟AFClient 的構建配置app/build.gradle與倉庫中其他 API 26 示例一致autofill 特性決定了其最低版本android { compileSdkVersion 26 buildToolsVersion 26.0.2 defaultConfig { applicationId com.commonsware.android.autofill.client minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName 1.0 } } dependencies { implementation com.android.support.constraint:constraint-layout:1.0.2 }minSdkVersion 26是硬性前提Autofill 框架AutofillManager、AutofillService、android:autofillHints從 Android 8.0 起才存在低于 API 26 的設備無法體驗AutoFillLogger 的 build.gradle 同樣minSdkVersion 26。依賴僅一個constraint-layoutautofill 本身是平臺 API無需額外引入 AndroidX 庫。推薦的聯(lián)調(diào)步驟在 API 26 模擬器或真機上分別安裝 AutoFillLogger 與 AFClient 兩個 App打開系統(tǒng)設置 → 自動填充服務選擇「AutoFill Logger Demo」期間會走一遍ACTION_REQUEST_SET_AUTOFILL_SERVICE引導流程啟動 AFClient聚焦「Username」輸入框——autofill 框架會向 AutoFillLogger 發(fā)起onFillRequest此時可在外部存儲的autofilllogger_*目錄看到fill-*.json日志內(nèi)含 AssistStructure 與各字段 hint填寫用戶名、口令需為password、信用卡號并點擊 SaveResultActivity回顯用戶名與卡號此階段框架觸發(fā)onSaveRequest生成save-*.json日志口令錯誤時 MainActivity 彈出 Invalid credentials, please try again不會跳轉——可借此觀察 autofill 保存流程與校驗邏輯的先后關系。小結AFClient 用最小化代碼回答了「客戶端如何支持 autofill」這個問題不需要 manifest 聲明、不需要 autofill 相關 Java 代碼只需在視圖上寫好android:autofillHints。字段語義通過標準 hint 值暴露給框架由系統(tǒng)與用戶選擇的填充服務完成讀取、回填與保存配合 AutoFillLogger 這樣只記錄數(shù)據(jù)的最小服務實現(xiàn)可以清晰觀察到onFillRequest/onSaveRequest兩條回調(diào)鏈路以及SaveInfo數(shù)據(jù)類型與客戶端 hint 之間的映射關系。對于需要自行接入 autofill 的開發(fā)者這套「客戶端標注 服務端日志」的組合是理解框架運行機制最直接的入門素材相關源碼均在 AutoFill/ 目錄下。贊分享示例工程教程【免費下載鏈接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_項目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus點擊查看免費下載相關推薦Android 顯式 Intent 跳轉實戰(zhàn)從 cw-omnibus Explicit 示例理解 Activity 間導航Android 顯式 Intent 跳轉實戰(zhàn)從 cw omnibus Explicit 示例理解 Activity 間導航 導讀 本文以 cw omnibus示例工程教程在低版本 Android 上實現(xiàn)淡入淡出動畫cw-omnibus 中 AnimatorFadeBC 示例與 NineOldAndroids 回移植剖析在低版本 Android 上實現(xiàn)淡入淡出動畫cw omnibus 中 AnimatorFadeBC 示例與 NineOldAndroids 回移植剖析 本篇技示例工程教程cw-omnibus AppWidget/Resize 示例解析構建支持自由調(diào)整尺寸的 Android 應用微件cw omnibus AppWidget/Resize 示例解析構建支持自由調(diào)整尺寸的 Android 應用微件 這篇技術指南以 cw omnibus 倉庫中示例工程教程上一篇Wand 2 小時免費時長限制本地補丁能永久去掉嗎下一篇老舊Mac煥新指南OpenCore-Legacy-Patcher EFI引導部署全流程創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考