AccessibilityService

AccessibilityService從入門到出軌html

AccessibilityService根據官方的介紹,是指開發者經過增長相似contentDescription的屬性,從而在不修改代碼的狀況下,讓殘障人士可以得到使用體驗的優化,你們能夠打開AccessibilityService來試一下,點擊區域,能夠有語音或者觸摸的提示,幫助殘障人士使用App。node

固然,如今AccessibilityService已經基本偏離了它設計的初衷,至少在國內是這樣,愈來愈多的App借用AccessibilityService來實現了一些其它功能,甚至是灰色產品。android

使用入門git

老規矩,官網鎮樓
https://developer.android.com...
https://developer.android.com...程序員

要使用AccessibilityService實際上很是簡單,通常來講,只須要如下三步便可。github

繼承系統AccessibilityServiceshell

public class MyAccessibility extends AccessibilityService {數據庫

private static final String TAG = "xys";

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    Log.d(TAG, "onAccessibilityEvent: " + event.toString());
}

@Override
public void onInterrupt() {
}

}
其中有兩個必須實現的方法:onAccessibilityEvent和onInterrupt。瀏覽器

在onAccessibilityEvent中,咱們能夠接收所監聽的事件。不熟悉這些事件的話,只須要使用toString把這些信息打出來,本身多看幾個Log,就大概可以瞭解了。安全

新建配置文件

在資源目錄res下新建xml文件夾,新建accessibility.xml文件,寫入:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"

android:accessibilityEventTypes="typeAllMask"
                   android:accessibilityFeedbackType="feedbackSpoken"
                   android:canRetrieveWindowContent="true"
                   android:notificationTimeout="1000"/>

裏面有一些比較簡單的配置。

其中 description 爲 用戶容許應用的輔助功能的說明字符串,這裏沒有指定所要輔助的應用packageNames,當沒有指定時,默認輔助全部的應用,建議你們在使用時,指定須要監聽的包名(你能夠經過|來進行分隔),而不是全部的包名。typeAllMask是設置響應事件的類型,feedbackGeneric是設置回饋給用戶的方式,有語音播出和振動。

註冊

在AndroidMainifest中註冊:

<service

android:name=".MyAccessibility"
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/accessibility"/>

</service>
完成以上步驟後,一個AccessibilityService就可使用了,你要知道的是,AccessibilityService具備很高的系統權限,因此,系統不會讓App直接設置是否啓用,須要用戶進入設置-輔助功能中去手動啓用,這樣在必定程度上,保護了用戶數據的安全。

如何理解AccessibilityService

不少人可能對AccessibilityService瞭解的不是很深刻,因此認爲AccessibilityService是在調用一些系統服務來自動執行一些操做,實際上,這個理解不能算錯,固然也不全對,我以爲你能夠把AccessibilityService理解爲——『按鍵精靈』。相信不少開發者都玩過PC上的這款軟件,他的做用,就是將你一次操做的整個記錄,錄製下來,而後就能夠根據這個記錄,重複的執行這些操做,例如:先點擊某個輸入框,再輸入XXXX,再輸入驗證碼,最後點擊某按鈕,這些操做若是須要重複執行,那麼顯然是一套機械的步驟,那麼經過按鍵精靈,記錄下這些操做後,直接經過腳本就能夠完成這些操做。其實AccessibilityService跟這個是同樣的,咱們記錄的,實際上就是咱們的操做步驟,或者稱之爲『腳本』,那麼系統在監控整個手機的各類AccessibilityService事件時,就會根據咱們的邏輯來判斷該使用哪個腳本。

所以,咱們徹底能夠抽象出一個基類AccessibilityService,並抽象出一些腳本的事件,例如,根據Text查找對應的View、點擊某個View、滑動、返回等等,因此,我在這裏封裝了一個BaseAccessibilityService,這裏就不貼具體的代碼了,你們能夠參考個人Github:

https://github.com/xuyisheng/...

入門

