1. 程式人生 > >輔助功能之自動搶紅包

輔助功能之自動搶紅包

hi大家好。
新年又來了,微信群裡又是各種紅包橫飛。作為技術人員的我們卻大可不必擔心一不小心,手速慢了點,又錯過了幾十萬。我們可以通過安卓的輔助功能來實現自己的微信自動搶紅包,安全又快捷。

輔助服務

我們在 設定->無障礙 中,就可以看到手機中所有的輔助服務了。輔助功能通常是針對一些視力聽力等有障礙導致使用手機有障礙的人群,做一些語言提醒等幫助他們更好地使用手機。
因為輔助功能可以得到系統級別的事件和服務,第三方應用的輔助功能都需要手動開啟。我們常用的綠色守護,冰箱等應用都是利用輔助服務實現的。


image

我們先來實現一個簡單的輔助服務吧。

1,繼承AccessibilityService類。AccessibilityService類一共有四個可以重寫的方法。

TestService類

public class TestService extends AccessibilityService {
    /**
     *  必須重寫的方法:此方法用了接受系統發來的event。在你註冊的event發生是被呼叫。在整個生命週期會被呼叫多次。
     */
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
    }

   /**
     *  必須重寫的方法:系統要中斷此service返回的響應時會呼叫。在整個生命週期會被呼叫多次。
     */
    @Override
    public void onInterrupt() {
    }

     /**
     *  當系統連線上你的服務時被呼叫
     */
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
    }


    /**
     *  在系統要關閉此service時呼叫。
     */
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
}

2,給輔助服務寫一個配置檔案。
res/xml/text_server_config.xml
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_description"
    android:notificationTimeout="10" />

看屬性的名字應該比較容易猜測到不同是屬性是用來幹嘛的。

accessibilityEventTypes:響應那種型別的事件

accessibilityFeedbackType:用什麼方式反饋給使用者

notificationTimeout:響應時間

packageNames:指定響應哪個應用的事件。如果不填則是響應所有的應用事件(如果以後寫搶紅包的輔助功能,可以只寫微信的包名)

description:輔助服務的描述資訊。

3,在manifest中註冊服務。

 <service
            android:name=".TestService"
            //輔助功能的名稱
            android:label="@string/test_service_label"
            //此處必須宣告一次許可權
            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/text_service_config" />
        </service>

4,最後,回到服務的類,TestService。在onAccessibilityEvent(AccessibilityEvent event)方法中,我們可以接收到系統發過來的事件。當然取決於我們在配置檔案中選擇了我們要監聽哪些種類,哪些應用的事件了。
public void onAccessibilityEvent(AccessibilityEvent event) {
    //得到事件的包名。如果註冊了多個應用的事件,可以在此做一個判斷。
    String packageName = event.getPackageName().toString();

    //得到對應的事件型別,這裡有很多很多種的事件型別,具體可以自行翻閱AccessibilityEvent類中的定義。
    int eventType = event.getEventType();

    //得到根的view節點。可以當做當前acitivity的檢視看成是樹狀結構的(實際上也是~。~),而我們現在就得到了它的根節點。
    AccessibilityNodeInfo root = getRootInActiveWindow();

    //我們可以得到此節點的文字
    String rootText = root.getText().toString();
    //得到此節點的class
    String rootClass = root.getClass().toString();
    //得到子節點的和子節點總數
    root.getChild(root.getChildCount()-1);
 }

到這裡,我們可以通過無數次遍歷,找到檢視上自己想要的那個控制元件了。當然,還有更加簡單的方法。
  //這兩個方法如果找不到的話,都會報錯。所以請做好對應的處理。
    root.findAccessibilityNodeInfosByText("根據文字內容查詢節點");
    root.findAccessibilityNodeInfosByViewId("根據id查詢節點,當然實際上很難知道id是多少~、~");

最後我們可以對控制元件做一些操作,比如
 //點選操作
    root.performAction(AccessibilityNodeInfo.ACTION_CLICK);

    //滑動操作
    root.performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);

好,對於輔助服務的基礎知識我們學到這裡已經差不多了,如果跟著我寫了一個demo的童鞋們,可以執行一下,在設定->無障礙中把自己的輔助功能開啟試試。把玩一下。

下面可以進入搶紅包的開發。

搶紅包

我們先回顧一下手動搶紅包的過程。
假設小新某天在用手機刷微博。叮叮,聽到提示聲,通知欄上顯示:“小明\n [微信紅包]恭喜發財,大吉大利”。
小新光速點了一下微信通知,手機自動跳轉到了對應的微信聊天頁面,聊天介面里正是一條橙色底色,配上紅包圖片的資訊:“恭喜發財,大吉大利\n領取紅包\n微信紅包”。
腦子還沒反應過來,手指已經自動點到這條資訊上,這是有一個正在載入的提示框一閃而過,然後就是正中一個大大的紅包,中間是金黃色的“開”字。
不用想了,開!看著開字轉啊轉,心急如焚。最後螢幕一閃,跳到了紅包詳情頁面,心頭大石落地,詳情頁面寫在“0.01分錢”。小新也心滿意足地回去看微博了。

我們的自動搶紅包就是要自動幫我們完成這麼一個流程:
1,獲取通知欄的資訊,判斷是否紅包。
2,如果螢幕關著的,先開啟螢幕。
3,點選通知,進入聊天介面
4,點選紅包資訊
5,點選紅包中的“開”
6,返回主介面,安安靜靜了無痕跡。

先上github的地址~。~我是地址;大家可以直接去看程式碼。程式碼很簡單。無非就是遍歷找控制元件。

1, 得到通知欄資訊
通知欄事件

AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED

可以通過event.getText()方法得到通知欄的文字。然後在與“[微信紅包]”做對比,判斷是否微信紅包。

2,
開啟螢幕。如果是有螢幕鎖的~。~那我就沒辦法了哎,,知道的童鞋請賜教。

  /**
     * 解鎖
     */
    private void wakeAndUnlock() {
        //獲取電源管理器物件
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

        //獲取PowerManager.WakeLock物件,後面的引數|表示同時傳入兩個值,最後的是除錯用的Tag
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");

        //點亮螢幕
        wl.acquire(1000);

        //得到鍵盤鎖管理器物件
        KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        kl = km.newKeyguardLock("unLock");

        //解鎖
        kl.disableKeyguard();
    }

記得釋放鍵盤管理器

 kl.reenableKeyguard();
3,通過通知欄進入微信聊天介面。
//開啟微信聊天頁面
    private void openWeichaPage(AccessibilityEvent event) {
        if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
            //得到通知的物件
            Notification notification = (Notification) event.getParcelableData();

            //得到通知欄的資訊
//            String content = notification.tickerText.toString();
//            String name = content.substring(0, content.indexOf(":"));
//            String scontent = content.substring(content.indexOf(":"), content.length());
//            Log.d("mylog", "------openWeichaPage  name: " + name + " content: " + scontent);


            //開啟通知欄的intent,即開啟對應的聊天介面
            PendingIntent pendingIntent = notification.contentIntent;
            try {
                pendingIntent.send();
            } catch (PendingIntent.CanceledException e) {
                e.printStackTrace();
            }
        }
    }

4,我們需要監聽頁面的變化加自己定義變數來判斷是否跳轉到了微信聊天頁面。

頁面跳轉的事件是:

                      
 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED

微信聊天頁面的classname:

com.tencent.mm.ui.LauncherUI

判斷的方法:

    String className = event.getClassName().toString();

    //是否微信聊天頁面的類
    if (className.equals(LAUCHER)) {
       findStuff();
    }

然後就是做遍歷,大體思路是呼叫getChild(i)找到聊天頁面中的紅包。可以先通過getClassName()比較是否“android.widget.TextView”,然後通過getText()匹配文字內容。

具體方法不表。大家可以自己寫寫,不想寫可以看GitHub上我寫的程式碼。

5,和上面的方法一直,判斷視窗跳轉,加遍歷找到“開”字,對,開 也是一個TextView。

6,至此就大功告成,可以返回桌面了。

 /**
     * 回到系統桌面
     */
    private void back2Home() {
        Intent home = new Intent(Intent.ACTION_MAIN);

        home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        home.addCategory(Intent.CATEGORY_HOME);

        startActivity(home);
    }

我們的搶紅包之旅到這裡就告一段落了,結束的是一次艱苦的擼程式碼的時光,開啟的是千千萬萬次自動搶紅包的快感。