hi大家好。
新年又来了,微信群里又是各种红包横飞。作为技术人员的我们却大可不必担心一不小心,手速慢了点,又错过了几十万。我们可以通过安卓的辅助功能来实现自己的微信自动抢红包,安全又快捷。
辅助服务
我们在 设置->无障碍 中,就可以看到手机中所有的辅助服务了。辅助功能通常是针对一些视力听力等有障碍导致使用手机有障碍的人群,做一些语言提醒等帮助他们更好地使用手机。
因为辅助功能可以得到系统级别的事件和服务,第三方应用的辅助功能都需要手动开启。我们常用的绿色守护,冰箱等应用都是利用辅助服务实现的。
我们先来实现一个简单的辅助服务吧。
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);
}
我们的抢红包之旅到这里就告一段落了,结束的是一次艰苦的撸代码的时光,开启的是千千万万次自动抢红包的快感。
最后,祝大家新年 大 吉 吧!