1. 程式人生 > >Android輔助功能之自動安裝apk

Android輔助功能之自動安裝apk

原理:1、當有apk安裝時,包名為com.android.packageinstaller的apk會彈出安裝授權框,會引起介面視窗的變化

2.AccessbilityService可以監聽到介面視窗的變化

步驟:

1.寫一個類繼承AccessibilityService並重寫相關方法,在方法onAccessibilityEvent中監聽視窗事件的變化

AccessibilityNodeInfo rootNode = getRootInActiveWindow();   //獲取視窗


int count = rootNode.getChildCount();     //獲取元件的數目


 List<AccessibilityNodeInfo> nodeInfos = nodeInfo1.findAccessibilityNodeInfosByText("下一步");  //安裝文字內容查詢控制元件


 accessibilityNodeInfo.getClassName()            //獲取元件的名稱


  accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);   //執行點選事件

程式碼如下:

package com.example.zjhl.myapplication;

import android.accessibilityservice.AccessibilityService;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.os.Build;
import android.os.PowerManager;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;

import java.util.List;

/**
 * Created by zjhl on 2017/10/28.
 */
public class AutoReplyService extends AccessibilityService {

    private boolean canGet = false;//能否點選紅包
    private boolean enableKeyguard = true;//預設有螢幕鎖

    //視窗狀態
    private static final int WINDOW_NONE = 0;
    private static final int WINDOW_LAUNCHER = 3;
    //當前視窗
    private int mCurrentWindow = WINDOW_NONE;

    //鎖屏、解鎖相關
    private KeyguardManager km;
    private KeyguardManager.KeyguardLock kl;
    //喚醒螢幕相關
    private PowerManager pm;
    private PowerManager.WakeLock wl = null;

    private boolean isInstall;


    //喚醒螢幕和解鎖
    private void wakeAndUnlock(boolean unLock) {
        if (unLock) {
            //若為黑屏狀態則喚醒螢幕
            if (!pm.isScreenOn()) {
                //獲取電源管理器物件,ACQUIRE_CAUSES_WAKEUP這個引數能從黑屏喚醒螢幕
                wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "bright");
                //點亮螢幕
                wl.acquire();
            }
            //若在鎖屏介面則解鎖直接跳過鎖屏
            if (km.inKeyguardRestrictedInputMode()) {
                //設定解鎖標誌,以判斷搶完紅包能否鎖屏
                enableKeyguard = false;
                //解鎖
                kl.disableKeyguard();
            }
        } else {
            //如果之前解過鎖則加鎖以恢復原樣
            if (!enableKeyguard) {
                //鎖屏
                kl.reenableKeyguard();
            }
            //若之前喚醒過螢幕則釋放之使螢幕不保持常亮
            if (wl != null) {
                wl.release();
                wl = null;
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        int eventType = event.getEventType();
        System.out.println("onAccessibilityEvent..............................."+eventType);
        switch (eventType) {
            //第一步:監聽通知欄訊息
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                System.out.println("onAccessibilityEvent.......................................TYPE_NOTIFICATION_STATE_CHANGED.");
                break;
            //第二步:監聽是否進入apk安裝介面
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                System.out.println("TYPE_WINDOW_STATE_CHANGED...............................");
                AccessibilityNodeInfo rootNode = getRootInActiveWindow();
                if (rootNode != null) {
                    int count = rootNode.getChildCount();
                    for (int i = 0; i < count; i++) {
                        final AccessibilityNodeInfo nodeInfo = rootNode.getChild(i);
                        if (nodeInfo == null) {
                            continue;
                        }
                        System.out.println("nodeInfo.getClassName.............................." + nodeInfo.getClassName());
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                clickNode(nodeInfo);
                            }
                        }).start();
                    }
                }
                break;

            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                System.out.println("onAccessibilityEvent.......................................TYPE_WINDOW_CONTENT_CHANGED");
                break;
        }

    }

    private void clickNode(AccessibilityNodeInfo nodeInfo) {
        //“下一步”和“安裝”都是button
        if ("android.widget.Button".equals(nodeInfo.getClassName()) && !isInstall) {
            isInstall = true;
            System.out.println("TYPE_WINDOW_STATE_CHANGED...............................1");
            AccessibilityNodeInfo nodeInfo1 = getRootInActiveWindow();
            System.out.println("TYPE_WINDOW_STATE_CHANGED...............................2");
            if (nodeInfo1 != null) {
                System.out.println("TYPE_WINDOW_STATE_CHANGED...............................3");
                //找到"下一步"
                List<AccessibilityNodeInfo> nodeInfos = nodeInfo1.findAccessibilityNodeInfosByText("下一步");
                System.out.println("下一步.................................");
                if (nodeInfos.size() == 0) {
                    nodeInfos = nodeInfo1.findAccessibilityNodeInfosByText("安裝");
                    System.out.println("安裝.................................");
                    if (nodeInfos.size() == 0) {
                        System.out.println("完成.................................");
                        nodeInfos = nodeInfo1.findAccessibilityNodeInfosByText("完成");
                    }
                }
                System.out.println("TYPE_WINDOW_STATE_CHANGED...............................4..." + nodeInfos.size());
                for (int j = 0; j < nodeInfos.size(); j++) {
                    System.out.println("recycle.................................." + j);
                    AccessibilityNodeInfo accessibilityNodeInfo = nodeInfos.get(j);
                    System.out.println("TYPE_WINDOW_STATE_CHANGED...............................5..." + accessibilityNodeInfo.getClassName());
                    //找到圖片最外層的位置
//                    if (!isInstall) {
                        if ("android.widget.Button".equals(accessibilityNodeInfo.getClassName())) {
                            accessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            System.out.println("TYPE_WINDOW_STATE_CHANGED...............................clicked...");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            isInstall = false;
                            clickNode(nodeInfo);
                            break;
                        }
                }
            }
        }
    }

    @Override
    public void onInterrupt() {
        System.out.println("onInterrupt.............................");

    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.i("demo", "開啟");
        System.out.println("onServiceConnected.......................................");
        //獲取電源管理器物件
        pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        //得到鍵盤鎖管理器物件
        km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        //初始化一個鍵盤鎖管理器物件
        kl = km.newKeyguardLock("unLock");
        Toast.makeText(this, "_已開啟應用自動安裝服務_", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("onDestroy.......................................");
        Log.i("demo", "關閉");
        wakeAndUnlock(false);
        Toast.makeText(this, "_已關閉應用自動安裝服務_", Toast.LENGTH_LONG).show();
    }

}


2.在配置檔案中進行服務的配置

   <service
            android:name=".AutoReplyService"
            android:enabled="true"
            android:exported="true"
            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/auto_reply_service_config"/>
        </service>

3.在res的xml資料夾下配置檔案auto_reply_service_config.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"
    android:notificationTimeout="100"
    android:packageNames="com.tencent.mobileqq,com.android.packageinstaller"
    />
    <!--android:packageNames="com.example.zjhl.myapplication,com.UCMobile,com.wandoujia.phoenix2,com.wandoujia.phoenix2.usbproxy,eu.chainfire.supersu,com.mediatek.voiceunlock,com.kingouser.com.fragment" -->

4.執行後在輔助功能中手動開啟服務MyAccessibilityApplication服務,直接執行後當有apk安裝時會自動模擬點選