Android自動搶紅包,自動安裝原理之AccessibilityService

euom2269 9年前發布 | 52K 次閱讀 Android 微信 Android開發 移動開發

前段時間看別人博客的時候偶然間看到了Android微信自動回復功能,最后的效果也很不錯,博主在文中提到了AccessibilityService,以前壓根沒接觸過這東西,表示一臉懵逼。也是這個原因我去找了AccessibilityService相關的資料好好的看了一遍,發現這個東西真的太NB了,網上對AccessibilityService的應用還是有不少的文章的,但是詳細的介紹資料還是比較少,對于剛剛學習這個的同學看完很多資料還是一臉茫然,于是才有了本文。我相信當你在看完本文之后,再去看前面的那篇文章,我相信會輕松很多。

AccessibilityService是什么,官網是這樣解釋的

Accessibility services are intended to assist users with disabilities in using Android devices and apps. They run in the background and receive callbacks by the system whenAccessibilityEvents are fired.

也就是說這是個輔助功能,目的是幫助殘疾人去使用Android設備和應用。它在后臺運行,可以接收系統的回調。

可見AccessibilityService的出現Google的初衷是幫助殘疾人去使用Android設備,但是當你對它足夠了解了之后你會發現它的作用不僅僅只是這樣。對windows編程有了解的同學肯定知道hook(鉤子),AccessibilityService和windows下的hook有那么一點的相似。AccessibilityService可以攔截到系統發出的一些消息(比如窗體狀態的改變,通知欄狀態的改變,View被點擊了等等),當攔截到這些事件我們就可以去做一些我們想做的事兒了~~~
AccessibilityService能做些什么呢? 比如自動化測試、自動搶紅包、自動安裝等等。在帶來便利的同事,也還是有需要注意的地方:當你開啟了輔助功能之后會對你的隱私信息帶來一些風險,所以還是需要謹慎的去開啟第三方的輔助功能。當然這對于我們開發者而言都不是事,因為我們完全可以自己去開發屬于我們的輔助功能。

本文學習目錄

1.AccessibilityService的創建與配置
2.怎么去使用AccessibilityService
3.一步一步構建一個apk自動安裝器

1.AccessibilityService的創建與配置

第一步就是自己去創建一個類繼承于AccessibilityService,并實現必須實現的兩個方法

public class MyAccessibilityService extends AccessibilityService {
    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {

    }

    @Override
    public void onInterrupt() {

    }
}

隨后就是在res/xml目錄下新建一個xml文件(文件名隨意),后面會對這個文件作詳細的介紹。

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"  
    android:canRetrieveWindowContent="true"
    android:description="@string/my_accessibility_description"
    android:notificationTimeout="100"
    android:packageNames="com.tencent.mobileqq,com.android.packageinstaller" />

最后就是去配置清單文件了

 <service
            android:name=".service.MyAccessibilityService"
            android:enabled="true"
            android:exported="true"
            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/my_services_config" />//在meta-data里申明配置信息
        </service>

別忘記了添加權限

<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />

到這我們就可以把應用跑到我們的手機上了,然后打開輔助功能,去開啟我們剛剛創建的這個輔助功能。如下圖:

Android自動搶紅包,自動安裝原理之AccessibilityService

當然因為什么都沒做,開啟了也沒什么用,下面就去看看怎么使用吧!

2.怎么去使用AccessibilityService

先說說之前創建的那個xml文件中各個屬性的含義吧

  • accessibilityEventTypes: 用來設置響應事件的類型,比如typeAllMask就是響應全部事件,typeNotificationStateChanged就是響應通知狀態的改變,如果需要響應多種事件類型可以以 ‘ | ’ 隔開。
  • accessibilityFeedbackType: 給用戶的反饋方式,比如語音、震動等,這里用處不大。
  • canRetrieveWindowContent :是否可以獲取活動窗體的內容,這個設置為true才可以取得窗體中的控件和事件源
  • description :輔助功能的描述
  • notificationTimeout :兩個相同類型事件發送到服務的事件間隔,單位毫秒
  • packageNames :指定響應某個應用的事件,取值為應用的包名,多個以‘ , ’ 隔開。沒有此屬性則表示響應全部應用。這里我填寫的是手機qq和系統安裝器的包名

然后進入到我們的MyAccessibilityService中,定位到onAccessibilityEvent方法編寫如下代碼

log("-------------------------------------------------------------");
        int eventType = event.getEventType();//事件類型
        log("packageName:" + event.getPackageName() + "");//響應事件的包名,也就是哪個應用才響應了這個事件
        log("source:" + event.getSource() + "");//事件源信息
        log("source class:" + event.getClassName() + "");//事件源的類名,比如android.widget.TextView
        log("event type(int):" + eventType + "");

        switch (eventType) {
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知欄事件
                log("event type:TYPE_NOTIFICATION_STATE_CHANGED");
                break;
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED://窗體狀態改變
                log("event type:TYPE_WINDOW_STATE_CHANGED");
                break;
            case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED://View獲取到焦點
                log("event type:TYPE_VIEW_ACCESSIBILITY_FOCUSED");
                break;
            case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
                log("event type:TYPE_VIEW_ACCESSIBILITY_FOCUSED");
                break;
            case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
                log("event type:TYPE_GESTURE_DETECTION_END");
                break;
            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                log("event type:TYPE_WINDOW_CONTENT_CHANGED");
                break;
            case AccessibilityEvent.TYPE_VIEW_CLICKED:
                log("event type:TYPE_VIEW_CLICKED");
                break;
            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
                log("event type:TYPE_VIEW_TEXT_CHANGED");
                break;
            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                log("event type:TYPE_VIEW_SCROLLED");
                break;
            case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
                log("event type:TYPE_VIEW_TEXT_SELECTION_CHANGED");
                break;
        }

        for (CharSequence txt : event.getText()) {
            log("text:" + txt);//輸出當前事件包含的文本信息
        }

        log("-------------------------------------------------------------");

