微信外卦抢红包下载外监视器

从抢红包插件谈AccessibilityService
微信红包自打出世以来就极其受欢迎,抢红包插件可谓红极一时 今天,我们重新谈谈抢红包插件的哪些事儿 本质上,抢红包插件的原理不难理解,其过程就是在收到红包时,自动模拟点击 做过自动化UI测试的童鞋应该非常熟悉
微信红包自打出世以来就极其受欢迎,抢红包插件可谓红极一时.今天,我们重新谈谈抢红包插件的哪些事儿.本质上,抢红包插件的原理不难理解,其过程就是在收到红包时,自动模拟点击.做过自动化UI测试的童鞋应该非常熟悉了.
那么问题来了,我们怎么知道有没有红包,又怎么模拟点击操作呢?在PC端我们有按键精灵,那么在设备上呢?话说也偶然,Google为了让Android更实用,为用户提供了无障碍辅助服务—AccessibilityService.
AccessibilityService运行在后台,并且能够收到由系统发出的一些事件(AccessibilityEvent),比如焦点改变,输入内容变化,按钮被点击了等等,换言之,界面中产生的任何变化都会产生一个时间,并由系统通知给AccessibilityService.这就像监视器监视着界面的一举一动,一旦界面发生变化,立刻发出警报.另外,该服务不受系统重启的的影响.除非你手动关闭或者通过第三方安全软件将其强制关闭.
现在让我们来看看如何AccessibilityService的基本使用.
1. 创建服务类
和Service类似,要使用该服务,首先创建继承子AccessibilityService子类:
public class RobService extends AccessibilityService {
public void onAccessibilityEvent(AccessibilityEvent event) {
public void onInterrupt() {
protected void onServiceConnected() {
简单的介绍这两个常用的方法:
onServiceConnected():服务启动成功后执行该方法,通常我们会在这里做一些初始化的操作.除此之外,也可以在该方法中为AccessibilityServiceInfo设置AccessibilityService参数
onAccessibilityEvent():系统通过sendAccessibiliyEvent()不断的发送AccessibilityEvent,onAccessibilityEvent()中可以捕获到这些事件,进而根据不同的事件进行处理.该方法是整个服务的核心方法.
2. 配置服务类
AccessibilityService是一个特殊的Service服务,同样需要在manifest.xml中声明该Service.另外在版本4.1之后,该Service需要BIND_ACCESSIBILITY_SERVICE权限,因此其基本配置如下:
和普通的Service不同,该服务不能通过普通的startService()方法启动,而是由系统自行识别.为了让系统能够该服务,还需要为该服务配置响应的参数信息.在4.0系统之前,我们通过setServiceInfo()方法在运行时为其设置配置信息,而在4.0之后,可以在manifest.xml中通过来为其配置信息.
先来看如何通过setServiceInfo()为其配置信息,这就用到了上面onServiceConnected()方法:
protected void onServiceConnected() {
AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
serviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
serviceInfo.packageNames = new String[]{"com.tencent.mm"};
serviceInfo.notificationTimeout=100;
setServiceInfo(serviceInfo);
再来看看如何通过来配置:
首先,我们在上面标签中添加元素,然后通过android:resource指定相应的配置文件(在res目录下创建xml文件,并在其中创建配置文件accessibility.xml):
接下来我们来看accessibility.xml的相关配置:
为了方便理解,我们快速的对其中的一些重要属性进行说明:
accessibilityEventTypes:表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如滑动,焦点变化,长按等.具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知.
accessibilityFeedbackType:表示反馈方式,比如是语音播放,还是震动
canRetrieveWindowContent:表示该服务能否访问活动窗口中的内容.也就是如果你希望在服务中获取窗体内容的化,则需要设置其值为true.
notificationTimeout:接受事件的时间间隔,通常将其设置为100即可.
packageNames:表示对该服务是用来监听哪个包的产生的事件
多数情况下,我们使用配置文件的方式来配置AccessibilityService即可.
3. 启动服务
当我们做完以上操作,便可将app安装到手机.安装成功后,在设置-&辅助功能中便可以找到我们的服务.该服务默认处在关闭状态,需要手动开启.
4. 获取事件信息
上面我们说道,onAccessibilityEvent(AccessibilityEvent event)是该服务的核心方法,其中参数event封装来自界面相关事件的信息,比如我们可以获得该事件的事件类型,进而根据起类型选择不同的处理方式:
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_VIEW_CLICKED:
//界面点击
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
//界面文字改动
5. 获取控件信息
仅仅知道事件的信息是不够的,我们还希望通过事件来获取发出该事件(事件源)的信息,比如Button按钮被点击时它的text.
正如上面所提到的,要想获取控件的相关信息,在配置AccessibilityService时设置其canRetrieveWindowContent属性.之后,我们便可以通过event.getSource()来获取事件源.同样,我们也可以通过getRootInActiveWindow()来获取当前活动窗口的根节点.
那么什么是活动窗口呢?
所谓的活动窗口是用户当前触摸的窗口,或者在没有触摸状态下带有输入焦点的窗口.
6. 检测服务是否开启
简单了介绍了一些AccessibilityService的基础知识,想必到现在已经了解了如何去用了.但是这里我还是要补充一点关于检测某个服务是否开启的知识,通常来说大体有一下两种方法来检测:
方法一:借助服务管理器AccessibilityManager来判断,但是该方法不能检测app本身开启的服务.
private boolean enabled(String name) {
AccessibilityManager am = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
List serviceInfos = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC);
List installedAccessibilityServiceList = am.getInstalledAccessibilityServiceList();
for (AccessibilityServiceInfo info : installedAccessibilityServiceList) {
Log.d("MainActivity", "all --&" + info.getId());
if (name.equals(info.getId())) {
方法二:我们知道大部分的系统属性都在settings中进行设置,比如wifi,蓝牙状态等,而这些信息主要是存储在settings对应的的中(system表和serure表),同样我们也可以通过直接读取setting设置来判断相关服务是否开启:
private boolean checkStealFeature1(String service) {
int ok = 0;
ok = Settings.Secure.getInt(getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);
Log.d("MainActivity", "accessibilityEnabled :" + ok);
} catch (Settings.SettingNotFoundException e) {
Log.d("MainActivity", "Error finding setting,default accessibility to not found:" + e.getMessage());
TextUtils.SimpleStringSplitter ms = new TextUtils.SimpleStringSplitter(':');
if (ok == 1) {
String settingValue = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
ms.setString(settingValue);
while (ms.hasNext()) {
String accessibilityService = ms.next();
if (accessibilityService.equalsIgnoreCase(service)) {
到现在有关AccessibilityService的一些知识,我们已经讲完,下面我们就看它的具体使用,其中典型的应用就是抢红包插件.
实战:红包插件
先回顾一下抢红包的的流程:
1. 状态栏出现”[微信红包]”的消息提示,点击进入聊天界面
2. 点击相应的红包信息,弹出抢红包界面
3. 在抢红包界面点击”开”,打开红包
4. 在红包详情页面,查看详情,点击返回按钮返回微信聊天界面.
以上是不在微信聊天界面时的流程.如果你所在的微信聊天窗口出现红包,则不会执行步骤1,而是直接执行2,3,4.如果是在微信好友列表时,收到红包,则会在列表项中显示[微信红包],需要点即该列表项,进入聊天界面,随后执行2,3,4.为了方便演示,这里我们暂时不考虑好友列表时出现红包的情况.
明白了抢红包流程,之后我们通过AccessibilityService获取通知栏信息及微信聊天窗口界面,继而通过模拟点击实现打开红包,抢红包等操作.
AccessibilityService配置如下:
具体实现代码如下:
public class RobService extends AccessibilityService {
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
handleNotification(event);
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
String className = event.getClassName().toString();
if (className.equals("com.tencent.mm.ui.LauncherUI")) {
getPacket();
} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) {
openPacket();
} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) {
* 处理通知栏信息
* 如果是微信红包的提示信息,则模拟点击
* @param event
private void handleNotification(AccessibilityEvent event) {
List texts = event.getText();
if (!texts.isEmpty()) {
for (CharSequence text : texts) {
String content = text.toString();
//如果微信红包的提示信息,则模拟点击进入相应的聊天窗口
if (content.contains("[微信红包]")) {
if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
Notification notification = (Notification) event.getParcelableData();
PendingIntent pendingIntent = notification.contentI
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
* 关闭红包详情界面,实现自动返回聊天窗口
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void close() {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
//为了演示,直接查看了关闭按钮的id
List infos = nodeInfo.findAccessibilityNodeInfosByViewId("@id/ez");
nodeInfo.recycle();
for (AccessibilityNodeInfo item : infos) {
item.performAction(AccessibilityNodeInfo.ACTION_CLICK);
* 模拟点击,拆开红包
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void openPacket() {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
//为了演示,直接查看了红包控件的id
List list = nodeInfo.findAccessibilityNodeInfosByViewId("@id/b9m");
nodeInfo.recycle();
for (AccessibilityNodeInfo item : list) {
item.performAction(AccessibilityNodeInfo.ACTION_CLICK);
* 模拟点击,打开抢红包界面
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void getPacket() {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
AccessibilityNodeInfo node = recycle(rootNode);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
AccessibilityNodeInfo parent = node.getParent();
while (parent != null) {
if (parent.isClickable()) {
parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
parent = parent.getParent();
* 递归查找当前聊天窗口中的红包信息
* 聊天窗口中的红包都存在"领取红包"一词,因此可根据该词查找红包
* @param node
public AccessibilityNodeInfo recycle(AccessibilityNodeInfo node) {
if (node.getChildCount() == 0) {
if (node.getText() != null) {
if ("领取红包".equals(node.getText().toString())) {
for (int i = 0; i & node.getChildCount(); i++) {
if (node.getChild(i) != null) {
recycle(node.getChild(i));
public void onInterrupt() {
protected void onServiceConnected() {
super.onServiceConnected();
上面的代码简单演示了抢红包的原理,为了方便起见,我直接通过findAccessibilityNodeInfosByViewId()获取制定id控件的信息.在实际中,这种方法不太可靠,到目前为止,微信已经改过几次相关控件的id了.
有童鞋问,怎么样知道该控件的id呢.其实很简单,android中已经为我们提供了相关的工具:在Android Studio中开启Android Device Monitor,选择设备后点击Dump View Hierarchy for UI Automator,如下:
稍等片刻之后,便会出现当前设备的窗口,在该窗口中点击相关控件,便会显示该控件的属性.借助该工具,可以帮我们快速的分析界面结构,帮助我们从其他app布局策略中学习.
我们用Dump View Hierarchy fZ喎"/kf/ware/vc/" target="_blank" class="keylink">vciBVSSBBdXRvbWF0b3K31s72wcTM7L3nw+bOotDFuuyw/NDFz6I6PGJyIC8+DQo8aW1nIGFsdD0="这里写图片描述" src="/uploadfile/Collfiles/26.jpg" title="\" />
抢红包界面:
实战:App自动安装
讲完了微信红包插件的实现原理,不难发现其本质是根据相关的界面状态,模拟后续的操作(比如点击等).
既然这样,那么我们完全可以利用该服务实现更多的功能,比如apk自动安装,传统的安装过程大概是如下流程:
点击apk文件,弹出安装信息界面,在该界面点击”下一步”,然后在点击”安装”,最后在安装完成界面点击”完成”.该流程完全可以通过模拟点击操作完成.现在我们简单的讲一下AccessibilityService在这方面的具体应用.
我们知道系统的安装程序PackageInstaller的报名是,其package name 是com.android.packageinstaller,那么我们只需要监听该package下的安装信息界面和安装完成界面,并模拟点击”下一步”,”安装”,完成”“操作即可.
AccessibilityService配置如下:
具体实现代码如下:
public class InstallService extends AccessibilityService {
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d("InstallService", event.toString());
checkInstall(event);
private void checkInstall(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if (source != null) {
boolean installPage = event.getPackageName().equals("com.android.packageinstaller");
if (installPage) {
installAPK(event);
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void installAPK(AccessibilityEvent event) {
AccessibilityNodeInfo source = getRootInActiveWindow();
List nextInfos = source.findAccessibilityNodeInfosByText("下一步");
nextClick(nextInfos);
List installInfos = source.findAccessibilityNodeInfosByText("安装");
nextClick(installInfos);
List openInfos = source.findAccessibilityNodeInfosByText("打开");
nextClick(openInfos);
runInBack(event);
private void runInBack(AccessibilityEvent event) {
event.getSource().performAction(AccessibilityService.GLOBAL_ACTION_BACK);
private void nextClick(List infos) {
if (infos != null)
for (AccessibilityNodeInfo info : infos) {
if (info.isEnabled() && info.isClickable())
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private boolean checkTilte(AccessibilityNodeInfo source) {
List infos = getRootInActiveWindow().findAccessibilityNodeInfosByViewId("@id/app_name");
for (AccessibilityNodeInfo nodeInfo : infos) {
if (nodeInfo.getClassName().equals("android.widget.TextView")) {
public void onInterrupt() {
protected void onServiceConnected() {
Log.d("InstallService", "auto install apk");
实战:检测前台服务:
在很多情况下,我们需要检测自己的app是不是处在前台,借助该服务同样也能够完成该检测操作.
下面,我们就演示一下如何实现:
AccessibilityService配置如下:
具体实现代码如下:
public class DetectionService extends AccessibilityService {
private static volatile String foregroundPackageName = "error";
* 检测是否是前台服务
* @param packagenName
public static boolean isForeground(String packagenName) {
return foregroundPackageName.equals(packagenName);
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
foregroundPackageName = event.getPackageName().toString();
public void onInterrupt() {
在使用时,需要引导用于开启该服务,然后通过调用DetectionService.isForeground()即可.
上面的所有示例演示的都是AccessibilityService在具体应用中发挥的良好作用.但是该服务也存在一定的风险,很多人利用该服务做一些”坏事”,比如窃取短信验证码,窃取短信内容,想要看看自己女朋友最近在和谁聊QQ等等.
你现在是不是想能否借助该服务直接获取一些app的密码呢?凡是EditText中设置inputType为password类型的,都无法获取其输入值.除此之外,大多数软件都针对该中风险做了提前的防范.因此,你想要借助该服务来实现窃取密码还是比较有难度的.
暂时先到这里,后面再补充其他的吧.其实该服务能做的事情远不止这些,比如也可以通过该服务获取微信公众号的key,进而爬去文章数,也可借助该服务做自动化UI测试等.安卓微信抢红包控制尾数大小作弊插件
点击图片查看原图
安卓微信抢红包控制尾数大小作弊插件
发货期限:
自买家付款之日起
3 天内发货
更新时间:
联系人李经理(先生)&客服
会员 [当前离线]
电话手机地区广东-广州市
地址广东省广州市
【透视普通杯碗骰子透视仪&】【透视普通塑料杯碗硬币透视仪&】产品介绍:
产品主要结构:
& & 1.成像器
1-1:16*18平板高清成像器
1-2:成像器厚约3公分
1-3:支持小包携带
2: X光射线装置
& &2-1:尺寸198mm&&P45mm(可按客户需要改变尺寸大小)
& &2-2:X光射线源装有射线防护板,不会影响人体健康
&2-3:支持小包携带
3:手机、平板实时显示
3-1:实时传送,无线接收,显示清晰。
3-2:支持空旷区域200米内无线传送
3-3:客户如有特殊传送距离需要可加装中转设备
产品适用范围:
微型X光看穿机可看穿如陶瓷、金属、竹木、铜管、纤维、橡胶、塑料等介质。还可对陶瓷壶、陶瓷工艺品、木制工艺品、金属物、衣物、毛巾、塑料桶等物品进行实时看穿或检测。&
配件组成及使用方法:
设备主要由X射线源端和成像探测器端组成,待看穿物置于X射线源与探测器端之间,放置方位大致&三点一线&对齐,其中X射线源端与探测器端的距离在1.2-1.8米最佳。本仪器配置了专用的小型液晶显示屏、无线控制器、视频发射器、锂离子电池、中转终端组件。
标准型机器详细参数:
主要参数:
看穿范围:
成像尺寸:
成像尺寸:
显像部分:
显像设备:
外连监视器/微型液晶显示屏
像元尺寸:
屏幕亮度:
>6cd/cm²
灰度等级:
图像格式:
传输方式:
无线传输:最大200M&可增强至1000M
设备规格:
外形结构:
分体式主机
外形尺寸:
射线源部分:198mm&&P45mm
成像探测器:98mm&90mm&79mm&支持定制更小的外形
锂离子电池组供电
扩展端口:
A/V输出&USB输出(可选)
外观颜色:
全套组成:
X射线机主机/电源适配器/线控踏板开关/射线防护板
【普通扑克牌光感分析仪&】【普通扑克牌光感分析仪&】
产品介绍: 最新扑克感应器,瞬间识别扑克牌大小,适合三公,炸金花,斗牛,二八杠,梭哈,十点半,双十,两张,四张,十三张,十三水等扑克玩法。
1、桌面不需要放任何东西、不需要专用桌子、不需要扫描镜头、不需要提早装置任何东西。
2、用户能够经过分析的成果知道任何一家牌的大小、以便调整出牌办法、并主动报生死门!
3、不受场所约束,不受距离约束,感应报牌规模可达2米以上。
4、包牌速度秒杀,1秒即可辨认分析报出成果,精确率达100%。
5、产品外观规划时髦大方,而且合适全国各地玩法,可玩筒子、牌九、板九等各种游戏,
最新扑克感应器,瞬间识别扑克牌大小,它是在普通的扑克牌上涂上这个特殊的药物,然后身上带着一个感应器,里面是大牌或者是小牌还是大小,震动器就会通过震动的频率来通知玩家,这样,你就可以轻易的知道里面的扑克牌的点数了,十分的方便。
最新扑克感应器,瞬间识别扑克牌大小,我公司扑克新产品有:扑克感应器,扑克牌感应器,最新扑克感应器,扑克感应分析仪,感应分析设备,感应,番摊分析仪,番摊感应器等。都是你玩牌最理想的产品。
买最好用的单人操作扑克感应器,就来新科技牌具 ,我公司的任意一款牌具产品质量绝对的顶呱呱,包你用了说好。我公司以质量求生存,以信誉求发展,欢迎各位来我公司看货。
产品介绍:
1:选牌快速:采用日本悬浮技术,彻底解决选牌程序选牌慢的问题。
2:超级静音:采用轿车降噪技术,配合纳米隔音材料,彻底解决选牌时掉牌的噪音。
3:进牌口没有选牌架,将选牌架与麻将机整体设计,外观更隐蔽、选牌更准确。
4:一体化麻将机免掉客户自己安装选牌程序难且麻烦、复杂的工序;万种牌型变化,满足客户多种需求。
5:匠心工艺:将选牌程序自动打色面控线、色子控制线圈与麻将机按键面板设计为美观隐蔽。
6:操作简单:无需遥控器操作,开、关机查找、控色、程序转换全部在麻将机上完成,真正的单人操作。
7:配套附件:可以选择新型无孔万能程序麻将,避免有孔程序麻将易磨损掉针露孔、封口处及表面有色差、易脏、无光泽等弊病。
8:款式多样:客户可以根据自己的喜好和各地玩法,选择您需要的万能一体化麻将机。
9:严谨质检:从原材料购进到生产成品出库,层层把关,以杜绝不合格产品流入市场。
操作步骤:&
一:坐在麻将机位置上,按四下A键(这样麻将机就会自己启动程序。来采集麻将机发出的电磁&
波,来辨别麻将机的品牌型号,然后在遥控来完成!采集电磁波所需要的时间基本三秒!)&
二:确定方位,按住B键三秒不放,仪器就会自动识别您所在的位置
三:操作C键确定进行程序选择(按设置好的程序按键选择)
四:游戏开始(在玩的时候也可以遥控程序)
五:游戏结束,直接按两下D键!(智能芯片就会自动关闭接收
本文网址:从抢红包插件谈AccessibilityService
从抢红包插件谈AccessibilityService
从抢红包插件谈AccessibilityService
来源:代码之道,编程之法&&
微信红包自打出世以来就极其受欢迎,抢红包插件可谓红极一时.今天,我们重新谈谈抢红包插件的哪些事儿.本质上,抢红包插件的原理不难理解,其过程就是在收到红包时,自动模拟点击.做过自动化UI测试的童鞋应该非常熟悉了.
那么问题来了,我们怎么知道有没有红包,又怎么模拟点击操作呢?在PC端我们有按键精灵,那么在Android设备上呢?话说也偶然,Google为了让Android系统更实用,为用户提供了无障碍辅助服务—AccessibilityService.
AccessibilityService运行在后台,并且能够收到由系统发出的一些事件(AccessibilityEvent),比如焦点改变,输入内容变化,按钮被点击了等等,换言之,界面中产生的任何变化都会产生一个时间,并由系统通知给AccessibilityService.这就像监视器监视着界面的一举一动,一旦界面发生变化,立刻发出警报.另外,该服务不受系统重启的的影响.除非你手动关闭或者通过第三方安全软件将其强制关闭.
现在让我们来看看如何AccessibilityService的基本使用.
1. 创建服务类
和Service类似,要使用该服务,首先创建继承子AccessibilityService子类:
?123456789101112131415161718&code class="hljs java"&public class RobService extends AccessibilityService {&&&&@Override&&&&public void onAccessibilityEvent(AccessibilityEvent event) {&&&&&&&&//handle &&&&}&&&&@Override&&&&public void onInterrupt() {&&&&}&&&&@Override&&&&protected void onServiceConnected() {&&&&}&/code&
简单的介绍这两个常用的方法:
onServiceConnected():服务启动成功后执行该方法,通常我们会在这里做一些初始化的操作.除此之外,也可以在该方法中为AccessibilityServiceInfo设置AccessibilityService参数
onAccessibilityEvent():系统通过sendAccessibiliyEvent()不断的发送AccessibilityEvent,onAccessibilityEvent()中可以捕获到这些事件,进而根据不同的事件进行处理.该方法是整个服务的核心方法.
2. 配置服务类
AccessibilityService是一个特殊的Service服务,同样需要在manifest.xml中声明该Service.另外在版本4.1之后,该Service需要BIND_ACCESSIBILITY_SERVICE权限,因此其基本配置如下:
?123456&code class="language-java hljs "& &service android:enabled="true" android:exported="true" android:name=".RobService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&&&&&&&&&&&&&&intent-filter&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/action&&/intent-filter&&&&&&&&&&/service&&/code&
和普通的Service不同,该服务不能通过普通的startService()方法启动,而是由系统自行识别.为了让系统能够该服务,还需要为该服务配置响应的参数信息.在4.0系统之前,我们通过setServiceInfo()方法在运行时为其设置配置信息,而在4.0之后,可以在manifest.xml中通过来为其配置信息.
先来看如何通过setServiceInfo()为其配置信息,这就用到了上面onServiceConnected()方法:
?123456789&code class="language-java hljs "& @Override&&&&protected void onServiceConnected() {&&&&&&&&AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();&&&&&&&&serviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;&&&&&&&&serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;&&&&&&&&serviceInfo.packageNames = new String[]{"com.tencent.mm"}; &&&&&&&&serviceInfo.notificationTimeout=100;&&&&&&&&setServiceInfo(serviceInfo);&&&&}&/code&
再来看看如何通过来配置:
首先,我们在上面标签中添加元素,然后通过android:resource指定相应的配置文件(在res目录下创建xml文件,并在其中创建配置文件accessibility.xml):
?12345678&code class="hljs xml"& &service android:enabled="true" android:exported="true" android:name=".RobService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&&&&&&&&&&&&&&intent-filter&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/action&&/intent-filter&&&&&&&&&&&&&&meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility"&&&&&&&&&&/meta-data&&/service&&/code&
接下来我们来看accessibility.xml的相关配置:
?12&code class="hljs xml"&&!--?xml version="1.0" encoding="utf-8"?--&&/accessibility-service&&/code&
为了方便理解,我们快速的对其中的一些重要属性进行说明:
accessibilityEventTypes:表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如滑动,焦点变化,长按等.具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知.
accessibilityFeedbackType:表示反馈方式,比如是语音播放,还是震动
canRetrieveWindowContent:表示该服务能否访问活动窗口中的内容.也就是如果你希望在服务中获取窗体内容的化,则需要设置其值为true.
notificationTimeout:接受事件的时间间隔,通常将其设置为100即可.
packageNames:表示对该服务是用来监听哪个包的产生的事件
多数情况下,我们使用配置文件的方式来配置AccessibilityService即可.
3. 启动服务
当我们做完以上操作,便可将app安装到手机.安装成功后,在设置-&辅助功能中便可以找到我们的服务.该服务默认处在关闭状态,需要手动开启.
4. 获取事件信息
上面我们说道,onAccessibilityEvent(AccessibilityEvent event)是该服务的核心方法,其中参数event封装来自界面相关事件的信息,比如我们可以获得该事件的事件类型,进而根据起类型选择不同的处理方式:
?123456789101112&code class="hljs cs"& public void onAccessibilityEvent(AccessibilityEvent event) {&&&&&&&&int eventType = event.getEventType();&&&&&&&&switch (eventType) {&&&&&&&&&&&&case AccessibilityEvent.TYPE_VIEW_CLICKED:&&&&&&&&&&&&&&&&//界面点击&&&&&&&&&&&&&&&&break;&&&&&&&&&&&&case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:&&&&&&&&&&&&&&&&//界面文字改动&&&&&&&&&&&&&&&&break;&&&&&&&&}&&&&}&/code&
5. 获取控件信息
仅仅知道事件的信息是不够的,我们还希望通过事件来获取发出该事件(事件源)的信息,比如Button按钮被点击时它的text.
正如上面所提到的,要想获取控件的相关信息,在配置AccessibilityService时设置其canRetrieveWindowContent属性.之后,我们便可以通过event.getSource()来获取事件源.同样,我们也可以通过getRootInActiveWindow()来获取当前活动窗口的根节点.
那么什么是活动窗口呢?
所谓的活动窗口是用户当前触摸的窗口,或者在没有触摸状态下带有输入焦点的窗口.
6. 检测服务是否开启
简单了介绍了一些AccessibilityService的基础知识,想必到现在已经了解了如何去用了.但是这里我还是要补充一点关于检测某个服务是否开启的知识,通常来说大体有一下两种方法来检测:
方法一:借助服务管理器AccessibilityManager来判断,但是该方法不能检测app本身开启的服务.
?1234567891011121314&code class="hljs lasso"&private boolean enabled(String name) {&&&&&&&&AccessibilityManager am = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);&&&&&&&&List serviceInfos = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC);&&&&&&&&List installedAccessibilityServiceList = am.getInstalledAccessibilityServiceList();&&&&&&&&for (AccessibilityServiceInfo info : installedAccessibilityServiceList) {&&&&&&&&&&&&Log.d("MainActivity", "all --&" + info.getId());&&&&&&&&&&&&if (name.equals(info.getId())) {&&&&&&&&&&&&&&&&return true;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&return false;&&&&}&/accessibilityserviceinfo&&/accessibilityserviceinfo&&/code&
方法二:我们知道大部分的系统属性都在settings中进行设置,比如wifi,蓝牙状态等,而这些信息主要是存储在settings对应的的中(system表和serure表),同样我们也可以通过直接读取setting设置来判断相关服务是否开启:
?123456789101112131415161718192021222324&code class="hljs avrasm"&private boolean checkStealFeature1(String service) {&&&&&&&&int ok = 0;&&&&&&&&try {&&&&&&&&&&&&ok = Settings.Secure.getInt(getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);&&&&&&&&&&&&Log.d("MainActivity", "accessibilityEnabled :" + ok);&&&&&&&&} catch (Settings.SettingNotFoundException e) {&&&&&&&&&&&&Log.d("MainActivity", "Error finding setting,default accessibility to not found:" + e.getMessage());&&&&&&&&}&&&&&&&&TextUtils.SimpleStringSplitter ms = new TextUtils.SimpleStringSplitter(':');&&&&&&&&if (ok == 1) {&&&&&&&&&&&&String settingValue = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);&&&&&&&&&&&&if (settingValue != null) {&&&&&&&&&&&&&&&&ms.setString(settingValue);&&&&&&&&&&&&&&&&while (ms.hasNext()) {&&&&&&&&&&&&&&&&&&&&String accessibilityService = ms.next();&&&&&&&&&&&&&&&&&&&&if (accessibilityService.equalsIgnoreCase(service)) {&&&&&&&&&&&&&&&&&&&&&&&&return true;&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&/code&
到现在有关AccessibilityService的一些知识,我们已经讲完,下面我们就看它的具体使用,其中典型的应用就是抢红包插件.
实战:红包插件
先回顾一下抢红包的的流程:
1. 状态栏出现”[微信红包]”的消息提示,点击进入聊天界面
2. 点击相应的红包信息,弹出抢红包界面
3. 在抢红包界面点击”开”,打开红包
4. 在红包详情页面,查看详情,点击返回按钮返回微信聊天界面.
以上是不在微信聊天界面时的流程.如果你所在的微信聊天窗口出现红包,则不会执行步骤1,而是直接执行2,3,4.如果是在微信好友列表时,收到红包,则会在列表项中显示[微信红包],需要点即该列表项,进入聊天界面,随后执行2,3,4.为了方便演示,这里我们暂时不考虑好友列表时出现红包的情况.
明白了抢红包流程,之后我们通过AccessibilityService获取通知栏信息及微信聊天窗口界面,继而通过模拟点击实现打开红包,抢红包等操作.
AccessibilityService配置如下:
?12&code class="hljs xml"&&!--?xml version="1.0" encoding="utf-8"?--&&/accessibility-service&&/code&
具体实现代码如下:
?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143&code class="hljs java"&public class RobService extends AccessibilityService {&&&&@Override&&&&public void onAccessibilityEvent(AccessibilityEvent event) {&&&&&&&&int eventType = event.getEventType();&&&&&&&&switch (eventType) {&&&&&&&&&&&&case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:&&&&&&&&&&&&&&&&handleNotification(event);&&&&&&&&&&&&&&&&break;&&&&&&&&&&&&case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:&&&&&&&&&&&&case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:&&&&&&&&&&&&&&&&String className = event.getClassName().toString();&&&&&&&&&&&&&&&&if (className.equals("com.tencent.mm.ui.LauncherUI")) {&&&&&&&&&&&&&&&&&&&&getPacket();&&&&&&&&&&&&&&&&} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) {&&&&&&&&&&&&&&&&&&&&openPacket();&&&&&&&&&&&&&&&&} else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) {&&&&&&&&&&&&&&&&&&&&close();&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&break;&&&&&&&&}&&&&}&&&&/**&&&&&* 处理通知栏信息&&&&&*&&&&&* 如果是微信红包的提示信息,则模拟点击&&&&&*&&&&&* @param event&&&&&*/&&&&private void handleNotification(AccessibilityEvent event) {&&&&&&&&List&charsequence& texts = event.getText();&&&&&&&&if (!texts.isEmpty()) {&&&&&&&&&&&&for (CharSequence text : texts) {&&&&&&&&&&&&&&&&String content = text.toString();&&&&&&&&&&&&&&&&//如果微信红包的提示信息,则模拟点击进入相应的聊天窗口&&&&&&&&&&&&&&&&if (content.contains("[微信红包]")) {&&&&&&&&&&&&&&&&&&&&if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {&&&&&&&&&&&&&&&&&&&&&&&&Notification notification = (Notification) event.getParcelableData();&&&&&&&&&&&&&&&&&&&&&&&&PendingIntent pendingIntent = notification.contentI&&&&&&&&&&&&&&&&&&&&&&&&try {&&&&&&&&&&&&&&&&&&&&&&&&&&&&pendingIntent.send();&&&&&&&&&&&&&&&&&&&&&&&&} catch (PendingIntent.CanceledException e) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&e.printStackTrace();&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&/**&&&&&* 关闭红包详情界面,实现自动返回聊天窗口&&&&&*/&&&&@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)&&&&private void close() {&&&&&&&&AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();&&&&&&&&if (nodeInfo != null) {&&&&&&&&&&&&//为了演示,直接查看了关闭按钮的id&&&&&&&&&&&&List infos = nodeInfo.findAccessibilityNodeInfosByViewId("@id/ez");&&&&&&&&&&&&nodeInfo.recycle();&&&&&&&&&&&&for (AccessibilityNodeInfo item : infos) {&&&&&&&&&&&&&&&&item.performAction(AccessibilityNodeInfo.ACTION_CLICK);&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&/**&&&&&* 模拟点击,拆开红包&&&&&*/&&&&@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)&&&&private void openPacket() {&&&&&&&&AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();&&&&&&&&if (nodeInfo != null) {&&&&&&&&&&&&//为了演示,直接查看了红包控件的id&&&&&&&&&&&&List list = nodeInfo.findAccessibilityNodeInfosByViewId("@id/b9m");&&&&&&&&&&&&nodeInfo.recycle();&&&&&&&&&&&&for (AccessibilityNodeInfo item : list) {&&&&&&&&&&&&&&&&item.performAction(AccessibilityNodeInfo.ACTION_CLICK);&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&/**&&&&&* 模拟点击,打开抢红包界面&&&&&*/&&&&@TargetApi(Build.VERSION_CODES.JELLY_BEAN)&&&&private void getPacket() {&&&&&&&&AccessibilityNodeInfo rootNode = getRootInActiveWindow();&&&&&&&&AccessibilityNodeInfo node = recycle(rootNode);&&&&&&&&node.performAction(AccessibilityNodeInfo.ACTION_CLICK);&&&&&&&&AccessibilityNodeInfo parent = node.getParent();&&&&&&&&while (parent != null) {&&&&&&&&&&&&if (parent.isClickable()) {&&&&&&&&&&&&&&&&parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);&&&&&&&&&&&&&&&&break;&&&&&&&&&&&&}&&&&&&&&&&&&parent = parent.getParent();&&&&&&&&}&&&&}&&&&/**&&&&&* 递归查找当前聊天窗口中的红包信息&&&&&*&&&&&* 聊天窗口中的红包都存在"领取红包"一词,因此可根据该词查找红包&&&&&* &&&&&* @param node&&&&&*/&&&&public AccessibilityNodeInfo recycle(AccessibilityNodeInfo node) {&&&&&&&&if (node.getChildCount() == 0) {&&&&&&&&&&&&if (node.getText() != null) {&&&&&&&&&&&&&&&&if ("领取红包".equals(node.getText().toString())) {&&&&&&&&&&&&&&&&&&&&return &&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&} else {&&&&&&&&&&&&for (int i = 0; i & node.getChildCount(); i++) {&&&&&&&&&&&&&&&&if (node.getChild(i) != null) {&&&&&&&&&&&&&&&&&&&&recycle(node.getChild(i));&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&return &&&&}&&&&@Override&&&&public void onInterrupt() {&&&&}&&&&@Override&&&&protected void onServiceConnected() {&&&&&&&&super.onServiceConnected();&&&&}}&/accessibilitynodeinfo&&/accessibilitynodeinfo&&/charsequence&&/code&
上面的代码简单演示了抢红包的原理,为了方便起见,我直接通过findAccessibilityNodeInfosByViewId()获取制定id控件的信息.在实际中,这种方法不太可靠,到目前为止,微信已经改过几次相关控件的id了.
有童鞋问,怎么样知道该控件的id呢.其实很简单,android中已经为我们提供了相关的工具:在Android Studio中开启Android Device Monitor,选择设备后点击Dump View Hierarchy for UI Automator,如下:
稍等片刻之后,便会出现当前设备的窗口,在该窗口中点击相关控件,便会显示该控件的属性.借助该工具,可以帮我们快速的分析界面结构,帮助我们从其他app布局策略中学习.
我们用Dump View Hierarchy for UI Automator分析聊天界面微信红包信息:
抢红包界面:
实战:App自动安装
讲完了微信红包插件的实现原理,不难发现其本质是根据相关的界面状态,模拟后续的操作(比如点击等).
既然这样,那么我们完全可以利用该服务实现更多的功能,比如apk自动安装,传统的安装过程大概是如下流程:
点击apk文件,弹出安装信息界面,在该界面点击”下一步”,然后在点击”安装”,最后在安装完成界面点击”完成”.该流程完全可以通过模拟点击操作完成.现在我们简单的讲一下AccessibilityService在这方面的具体应用.
我们知道系统的安装程序PackageInstaller的报名是,其package name 是com.android.packageinstaller,那么我们只需要监听该package下的安装信息界面和安装完成界面,并模拟点击”下一步”,”安装”,完成”“操作即可.
AccessibilityService配置如下:
?123&code class="hljs xml"&&!--?xml version="1.0" encoding="utf-8"?--&&/accessibility-service&&/code&
具体实现代码如下:
?1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768&code class="hljs java"&public class InstallService extends AccessibilityService {&&&&@Override&&&&public void onAccessibilityEvent(AccessibilityEvent event) {&&&&&&&&Log.d("InstallService", event.toString());&&&&&&&&checkInstall(event);&&&&}&&&&private void checkInstall(AccessibilityEvent event) {&&&&&&&&AccessibilityNodeInfo source = event.getSource();&&&&&&&&if (source != null) {&&&&&&&&&&&&boolean installPage = event.getPackageName().equals("com.android.packageinstaller");&&&&&&&&&&&&if (installPage) {&&&&&&&&&&&&&&&&installAPK(event);&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&@TargetApi(Build.VERSION_CODES.JELLY_BEAN)&&&&private void installAPK(AccessibilityEvent event) {&&&&&&&&AccessibilityNodeInfo source = getRootInActiveWindow();&&&&&&&&List nextInfos = source.findAccessibilityNodeInfosByText("下一步");&&&&&&&&nextClick(nextInfos);&&&&&&&&List installInfos = source.findAccessibilityNodeInfosByText("安装");&&&&&&&&nextClick(installInfos);&&&&&&&&List openInfos = source.findAccessibilityNodeInfosByText("打开");&&&&&&&&nextClick(openInfos);&&&&&&&&runInBack(event);&&&&}&&&&private void runInBack(AccessibilityEvent event) {&&&&&&&&event.getSource().performAction(AccessibilityService.GLOBAL_ACTION_BACK);&&&&}&&&&private void nextClick(List infos) {&&&&&&&&if (infos != null)&&&&&&&&&&&&for (AccessibilityNodeInfo info : infos) {&&&&&&&&&&&&&&&&if (info.isEnabled() && info.isClickable())&&&&&&&&&&&&&&&&&&&&info.performAction(AccessibilityNodeInfo.ACTION_CLICK);&&&&&&&&&&&&}&&&&}&&&&@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)&&&&private boolean checkTilte(AccessibilityNodeInfo source) {&&&&&&&&List infos = getRootInActiveWindow().findAccessibilityNodeInfosByViewId("@id/app_name");&&&&&&&&for (AccessibilityNodeInfo nodeInfo : infos) {&&&&&&&&&&&&if (nodeInfo.getClassName().equals("android.widget.TextView")) {&&&&&&&&&&&&&&&&return true;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&return false;&&&&}&&&&@Override&&&&public void onInterrupt() {&&&&}&&&&@Override&&&&protected void onServiceConnected() {&&&&&&&&Log.d("InstallService", "auto install apk");&&&&}}&/accessibilitynodeinfo&&/accessibilitynodeinfo&&/accessibilitynodeinfo&&/accessibilitynodeinfo&&/accessibilitynodeinfo&&/code&
实战:检测前台服务:
在很多情况下,我们需要检测自己的app是不是处在前台,借助该服务同样也能够完成该检测操作.
下面,我们就演示一下如何实现:
AccessibilityService配置如下:
?12&code class="hljs xml"&&!--?xml version="1.0" encoding="utf-8"?--&&/accessibility-service&&/code&
具体实现代码如下:
?123456789101112131415161718192021222324252627&code class="language-java hljs "&public class DetectionService extends AccessibilityService {&&&&private static volatile String foregroundPackageName = "error";&&&&/**&&&&&* 检测是否是前台服务&&&&&*&&&&&* @param packagenName&&&&&* @return&&&&&*/&&&&public static boolean isForeground(String packagenName) {&&&&&&&&return foregroundPackageName.equals(packagenName);&&&&}&&&&@Override&&&&public void onAccessibilityEvent(AccessibilityEvent event) {&&&&&&&&if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {&&&&&&&&&&&&foregroundPackageName = event.getPackageName().toString();&&&&&&&&}&&&&}&&&&@Override&&&&public void onInterrupt() {&&&&}}&/code&
在使用时,需要引导用于开启该服务,然后通过调用DetectionService.isForeground()即可.
上面的所有示例演示的都是AccessibilityService在具体应用中发挥的良好作用.但是该服务也存在一定的风险,很多人利用该服务做一些”坏事”,比如窃取短信验证码,窃取短信内容,想要看看自己女朋友最近在和谁聊QQ等等.
你现在是不是想能否借助该服务直接获取一些app的密码呢?凡是EditText中设置inputType为password类型的,都无法获取其输入值.除此之外,大多数软件都针对该中风险做了提前的防范.因此,你想要借助该服务来实现窃取密码还是比较有难度的.
暂时先到这里,后面再补充其他的吧.其实该服务能做的事情远不止这些,比如也可以通过该服务获取微信公众号的key,进而爬去文章数,也可借助该服务做自动化UI测试等.
发表评论:
馆藏&20662
TA的最新馆藏}

我要回帖

更多关于 微信群出现外人抢红包 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信