最近開(kāi)發(fā)用到了輔助功能,趕緊整理下來(lái)卸奉。先介紹一下Accessibility:
對(duì)于那些由于視力慰毅、聽(tīng)力或其它身體原因?qū)е虏荒芊奖闶褂肁ndroid智能手機(jī)的用戶德撬,Android提供了Accessibility功能和服務(wù)幫助這些用戶更加簡(jiǎn)單地操作設(shè)備,包括文字轉(zhuǎn)語(yǔ)音固歪、觸覺(jué)反饋蒜鸡、手勢(shì)操作胯努、軌跡球和手柄操作。開(kāi)發(fā)者可以搭建自己的Accessibility服務(wù)逢防,這可以加強(qiáng)可用性叶沛,例如聲音提示,物理反饋忘朝,和其他可選的操作模式灰署。
隨著Android版本的不斷升級(jí),Android Accessibility功能也越來(lái)越強(qiáng)大局嘁,Android 4.0版本以前溉箕,系統(tǒng)輔助服務(wù)功能比較單一,僅僅能過(guò)單向獲取窗口元素信息悦昵,比如獲取輸入框用戶輸入內(nèi)容肴茄。到Android 4.1版本以后,系統(tǒng)輔助服務(wù)增加了與窗口元素的雙向交互但指,此時(shí)可以通過(guò)輔助功能服務(wù)操作窗口元素寡痰,比如點(diǎn)擊按鈕等。
由于系統(tǒng)輔助服務(wù)能夠?qū)崟r(shí)獲取您當(dāng)前操作應(yīng)用的窗口元素信息棋凳,這有可能給你帶來(lái)隱私信息的泄露風(fēng)險(xiǎn)拦坠,比如獲取非密碼輸入框的輸入內(nèi)容等。同時(shí)通過(guò)輔助功能也可以模擬用戶自動(dòng)化點(diǎn)擊應(yīng)用內(nèi)元素剩岳,也會(huì)帶來(lái)一定的安全風(fēng)險(xiǎn)贞滨。
下面來(lái)實(shí)際操作一下(AndroidStudio)
1.在res文件下創(chuàng)建一個(gè)xml文件夾,在文件夾下創(chuàng)建一個(gè)phone_accessibilit.xml:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service android:description="@string/accessibility_service_description"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="100"
android:accessibilityFlags=""
android:canRetrieveWindowContent="true"
xmlns:android="http://schemas.android.com/apk/res/android" />
文件中定義了一些關(guān)于輔助功能服務(wù)的相關(guān)屬性
2.創(chuàng)建MyAccessibilityService
同時(shí)在manifest文件中填寫(xiě)service的相關(guān)信息卢肃。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyAccessibilityService"
android:label="@string/acc_service_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/phone_accessibility" />
</service>
</application>
MyAccessibilityService:
public class MyAccessibilityService extends AccessibilityService {
private static int ACTION_STEP = 0;
@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
try {
processAccessibilityEnvent(accessibilityEvent);
} catch (Exception e) {
e.printStackTrace();
}
}
public void processAccessibilityEnvent(AccessibilityEvent event) {
if (event.getSource() == null) {
Log.d("accessibility", "null");
return; //如果event沒(méi)有內(nèi)容,直接返回.
}
Log.d("accessibility", event.getPackageName().toString());
if (event.getPackageName().equals("com.mrtian.example.accessibilitytest")) { //通過(guò)包名,分別處理
//查找對(duì)應(yīng)id的View結(jié)點(diǎn)
List<AccessibilityNodeInfo> nodes = event.getSource().findAccessibilityNodeInfosByViewId("com.mrtian.example.accessibilitytest:id/button_01");
if (nodes != null && !nodes.isEmpty()) {
Log.d("accessibility", "button1 :" + "click");
AccessibilityNodeInfo node1;
for (int i = 0; i < nodes.size(); i++) {
node1 = nodes.get(i);
if (node1.getClassName().equals("android.widget.Button") && node1.isEnabled()) {
//如果發(fā)現(xiàn)該結(jié)點(diǎn),做一個(gè)點(diǎn)擊操作
node1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
//通過(guò)id查找結(jié)點(diǎn)
List<AccessibilityNodeInfo> list = event.getSource().findAccessibilityNodeInfosByViewId("com.qihoo.appstore:id/search_list_view");
if (list != null && !list.isEmpty()) {
//做一個(gè)下拉操作
list.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
//做一個(gè)下拉通知欄的操作
//this.performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
}
}
@Override
public void onInterrupt() {
}
}
為了給出思路疲迂,我做了一個(gè)簡(jiǎn)單的演示,不停點(diǎn)擊界面中的一個(gè)button莫湘。button的數(shù)字不停增加。
開(kāi)啟輔助功能后郑气,程序就會(huì)不斷回調(diào)onAccessibilityEvent函數(shù)幅垮,參數(shù)AccessibilityEvent accessibilityEvent,accessibilityEvent.getSource可以得到整個(gè)頁(yè)面的信息尾组。
通過(guò)event.getPackageName()得到應(yīng)用程序的包名忙芒,可以判斷包名做出不同的操作。
event.getSource().findAccessibilityNodeInfosByViewId/ByText可以通過(guò)文本或者id找到相應(yīng)的控件結(jié)點(diǎn)讳侨,拿到結(jié)點(diǎn)以后就可以做一些操作呵萨,比如點(diǎn)擊、下拉跨跨、觸摸...返回值是一個(gè)AccessibilityNodeInfo的list潮峦,AccessibilityNodeInfo是結(jié)點(diǎn)信息囱皿,對(duì)應(yīng)方法getParent,getChildren可以得到父子結(jié)點(diǎn)。
有了這個(gè)就可以做很多事情忱嘹,建議:
1.可以設(shè)置一個(gè)靜態(tài)變量來(lái)控制操作的步驟嘱腥。
2.利用DDMS可以查看當(dāng)當(dāng)前布局樹(shù),可以查看每個(gè)結(jié)點(diǎn)的id拘悦、Text齿兔、clickable等屬性。
3.利用Handler的postDelayed來(lái)做一些延時(shí)操作础米。