log方法就是打印信息用的,是對Log的一個簡單封裝。

在運行一次程序,打開我們的手機qq可以看見輸出日志如下

Android自動搶紅包,自動安裝原理之AccessibilityService

可以很清晰的看見當我們打開qq或觸發很多的事件,第一個響應的事件是TYPE_WINDOW_STATE_CHANGED,觸發此事件的事件源是com.tencent.mobileqq.activity.SplashActivity

接著,當我點擊最上面的 ‘ 電話 ’,會得到如下日志:

Android自動搶紅包,自動安裝原理之AccessibilityService

我就不一一截圖操作的日志了,下來大家可以自行嘗試。到這里你用該對onAccessibilityEvent有了進一步的了解。

3.一步一步構建一個apk自動安裝器

這一節來個實戰的應用:做一個apk的自動安裝器,點擊apk文件即可開始自動安裝。

國內的rom廠商大家都很清楚:百(shang)花(xin)齊(bing)放(kuang),已經把原生的rom改的面目全非。所以想做一個面對全部手機的apk的自動安裝器還是比較麻煩的。我的手機是魅族的,下圖是魅族手機apk安裝的步驟(其他手機可能會略有不同,下來自己更改不同部分即可,這里主要講解原理):

Android自動搶紅包,自動安裝原理之AccessibilityService

Android自動搶紅包,自動安裝原理之AccessibilityService

Android自動搶紅包,自動安裝原理之AccessibilityService

可以看見點擊安裝包之后會彈出一個確認框,點擊繼續之后會出現下一步,點擊了下一步就可以點擊安裝了。

好了,下面我們可以來創建一個自動安裝的服務了,步驟和第一節描述的一樣將packageNames指定成com.android.packageinstaller就可以了。這里我們先別著急去實現功能(就算你想去實現,也摸不著頭腦),我們還是像第二節那樣去輸出日志信息,查看日志輸出信息(對響應事件信息的打印)是使用AccessibilityService的重點,看完日志的輸出信息,然后對其分析,才會知道怎么去做。

我們來看看在安裝apk文件時候輸出的部分日志信息:

Android自動搶紅包,自動安裝原理之AccessibilityService

Android自動搶紅包,自動安裝原理之AccessibilityService

Android自動搶紅包,自動安裝原理之AccessibilityService

從日志信息中可以看出彈出對話框中繼續是個Button,接著的下一步是個TextView。到這里我們可以開始編寫我們的代碼了。

public class AutoInstallService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        PrintUtils.printEvent(event);
        findAndPerformActionButton("繼續");
        findAndPerformActionTextView("下一步");
        findAndPerformActionTextView("安裝");
    }


    private void findAndPerformActionButton(String text) {
        if (getRootInActiveWindow() == null)//取得當前激活窗體的根節點
            return;
        //通過文字找到當前的節點
        List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByText(text);
        for (int i = 0; i < nodes.size(); i++) {
            AccessibilityNodeInfo node = nodes.get(i);
            // 執行點擊行為
            if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
        }
    }

    private void findAndPerformActionTextView(String text) {
        if (getRootInActiveWindow() == null)
            return;
        //通過文字找到當前的節點
        List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByText(text);
        for (int i = 0; i < nodes.size(); i++) {
            AccessibilityNodeInfo node = nodes.get(i);
            // 執行按鈕點擊行為
            if (node.getClassName().equals("android.widget.TextView") && node.isEnabled()) {
                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
        }
    }
}

例子很簡單,代碼已經注釋的比較詳細,我就不再對代碼作更多的講解了,有疑問可以留言。

到這里你應該對AccessibilityService有了進一步的認識,會發現原來紅包助手之類軟件的實現的原理也沒那么難。是不是有點自己去做一個紅包助手的想法了?現在再去看看文章開始的那篇文章你的收獲會更大:Android微信自動回復功能

補充說明

AccessibilityService中還有幾個常用的方法 onServiceConnected、onInterrupt、onGesture。看名字大致也知道什么時候會被調用。

在onServiceConnected中可以去配置AccessibilityService的一些信息,也就是之前在xml文件可以在這里通過代碼配置,不過這里沒法配置canRetrieveWindowContent屬性,剛開始也被這個坑了很久

@Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        PrintUtils.log("onServiceConnected");
//        //可用代碼配置當前Service的信息
//        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
//        info.packageNames = new String[]{"com.android.packageinstaller", "com.tencent.mobileqq", "com.trs.gygdapp"}; //監聽過濾的包名
//        info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; //監聽哪些行為
//        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; //反饋
//        info.notificationTimeout = 100; //通知的時間
//        setServiceInfo(info);
    }

官方文檔

本文源碼


 

來源:http://www.jianshu.com/p/65afab3d1e2a

 

 本文由用戶 euom2269 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!