不知道從何時開始,AccessibilityService忽然從一個殘障人士使用的輔助服務,一躍變成了各類App的黑科技,利用AccessibilityService來作的事情,也愈來愈偏離了AccessibilityService設計的初衷,各類安全問題也隨之暴露出來,Google的理想是好的,願天下都是安分守己的程序員。

免Root自動安裝

這個也許是能考證的最先利用AccessibilityService的使用場景了,最先在一些應用市場中出現,例如用戶一次下載了不少App,那麼每一個App下載完畢後都會彈出安裝界面,並且須要用戶手動去處理,確實體驗不太好,因此後來就出現了利用Root權限來靜默安裝App的功能,但如今普通用戶Root的需求愈來愈少,因此,AccessibilityService來實現免Root自動安裝的黑科技,才走上了桌面。

那麼按照咱們前面的思路,要實現自動安裝,實際上就是把手動安裝的步驟腳本化。通常來講,咱們要安裝一個App,會經過如下幾個步驟:

調用系統的安裝Intent
在安裝界面上尋找『安裝』、『下一步』這些操做按鈕
點擊『安裝』、『下一步』按鈕
完成安裝
那麼這些流程化的操做,咱們就徹底能夠經過腳原本實現,下面就是一些簡單的代碼實現。

調用系統安裝Intent:

public void autoInstall(View view) {

String apkPath = Environment.getExternalStorageDirectory() + "/test.apk";
Uri uri = Uri.fromFile(new File(apkPath));
Intent localIntent = new Intent(Intent.ACTION_VIEW);
localIntent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(localIntent);

}
監控安裝界面,並根據邏輯處理點擊:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

super.onAccessibilityEvent(event);
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
        event.getPackageName().equals("com.android.packageinstaller")) {
    AccessibilityNodeInfo nodeInfo = findViewByText("安裝", true);
    if (nodeInfo != null) {
        performViewClick(nodeInfo);
    }
}

}
代碼寫完才發現,看似很牛逼的自動安裝,其實不過十幾行代碼。惟一複雜的,就是抽象化這些流程了。

搶紅包

搶紅包應該是AccessibilityService火起來的最大因素。網上藉助AccessibilityService來實現的搶紅包插件也是數不勝數,又是一個看上去很牛逼的功能。那麼咱們再來分析下,你是怎麼搶紅包的。

加入你如今在桌面,怎麼知道有紅包了呢?哦,看通知欄,出現了『微信紅包』這幾個關鍵字,而後,你點擊這條通知進去,點擊紅包的那條消息,而後再點擊拆紅包的按鈕,返回,回到桌面。

這樣一看,搶紅包徹底是一個體力活啊,若是有個機器人能幫助我完成上面的動做,根本不用我搶啊,對的,這個機器人就是AccessibilityService,咱們一樣把搶紅包流程化。

獲取通知欄通知事件
點擊通知欄消息
找到紅包消息
點擊
點擊拆紅包
返回
這每一個步驟,也都不難啊,咱們的工具類中,全部的方法都實現了,惟一要作的,就是寫幾個ifelse把邏輯拼起來就好了,具體代碼就不貼了,畢竟是微信嚴打的一件事,你們適可而止就行了。

固然,這個Demo一樣能夠作的更完善一點,例如,增長WakeLock和Keyguard,實如今鎖屏狀況下的自動搶紅包等功能。

微信自動回覆

在瞭解了微信搶紅包的方式以後,再看看微信自動回覆,是否是就更是小菜一碟了?咱們只要把搶紅包的流程稍微改一下,就完成了整個功能的實現,不相信?

獲取通知欄通知事件
點擊通知欄消息
找到紅包消息 ——> 輸入自動回覆的消息
點擊 ——> 點擊發送
點擊拆紅包 ——> 不須要了
返回
是否是很是簡單?惟一一個有價值的代碼以下:

private void notifyWechat(AccessibilityEvent event) {

if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
    Notification notification = (Notification) event.getParcelableData();
    String content = notification.tickerText.toString();
    String[] msg = content.split(":");
    name = msg[0].trim();
    text = msg[1].trim();
    PendingIntent pendingIntent = notification.contentIntent;
    try {
        pendingIntent.send();
    } catch (PendingIntent.CanceledException e) {
        e.printStackTrace();
    }
}

}
一個簡單的Trick而已,借用notification.contentIntent來喚起Notification對應的App。

實際上,咱們能作的事情還有不少,當咱們拿到對應的聊天信息時,能夠經過聊天對象的篩選,來實現對『特別對象的監控』,例如你離開的時候,能夠設置給你的老婆自動回覆『親愛的我在忙呢,等等哈』,而對其它人自動回覆『滾,LZ忙』。再例如,能夠對聊天信息進行分詞、識別,從而實現對內容的精準回覆,固然,這裏還須要使用到一些第三方的語言分析軟解,這裏就不詳解了,總之,沒有想不到。

檢查微信好友

那麼再好比去年比較火的一個方法,經過拉好友進羣組來檢查是否還有好友關係。PC、Chrome上已經有不少軟件來作這個檢查了,其核心原理,都是經過拉羣組的方式來作。那麼在手機上,一樣能夠經過這種方式來實現,若是如今你還不知道該怎麼作,那麼後面的文章就沒有看的必要了……

進程清理

你們應該都用過馮老師的『綠色守護』,這個App的最基本無Root功能,就是經過在應用管理界面『結束進程』的方式來中止一個後臺運行的App,你們都知道天朝的App,基本都是全家桶,因此這種方式對釋放系統資源確實仍是有必定的幫助的,那麼咱們就來看看簡單的實現。

核心原理很是簡單,在應用詳情頁面,經過中止服務來禁止App服務。OK,那麼咱們要作的,實際上,就是下面的流程:

經過Intent打開對應App的管理詳情信息頁面
點擊中止運行
返回,處理下一個
流程要比搶紅包什麼的簡單多了,下面列出2個關鍵代碼,你們應用詳情界面:

public void cleanProcess(View view) {

for (String mPackage : mPackages) {
    Intent intent = new Intent();
    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    Uri uri = Uri.fromParts("package", mPackage, null);
    intent.setData(uri);
    startActivity(intent);
}

}
監控詳情頁面,進行中止操做:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
        event.getPackageName().equals("com.android.settings")) {
    CharSequence className = event.getClassName();
    if (className.equals("com.android.settings.applications.InstalledAppDetailsTop")) {
        AccessibilityNodeInfo info = findViewByText("強行中止");
        if (info.isEnabled()) {
            performViewClick(info);
        } else {
            performBackClick();
        }
    }
    if (className.equals("android.app.AlertDialog")) {
        clickTextViewByText("肯定");
        performBackClick();
    }
}

}
這個App惟一的難點,應該就剩下怎麼把UI作的好看一點了。

另外,還有一個兼容性的問題,你們都懂的,國內各類第三方的ROM廠家,常常會修改一些系統的Activity,甚至不一樣系統版本同一個功能的Activity都有可能不同,因此,使用AccessibilityService的一個比較大的麻煩就是兼容性的處理,須要使用dumpsys和uiautomator這些工具來進行詳細的分析,這些工具的使用以及分析方法,在個人新書《Android羣英傳:神兵利器》中都有詳細的講解,想深刻了解的開發者能夠參考下。

判斷應用當前狀態

藉助AccessibilityService一樣能夠作一些比較有用的事情,例如監控App當前的狀態,例如前臺、後臺的切換,經過TYPE_WINDOW_STATE_CHANGED便可進行判斷,特別是在5.0以上,原先的getRunningTasks這個方法被升級到系統權限。

固然,AccessibilityService或多或少會存在一些性能問題,因此如今並不推薦使用這種方式來監控應用狀態,更多的是經過activitylifecyclecallbacks來實現對App狀態的跟蹤與監控。

出軌

其實一旦咱們瞭解了AccessibilityService的使用原理,那麼就很難作到不逾矩,畢竟這裏的誘惑太大了,當我寫到這裏時,甚至有種毛骨悚然的感受,因此這裏申明:
本文全部內容僅供學習、技術交流,由此產生的各類問題,均與本人無關。

防卸載

