輔助功能是Android系統提供的一種服務,派生自Service類。這個服務提供了增強的用戶界面,目的是為了幫助殘障人士。它一般提供了頁面元素查找功能和元素點擊功能。
通過輔助功能,開發者可以實現一些非常豐富的功能:
搶紅包
微信自動回復
檢查微信好友
進程清理
判斷應用當前狀態
防卸載
瀏覽器劫持
跳過用戶授權
關於更多AccessibilityService的安全信息可以查看這篇文章:
https://www.freebuf.com/articles/terminal/114045.html
AccessibilityService(輔助功能類)派生自Service,它是一個服務類。AccessibilityService是一個抽象類,所以要使用輔助功能的話,就要從AccessibilityService類派生一個實例類,完成配置、監聽,再根據監聽到的元素完成各種動作。
例如,下面這個案例:
MainActivity.java

import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import com.example.accessibilityservicetest.R; public class MainActivity extends Activity { private static String TAG="test"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //如果沒開啟,就提醒開啟輔助功能 if(!isAccessibilitySettingsOn(this)){ Intent intent=new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS); startActivity(intent); } } //判斷是否開啟輔助功能 private boolean isAccessibilitySettingsOn(Context mContext) { int accessibilityEnabled = 0; final String service = getPackageName() + "/" + MyCustomAccessibilityService.class.getCanonicalName(); try { accessibilityEnabled = Settings.Secure.getInt( mContext.getApplicationContext().getContentResolver(), android.provider.Settings.Secure.ACCESSIBILITY_ENABLED); Log.v(TAG, "accessibilityEnabled = " + accessibilityEnabled); } catch (Settings.SettingNotFoundException e) { Log.e(TAG, "Error finding setting, default accessibility to not found: " + e.getMessage()); } TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':'); if (accessibilityEnabled == 1) { Log.v(TAG, "***ACCESSIBILITY IS ENABLED*** -----------------"); String settingValue = Settings.Secure.getString( mContext.getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); if (settingValue != null) { mStringColonSplitter.setString(settingValue); while (mStringColonSplitter.hasNext()) { String accessibilityService = mStringColonSplitter.next(); Log.v(TAG, "-------------- > accessibilityService :: " + accessibilityService + " " + service); if (accessibilityService.equalsIgnoreCase(service)) { Log.v(TAG, "We've found the correct setting - accessibility is switched on!"); return true; } } } } else { Log.v(TAG, "***ACCESSIBILITY IS DISABLED***"); } return false; } }
MyCustomAccessibilityService.java

public class MyCustomAccessibilityService extends AccessibilityService { //該方法在初始化輔助功能時調用 @Override protected void onServiceConnected() { super.onServiceConnected(); } //獲取到指定的監聽事件 @Override public void onAccessibilityEvent(AccessibilityEvent event) { //輔助功能的時間類型 int eventType=event.getEventType(); //輸出事件的字符串type String typeStr=event.eventTypeToString(eventType); //根據事件類型來分發我們需要的操作,這里以窗口變化為例 if(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED==eventType){ //判斷我們的輔助功能,是否在約定的界面執行,以設置界面為例 if("com.android.settings".equals(event.getPackageName())){ //doSometing } }else if(AccessibilityEvent.TYPE_GESTURE_DETECTION_START==eventType){ }else{ //在完成自己的操作時候,可以關閉自己的服務,下次使用再開啟 //API>=24 //disableSelf() } //通過event遍歷nodeInfo AccessibilityNodeInfo info= event.getSource(); //findFocus(int) //getWindows() //getRootInActiveWindow() //遍歷節點 for(int i=0;i<info.getChildCount();i++){ AccessibilityNodeInfo childNode= info.getChild(i); //獲取子節點中的某個特定node,一下通過id查找 List<AccessibilityNodeInfo> list = childNode.findAccessibilityNodeInfosByViewId("com.android" +".settings:id/xxxx"); // 通過text查找 //List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByText("xxxx"); Log.i("InfoType",childNode.getClassName().toString()); Log.i("InfoText", childNode.getText().toString()); Log.i("InfoPkgName",childNode.getPackageName().toString()); Log.i("InfoViewId", childNode.getViewIdResourceName()); //進行點擊操作 for(AccessibilityNodeInfo anodeinfo : list){ if(anodeinfo.isClickable()){ anodeinfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } } //輔助功能被中斷時候調用該方法 @Override public void onInterrupt() { } }
acessibilityserviceconfig.xml

<?xml version="1.0" encoding="utf-8"?> <accessibility-service android:description="@string/accessibility_description" android:accessibilityEventTypes="typeAllMask" android:packageNames="com.example.accessibilityservicetest,com.android.settings" android:accessibilityFeedbackType="feedbackGeneric" android:notificationTimeout="100" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" xmlns:android="http://schemas.android.com/apk/res/android"/>
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.accessibilityservicetest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.accessibilityservicetest.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="com.example.accessibilityservicetest.MyCustomAccessibilityService" android:label="@string/app_name" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService"/> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/acessibilityserviceconfig"/> </service> </application> </manifest>
上面的acessibilityserviceconfig.xml文件是關於這次輔助功能的配置信息,在下面做出如下說明:
AccessibilityEventTypes 此服務希望接收的事件類型
constant value 描述
typeAllMask ffffffff 所有類型的事件
typeAnnouncement 4000 一個應用產生一個通知事件
typeAssistReadingContext 1000000 輔助用戶讀取當前屏幕事件
typeContextClicked 800000 view中上下文點擊事件
typeGestureDetectionEnd 80000 監測到的手勢事件完成
typeGestureDetectionStart 40000 開始手勢監測事件
typeNotificationStateChanged 40 收到notification彈出消息事件
typeTouchExplorationGestureEnd 400 觸摸瀏覽事件完成
typeTouchExplorationGestureStart 200 觸摸瀏覽事件開始
typeTouchInteractionEnd 200000 用戶觸屏事件結束
typeTouchInteractionStart 100000 觸摸屏幕事件開始
typeViewAccessibilityFocusCleared 10000 無障礙焦點事件清除
typeViewAccessibilityFocused 8000 獲得無障礙的焦點事件
typeViewClicked 1 點擊事件
typeViewFocused 8 view獲取到焦點事件
typeViewHoverEnter 80 一個view的懸停事件
typeViewHoverExit 100 一個view的懸停事件結束,懸停離開該view
typeViewLongClicked 2 view的長按事件
typeViewScrolled 1000 view的滾動事件,adapterview、scrollview
typeViewSelected 4 view選中,一般是具有選中屬性的view,例如adapter
typeViewTextChanged 10 edittext中文字發生改變的事件
typeViewTextSelectionChanged 2000 edittext文字選中發生改變事件
typeViewTextTraversedAtMovementGranularity 20000 UIanimator中在一個視圖文本中進行遍歷會產生這個事件,多個粒度遍歷文本。一般用於語音閱讀context
typeWindowContentChanged 800 窗口的內容發生變化,或者更具體的子樹根布局變化事件
typeWindowStateChanged 20 新的彈出層導致的窗口變化(dialog、menu、popupwindow)
typeWindowsChanged 400000 屏幕上的窗口變化事件,需要API 21+
accessibilityFeedbackType 此服務提供的反饋類型
constant value 描述
feedbackAllMask ffffffff 取消所有的可用反饋方式
feedbackAudible 4 可聽見的(非語音反饋)
feedbackGeneric 10 通用反饋
feedbackHaptic 2 觸覺反饋(震動)
feedbackSpoken 1 語音反饋
feedbackVisual 8 視覺反饋
accessibilityFlags 輔助功能附加的標志,多個使用 ' | '分隔
constant value 描述
flagDefault 1 默認的配置
flagEnableAccessibilityVolume 80 這個標志要求系統內所有的音頻通道,使用由STREAM_ACCESSIBILTY音量控制USAGE_ASSISTANCE_ACCESSIBILITY
flagIncludeNotImportantViews 2 表示可獲取到一些被表示為輔助功能無權獲取到的view
flagReportViewIds 10 使用該flag表示可獲取到view的ID
flagRequestAccessibilityButton 100 如果輔助功能可用,提供一個輔助功能按鈕在系統的導航欄 API 26+
flagRequestEnhancedWebAccessibility 8 此類擴展的目的是為WebView中呈現的內容提供更好的輔助功能支持。這種擴展的一個例子是從一個安全的來源注入JavaScript。如果至少有一個具有此標志的輔助功能服務, 則系統將使能增強的web輔助功能。因此, 清除此標志並不保證該設備不會使能增強的web輔助功能, 因為可能有另一個使能的服務在使用它。
flagRequestFilterKeyEvents 20 能夠監聽到系統的物理按鍵
flagRequestFingerprintGestures 200 監聽系統的指紋手勢 API 26+
flagRequestTouchExplorationMode 4 系統進入觸控探索模式。出現一個鼠標在用戶的界面
flagRetrieveInteractiveWindows 40 該標志知識的輔助服務要訪問所有交互式窗口內容的系統,這個標志沒有被設置時,服務不會收到TYPE_WINDOWS_CHANGE事件。
canRequestEnhancedWebAccessibility(boolean)
輔助功能服務是否能夠請求WEB輔助增強的屬性。例如: 安裝腳本以使應用程序內容更易於訪問。
canRequestFilterKeyEvents(boolean)
輔助功能服務是否能夠請求過濾KeyEvent的屬性,是否可以請求KeyEvent事件流。flagRequestFilterKeyEvents搭配使用
canRequestTouchExplorationMode (boolean)
此屬性用於,能夠讓輔助功能服務通過手勢,來請求觸摸瀏覽模式,其被觸摸的項,將被朗讀出來,flagRequestTouchExplorationMode搭配使用
canRetrieveWindowContent (boolean)
輔助功能服務是否能夠取回活動窗口內容的屬性。 與上邊的flagRetrieveInteractiveWindows搭配使用,無法在運行時更改此設置。
description
輔助功能服務目的或行為的簡短描述。
notificationTimeout
同一類型的兩個輔助功能事件發送到服務的最短間隔(毫秒,兩個輔助功能事件之間的最小周期)
packageNames
從此服務能接收到事件的軟件包名稱 (不適合所有軟件包)(多個軟件包用逗號分隔)。
settingsActivity
允許用戶修改輔助功能的activity組件名稱
summary
同description
可以通過DDMS來查看手機界面的節點元素的各種信息: