背景
之所以产生这个项目,是因为:
1、之前在做小车时,想通过手机来控制小车的行径,所以得要先研究下Android开发
2、某次在码代码时,错过了群里的好几个大红包,于是想着,可不可以来个自动抢红包的,省的每次都去关注手机
于是乎,就出现了这个项目了。
同时由于对这个很感兴趣,想快速的完成,所以这两个星期就把小车放下了,专来研究抢红包。
一、应该要具备哪些知识点
基础快速掌握
不懂Android开发怎么办?
学!
先去网上搜索开发自动抢红包,需要哪些材料。
最后看了好几篇文章好,核心点是AccessibilityService这么个Android组件。
好,问题来了,AccessibilityService是什么鬼?
继续查找资料,但发现,看看了几篇文章后,还是看不懂,连建个Android Project都搞不了。
于是就从Android开发基础开始看起,
网上有很多的教程,我看的是“菜鸟教程–安卓开发”,
跟着这里的教程,用业余时间看了3-4天左右,只是看到了Service那章就停了,感觉应该是差不多可以动手了。
最后能达到的效果是:
1、能使用Android Studio创建工程
2、能编写多个Activity之间通信
3、能在Activity中启动Service,且能互相通讯
然后的重点就是去理解AccessibilityService
关于AccessibilityService的具体我就不详写了,网上有很多,推荐这篇写的蛮好的:http://www.jianshu.com/p/959217070c87
这个过程,会遇到很多问题,及新的知识点,也就要各个击破了,要认真的去查询资料。
这个期间,为了分别了解每个知识点,都实验了如下项目:
1、app的自动安装
2、微信的自动回复
能做到以上两个,基本上对开发抢红包就没有什么难度了。
现在总结,利用AccessibilityService进行相关的操作,就是要理解:
1、事件响应的处理
2、app每个控件的查找
其实,有做过前端开发和桌面开发的同学,就比较容易上手了,套路几乎是一致的。
(偷下懒,思维跨度太大了,就直接上代码了,代码里也有注释)
WxHongBaoService.java
package com.example.xxh.wxhongbao; import android.accessibilityservice.AccessibilityService; import android.app.Notification; import android.app.PendingIntent; import android.content.Intent; import android.util.Log; import android.view.KeyEvent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import java.io.IOException; import java.util.List; /** * Created by xxh on 2017/9/21. */ public class WxHongBaoService extends AccessibilityService { private final String TAG = "WXHONGBAO"; private void log(String msg) { Log.i(TAG, msg); } @Override protected void onServiceConnected() { super.onServiceConnected(); log("service connected"); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: doNotification(event); break; case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED: case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: //doWxHome(); findAndOpenHB(); clickHB(); quitDetaiHB(); break; } } @Override public void onInterrupt() { } /** * 模拟back按键 */ private void pressBackButton(){ AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if(nodeInfo == null) return;; List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/hc"); if(list != null && list.size() > 0) { for(AccessibilityNodeInfo n : list) { n.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } /** * 找红包 并打开红包 */ private void findAndOpenHB() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if(nodeInfo == null) return; List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/a8q"); // 红包整块 if(list != null && list.size() > 0) { for(AccessibilityNodeInfo n : list) { List<AccessibilityNodeInfo> noClick = n.findAccessibilityNodeInfosByText("领取红包"); // 未被领取 if(noClick != null && noClick.size() > 0) { for (AccessibilityNodeInfo n1 : noClick) { log("***********找到***********"); n.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } } } /** * 拆红包 */ private void clickHB() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if(nodeInfo == null) return;; List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/bp6"); if(list != null && list.size() > 0) { for(AccessibilityNodeInfo n : list) { log("***********拆开***********"); n.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } /** * 退出 红包详情页面 拆开红包后的页面 如果在此页面的话 有红包来 触发不了以上事件 */ private void quitDetaiHB() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if(nodeInfo == null) return;; List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("红包详情"); if(list != null && list.size() > 0) { log("退出红包详情"); pressBackButton(); back2Home(); } } /** * 在微信首页 打开聊天窗口 */ private void doWxHome() { AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); if(nodeInfo == null) return;; List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/aja"); if(list != null && list.size() > 0) { for(AccessibilityNodeInfo n : list) { List<AccessibilityNodeInfo> child = n.findAccessibilityNodeInfosByText("[微信红包]"); if(child!=null && child.size()>0) { log("***********打开窗口***********"); n.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } } /** * 响应通知事件, 如果是红包通知, 则进入聊天界面 */ private void doNotification(final AccessibilityEvent event) { if(event.getParcelableData() != null && event.getParcelableData() instanceof Notification) { Notification notification = (Notification)event.getParcelableData(); String content = notification.tickerText.toString(); log("接收到通知信息: " + content); int idx = content.indexOf("[微信红包]"); if(idx > 0) { PendingIntent pendingIntent = notification.contentIntent; try { pendingIntent.send(); }catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } } } /** * 回到系统桌面 */ private void back2Home() { Intent home = new Intent(Intent.ACTION_MAIN); home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); home.addCategory(Intent.CATEGORY_HOME); startActivity(home); } }
创建了一个主界面
MainActivity.java
package com.example.xxh.wxhongbao; import android.content.Intent; import android.provider.Settings; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private final String TAG = "MAINACTIVITY"; private Button open_service_btn; private void log(String msg) { Log.i(TAG, msg); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); open_service_btn = (Button)findViewById(R.id.open_service_btn); open_service_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 打开辅助服务 final String mAction = Settings.ACTION_ACCESSIBILITY_SETTINGS; Intent intent = new Intent(mAction); startActivity(intent); } }); if(isAccessibilitySettingsOn()) { Toast.makeText(this, "你的辅助服务已开启,现在就可以开心的抢红包了", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "你的辅助服务没开启,请开启", Toast.LENGTH_LONG).show(); } } /** * 判断辅助服务是否开启 */ private boolean isAccessibilitySettingsOn() { int isEnable = 0; final String service = getPackageName() + "/" + WxHongBaoService.class.getCanonicalName(); log(service); try { isEnable = Settings.Secure.getInt(getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED); } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } TextUtils.SimpleStringSplitter simpleStringSplitter = new TextUtils.SimpleStringSplitter(':');// 多个服务使用冒号隔开 if(isEnable == 1) { String settingValue = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); if(settingValue != null) { simpleStringSplitter.setString(settingValue); while (simpleStringSplitter.hasNext()) { String accessibilityServcie = simpleStringSplitter.next(); log("["+accessibilityServcie + "]"+accessibilityServcie.length()); log("["+service + "]"+service.length()); if(accessibilityServcie.equalsIgnoreCase(service)) { return true; } } } } return false; } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.xxh.wxhongbao" > <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.REORDER_TASKS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher1" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".WxHongBaoService" android:label="@string/app_name" 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> </application> </manifest>
res/xml/accessibility.xml Accessibility配置文件
<?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:packageNames="com.tencent.mm" android:notificationTimeout="100" />