AccessibilityService类使用和抢红包功能的实现
来源:互联网 发布:java 高性能 并发库 编辑:程序博客网 时间:2024/04/27 17:39
2017.3.24日可用!以下是代码和说明
AndroidManifest.xml声明
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <service android:name="com.zhonglou.showtencent.Server.RobServer" android:label="@string/accessibility_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/accessibility" /> </service>
accessibility.xml
android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_description" android:notificationTimeout="100" android:packageNames="com.tencent.mm"
重要属性说明:
1.accessibilityEventTypes:表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如窗口打开,滑动,焦点变化,长按等.具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知.2.accessibilityFeedbackType:表示反馈方式,比如是语音播放,还是震动3.canRetrieveWindowContent:表示该服务能否访问活动窗口中的内容.也就是如果你希望在服务中获取窗体内容的化,则需要设置其值为true.4.notificationTimeout:接受事件的时间间隔,通常将其设置为100即可.5.packageNames:表示对该服务是用来监听哪个包的产生的事件
RobServer.java
/** 该类提供的方法 * getRootInActiveWindow() 如果配置能够获取窗口内容,则会返回当前活动窗口的根结点 * getSystemService(String name)获取系统服务 * onAccessibilityEvent(AccessibilityEvent event) 有关AccessibilityEvent事件的回调函数.系统通过sendAccessibiliyEvent()不断的发送AccessibilityEvent到此处 * onGesture() * onKeyEvent(KeyEvent event)如果允许服务监听按键操作,该方法是按键事件的回调,需要注意,这个过程发生了系统处理按键事件之前 * onServiceConnected()系统成功绑定该服务时被触发,通常我们可以在这里做一些初始化操作 */public class RobServer extends AccessibilityService { private boolean newPacket = false;//有没新红包 private boolean enableKeyguard = true;//默认有屏幕锁 //锁屏、解锁相关 private KeyguardManager km; private KeyguardManager.KeyguardLock kl; //唤醒屏幕相关 private PowerManager pm; private PowerManager.WakeLock wl = null; //唤醒屏幕和解锁 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(); Log.i("demo", "加锁"); } //若之前唤醒过屏幕则释放之使屏幕不保持常亮 if(wl != null) { wl.release(); wl = null; Log.i("demo", "关灯"); } } } //初始化设置 @Override protected void onServiceConnected() { super.onServiceConnected(); //获取电源管理器对象 pm=(PowerManager)getSystemService(Context.POWER_SERVICE); //得到键盘锁管理器对象 km= (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE); //初始化一个键盘锁管理器对象 kl = km.newKeyguardLock("unLock"); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { /** AccessibilityEvent提供的方法 * getEventType() 获取事件类型 * getClassName() 获取事件源对应类的类型,比如点击事件是有某个Button产生的,那么此时获取的就是 * Button的完整类名 * getText() 获取事件源的文本信息,比如事件是有TextView发出的,此时获取的就是TextView的text属 * 性.如果该事件源是树结构,那么此时获取的是这个树上所有具有text属性的值的集合 * isEnabled() 事件源(对应的界面控件)是否处在可用状态 * getItemCount() 如果事件源是树结构,将返回该树根节点下子节点的数量 */ int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知栏事件 /**抢红包步骤:检测通知栏事件是否有[微信红包],有则打开. * 检测窗口改变事件,然后确定窗口是领红包界面,是则获取id/text */ List<CharSequence> text = event.getText(); if (!text.isEmpty()) { for (CharSequence text1 : text) { String content = text1.toString(); if (content.contains("[微信红包]") || content.contains("[QQ红包]")) { //检测content中是否有该字符 wakeAndUnlock(true); newPacket = true; //监听到微信红包的notification,打开通知 if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) { Notification notification = (Notification) event.getParcelableData(); PendingIntent pi = notification.contentIntent; try { pi.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } } } } break; case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: //窗口改变事件 String className = event.getClassName().toString(); if (className.equals("com.tencent.mm.ui.LauncherUI")) { if (newPacket){ getPacket(); // 领取红包 } } else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI")) { openPacket(); wakeAndUnlock(false); } else if (className.equals("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI")) { MoneyDetal(); //查看红包详情并退出 } break; } } /** * 关闭红包详情界面,实现自动返回聊天窗口 */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private void MoneyDetal() { /**思路:微信中使用uiautomatorviewer查看布局,发现不同的手机相同的控件id是不一样的,比如我们需要查询获取红包 的数量时,需要先查找'元',然后获取其父控件,然后查找金额所在的位置,这个是不变的。 */ AccessibilityNodeInfo rootNode = getRootInActiveWindow(); List<AccessibilityNodeInfo> list = new ArrayList<>();List<AccessibilityNodeInfo> list1 = rootNode.findAccessibilityNodeInfosByText("元"); list.addAll(list1); AccessibilityNodeInfo parent = list.get(0).getParent(); //群聊和私发不同,这是共同点 AccessibilityNodeInfo name = parent.getChild(0); AccessibilityNodeInfo money = parent.getChild(2); Log.d("classname", money.getText().toString()); Log.d("classname", name.getText().toString()); performBack(this); } /** * 模拟点击,拆开红包 */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void openPacket() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if (nodeInfo != null) { boolean isHave = false; int count = nodeInfo.getChildCount(); for (int i = 0; i < count; i++) { AccessibilityNodeInfo childNode = nodeInfo.getChild(i); if ("android.widget.Button".equals(childNode.getClassName())) { isHave = true; childNode.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } if (!isHave) { List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("看看大家的手气"); if (list != null && list.size() > 0) { performBack(this); } } nodeInfo.recycle(); } } /** * 模拟点击,打开抢红包界面 */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void getPacket() { AccessibilityNodeInfo rootinfo = getRootInActiveWindow(); List<AccessibilityNodeInfo> list = new ArrayList<>(); if (rootinfo != null &&rootinfo.getChildCount()>0){ List<AccessibilityNodeInfo> list1 = rootinfo.findAccessibilityNodeInfosByText("领取红包"); if (list1.size()>0){ list.addAll(list1); } for (int i = list.size() - 1; i >= 0; i--) { AccessibilityNodeInfo parent = list.get(i).getParent(); if (parent != null) { parent.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } rootinfo.recycle(); newPacket = false; } } //模拟返回事件 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void performBack(AccessibilityService service) { if(service == null) { return; } service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); } @Override public void onInterrupt() { Toast.makeText(this, "中断抢红包服务", Toast.LENGTH_SHORT) .show(); } @Override public void onDestroy() { super.onDestroy(); wakeAndUnlock(false); }}
注意事项,1.启动服务用intent启动,用的是startserver(intent)
别人图拿来用,Dump View Hierarchy for UI Automator可以获取你想要的class和布局方式,在DDMS那边。
扩展
2. APK自动安装
讲完了微信红包插件的实现原理,不难发现其本质是根据相关的界面状态,模拟后续的操作(比如点击等).
既然这样,那么我们完全可以利用该服务实现更多的功能,比如apk自动安装,传统的安装过程大概是如下流程:
点击apk文件,弹出安装信息界面,在该界面点击”下一步”,然后在点击”安装”,最后在安装完成界面点击”完成”.
不难发现,该流程完全可以通过模拟点击操作完成.现在我们简单的讲一下AccessibilityService在这方面的具体应用.我们知道系统的安装程序由PackageInstaller负责,其包名是com.android.packageinstaller,那么我们只需要监听该package下的安装信息界面和安装完成界面,并模拟点击”下一步”,”安装”,完成”“操作即可实现自动安装.
AccessibilityService配置如下:
<?xml version="1.0" encoding="utf-8"?><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/auto_service_des" android:notificationTimeout="100" android:packageNames="com.android.packageinstaller"/>
具体实现代码如下:
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<AccessibilityNodeInfo> nextInfos = source.findAccessibilityNodeInfosByText("下一步"); nextClick(nextInfos); List<AccessibilityNodeInfo> installInfos = source.findAccessibilityNodeInfosByText("安装"); nextClick(installInfos); List<AccessibilityNodeInfo> openInfos = source.findAccessibilityNodeInfosByText("打开"); nextClick(openInfos); runInBack(event); } private void runInBack(AccessibilityEvent event) { event.getSource().performAction(AccessibilityService.GLOBAL_ACTION_BACK); } private void nextClick(List<AccessibilityNodeInfo> 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<AccessibilityNodeInfo> 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"); }}
- 检测前台服务:
在很多情况下,我们需要检测自己的app是不是处在前台,借助该服务同样也能够完成该检测操作.下面,我们就演示一下如何实现:
AccessibilityService配置如下:
<?xml version="1.0" encoding="utf-8"?><accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/auto_detection" android:notificationTimeout="100"/>
具体实现代码如下:
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() { }}
在使用时,需要引导用户开启该服务,之后通过调用DetectionService.isForeground()即可.
TYPE_VIEW_CLICKED TYPE_VIEW_FOCUSED TYPE_VIEW_LONG_CLICKED TYPE_VIEW_SELECTED TYPE_VIEW_TEXT_CHANGED TYPE_WINDOW_STATE_CHANGED TYPE_NOTIFICATION_STATE_CHANGED TYPE_TOUCH_EXPLORATION_GESTURE_END TYPE_ANNOUNCEMENT TYPE_TOUCH_EXPLORATION_GESTURE_START TYPE_VIEW_HOVER_ENTER TYPE_VIEW_HOVER_EXIT TYPE_VIEW_SCROLLED TYPE_VIEW_TEXT_SELECTION_CHANGED TYPE_WINDOW_CONTENT_CHANGED
0 0
- AccessibilityService类使用和抢红包功能的实现
- AccessibilityService的学习,抢红包实现
- AccessibilityService之微信抢红包辅助功能实现
- 使用AccessibilityService实现微信自动抢红包
- 使用AccessibilityService实现微信自动抢红包
- 使用Android辅助服务AccessibilityService实现的微信自动抢红包的小程序
- 微信自动回复和自动抢红包实现原理(一):AccessibilityService的介绍和配置
- 微信自动回复和自动抢红包实现原理(一):AccessibilityService的介绍和配置
- Android利用AccessibilityService实现抢红包,微信自动回复等功能思路
- Android辅助功能AccessibilityService与抢红包辅助
- Android辅助功能AccessibilityService与抢红包辅助
- AccessibilityService实现微信抢红包插件
- Android AccessibilityService实现微信自动抢红包
- 利用辅助服务AccessibilityService实现微信自动抢红包
- 微信抢红包-AccessibilityService的用法。
- Android 通过AccessibilityService实现微信自动抢红包时如何过滤已抢红包
- 自动抢红包-辅助功能的使用
- 利用AccessibilityService实现“微信红包”插件
- Android Studio 2.3 签名打包问题
- thinking in java——0324学习笔记
- 案例五 、利用jQuery写一个弹幕
- Android中aapt使用详解
- Python异常处理
- AccessibilityService类使用和抢红包功能的实现
- You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
- 欧拉定理的应用
- swift3 多个异步网络请求转同步
- 从实例和源码角度理解 postInvalidate() 和 invalidate() 的区别与联系
- bzoj 2023 && bzoj 1630 dp+滚动数组
- APUE常用头文件
- c++实现单链表
- C++全局变量