據我所知,已經有些App或者稱之爲惡意軟件實現了這樣的功能,這個功能難嗎,不難,估計都不超過20行代碼,但確實很噁心,特別是對一些普通、小白用戶,壓根都不知道AccessibilityService是什麼,莫名其妙你讓我啓用,寫的可能比較好看,什麼幫助你清理系統,優化資源,但實際上,在後面作一些見不得人的事情。

咱們來分析下如何實現,當用戶想要卸載你的App的時候,通常會來到設置界面,找到你的App而後選擇卸載,那麼若是咱們監控這個頁面,若是發現是本身的App,就直接退出,這樣不就沒法卸載了嗎?是的,代碼以下,沒幾行代碼:

private String mDefenseName = "微信";

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

super.onAccessibilityEvent(event);
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
        event.getPackageName().equals("com.android.settings")) {
    CharSequence className = event.getClassName();
    if (className.equals("com.android.settings.SubSettings")) {
        AccessibilityNodeInfo nodeInfo = findViewByText("應用程序信息");
        if (nodeInfo != null && findViewByText(mDefenseName) != null) {
            performBackClick();
        }
    }
}

}
那麼有人要說了,若是是用的一些第三方ROM,直接在桌面就能卸載呢?一樣的,只不過會稍微麻煩點,須要判斷的東西更多了,要處理的兼容性更復雜了而已。

這裏不得不說,雖然國內各類第三方ROM百花齊放、肆意妄爲,但這也給AccessibilityService形成了很大的兼容性處理難題,因此對一些惡意的使用AccessibilityService的App也造成了很大的限制。

瀏覽器劫持

實際上並不侷限於瀏覽器,各類App都能被劫持,由於AccessibilityService監控的是全局App,良心點的可能會指定包名進行監控。因此,咱們能夠監控任意一個App,例如瀏覽器,一旦打開,咱們就輸入指定的網址,或者是一打開一些App,就輸入一些查詢內容,這裏我以鄙司的滬江網校爲例,進入後直接進行搜索。

算了代碼仍是不貼了,徹底都是Copy前面的內容。

監控密碼框

呵呵呵,這個你還真是想多了,系統再天真也不會把這個權限開放給你,全部的設置爲password類型的EditText都是沒法被監控的,系統還算有點良心。

這裏我只列舉了一些很是簡單的Hack方式,但實際上,還有不少,例如經過拉取指定網站的內容後自動安裝App並模擬點擊等,固然,AccessibilityService也能夠用在自動化測試中,這徹底就是一把雙刃劍,是利是弊,徹底取決於使用他的人。

跳過用戶受權

通常來講,AccessibilityService是須要用戶手動操做受權才能夠執行的,可是,若是是在Root的狀況下,或者是在ADB鏈接PC的狀況下,甚至都不用用戶受權,就能夠完成AccessibilityService的受權操做。

Root的狀況就不說了,經過修改Setting的數據庫就能夠更改這個設置了,固然,有Root的狀況下,就根本不須要AccessibilityService了。

在沒有Root的狀況下,若是PC經過ADB發出指令,一樣是能夠自動完成受權的,這個能夠參考360的一篇文章:

http://www.freebuf.com/articl...

我這裏就很少說了,你們看看就懂了,並無太多的技術含量,應該算是系統的一個小的漏洞。

AccessibilityService通常分析步驟

前面咱們分析了那麼多AccessibilityService好的很差的使用方法,實際上,總結下就這麼幾步。

分析操做的流程,拆解成單步可實現的過程
經過UIAutomator和adb shell dumpsys來查看對應的UI控件ID、文本或者是具體的Activity
經過邏輯組合進行代碼編寫
調試、兼容性處理
經過上面的這些方式,基本就能夠實現一些固定流程的操做自動化了。關於AccessibilityService的工具類,我放到了Github上,雖然功能已經比較全了,但尚未通過不少的兼容性測試,同時,礙於時間和精力的關係,給出的Demo示例也很少,但願你們能夠多提PR,共同完善。

https://github.com/xuyisheng/...

歡迎你們關注個人微信公衆號:

Android羣英傳

相關文章
相關標籤/搜索