Android輔助功能之自動安裝apk
阿新 • • 發佈:2019-01-03
原理: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安裝時會自動模擬點選