WeChatLuckyMoney扩展开发指南:编写自定义插件
1. 插件开发概述
WeChatLuckyMoney作为一款高效的微信抢红包插件,提供了灵活的扩展机制允许开发者编写自定义插件。本指南将详细介绍插件开发的核心概念、架构设计和实现步骤,帮助开发者快速上手插件开发。
1.1 插件系统架构
WeChatLuckyMoney插件系统基于Android无障碍服务(Accessibility Service)构建,主要通过以下组件实现扩展功能:
1.2 开发环境准备
开发工具要求:
- Android Studio 4.0+
- Gradle 6.0+
- Android SDK API 21+ (Android 5.0+)
项目构建:
# 克隆仓库
git clone https://gitcode.com/gh_mirrors/we/WeChatLuckyMoney
# 构建项目
cd WeChatLuckyMoney
./gradlew assembleDebug
2. 核心API解析
2.1 无障碍事件处理
HongbaoService是抢红包功能的核心服务,通过onAccessibilityEvent方法接收系统事件:
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (sharedPreferences == null) return;
setCurrentActivityName(event);
/* 检测通知消息 */
if (!mMutex) {
if (sharedPreferences.getBoolean("pref_watch_notification", false) && watchNotifications(event)) return;
if (sharedPreferences.getBoolean("pref_watch_list", false) && watchList(event)) return;
mListMutex = false;
}
if (!mChatMutex) {
mChatMutex = true;
if (sharedPreferences.getBoolean("pref_watch_chat", false)) watchChat(event);
mChatMutex = false;
}
}
事件类型说明:
| 事件类型 | 描述 | 插件应用场景 |
|---|---|---|
| TYPE_WINDOW_STATE_CHANGED | 窗口状态变化 | 检测微信界面切换 |
| TYPE_WINDOW_CONTENT_CHANGED | 窗口内容变化 | 检测新消息或红包出现 |
| TYPE_NOTIFICATION_STATE_CHANGED | 通知状态变化 | 检测红包通知 |
2.2 红包识别与处理流程
红包识别的核心逻辑位于checkNodeInfo方法,通过节点分析识别红包:
private void checkNodeInfo(int eventType) {
if (this.rootNodeInfo == null) return;
// 聊天窗口红包识别
AccessibilityNodeInfo node1 = getTheLastNode(WECHAT_VIEW_OTHERS_CH);
if (node1 != null && signature.generateSignature(node1, excludeWords)) {
mLuckyMoneyReceived = true;
mReceiveNode = node1;
return;
}
// 拆红包按钮识别
AccessibilityNodeInfo node2 = findOpenButton(this.rootNodeInfo);
if (node2 != null && "android.widget.Button".equals(node2.getClassName())) {
mUnpackNode = node2;
mUnpackCount += 1;
return;
}
}
节点信息获取方法:
findAccessibilityNodeInfosByText(text): 按文本查找节点findAccessibilityNodeInfosByViewId(id): 按ID查找节点getRootInActiveWindow(): 获取当前窗口根节点
3. 插件开发步骤
3.1 创建插件基础类
创建自定义插件需继承BasePlugin类,实现核心方法:
public class CustomPlugin extends BasePlugin {
private static final String TAG = "CustomPlugin";
private boolean enabled = false;
public CustomPlugin(Context context) {
super(context);
enabled = prefs.getBoolean("custom_plugin_enabled", false);
}
@Override
public boolean processEvent(AccessibilityEvent event) {
if (!enabled) return false;
// 处理事件,返回true表示已消费事件
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
Log.d(TAG, "处理窗口内容变化事件");
// 自定义逻辑
return false; // 不中断原有处理流程
}
return false;
}
@Override
public View getConfigUI() {
// 创建插件配置界面
LinearLayout layout = new LinearLayout(context);
Switch switchBtn = new Switch(context);
switchBtn.setChecked(enabled);
switchBtn.setOnCheckedChangeListener((buttonView, isChecked) -> {
prefs.edit().putBoolean("custom_plugin_enabled", isChecked).apply();
enabled = isChecked;
});
layout.addView(switchBtn);
return layout;
}
}
3.2 插件注册与加载
在HongbaoService中添加插件加载逻辑:
private List<PluginInterface> plugins = new ArrayList<>();
private void loadPlugins() {
// 反射加载插件
try {
Class<?> pluginClass = Class.forName("xyz.monkeytong.hongbao.plugins.CustomPlugin");
PluginInterface plugin = (PluginInterface) pluginClass.getConstructor(Context.class)
.newInstance(this);
plugins.add(plugin);
Log.d(TAG, "插件加载成功: " + pluginClass.getSimpleName());
} catch (Exception e) {
Log.e(TAG, "插件加载失败", e);
}
}
// 在onServiceConnected中调用
@Override
public void onServiceConnected() {
super.onServiceConnected();
watchFlagsFromPreference();
loadPlugins(); // 加载插件
}
// 修改事件处理方法
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (sharedPreferences == null) return;
// 插件事件处理
for (PluginInterface plugin : plugins) {
if (plugin.processEvent(event)) {
return; // 如果插件消费了事件,终止处理
}
}
// 原有逻辑...
setCurrentActivityName(event);
// ...
}
3.3 插件配置界面集成
在设置界面添加插件配置入口,修改GeneralSettingsFragment:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.general_preferences);
// 添加插件配置
for (PluginInterface plugin : HongbaoService.getPlugins()) {
View pluginView = plugin.getConfigUI();
if (pluginView != null) {
Preference pluginPref = new Preference(getActivity());
pluginPref.setWidgetLayoutResource(R.layout.plugin_config_container);
getPreferenceScreen().addPreference(pluginPref);
}
}
}
4. 实用插件示例
4.1 延迟抢红包插件
实现红包延迟抢功能,避免被检测为机器人:
public class DelayGrabPlugin extends BasePlugin {
private int delayTime = 1000; // 默认延迟1秒
public DelayGrabPlugin(Context context) {
super(context);
delayTime = prefs.getInt("delay_grab_time", 1000);
}
@Override
public boolean processEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) return false;
// 查找红包节点
List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText("领取红包");
if (!nodes.isEmpty()) {
// 延迟抢红包
new Handler(Looper.getMainLooper()).postDelayed(() -> {
nodes.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
}, delayTime);
return true; // 消费事件,阻止默认抢红包逻辑
}
}
return false;
}
@Override
public View getConfigUI() {
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.HORIZONTAL);
TextView text = new TextView(context);
text.setText("延迟抢红包(毫秒):");
EditText edit = new EditText(context);
edit.setText(String.valueOf(delayTime));
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
edit.setOnEditorActionListener((v, actionId, event) -> {
try {
delayTime = Integer.parseInt(edit.getText().toString());
prefs.edit().putInt("delay_grab_time", delayTime).apply();
} catch (NumberFormatException e) {
// 处理无效输入
}
return true;
});
layout.addView(text);
layout.addView(edit);
return layout;
}
}
4.2 红包过滤插件
根据群聊名称或发送者过滤红包:
public class FilterPlugin extends BasePlugin {
private Set<String> filteredGroups = new HashSet<>();
private Set<String> filteredSenders = new HashSet<>();
public FilterPlugin(Context context) {
super(context);
loadFilters();
}
private void loadFilters() {
String groups = prefs.getString("filtered_groups", "");
String senders = prefs.getString("filtered_senders", "");
filteredGroups.clear();
if (!TextUtils.isEmpty(groups)) {
Collections.addAll(filteredGroups, groups.split(","));
}
filteredSenders.clear();
if (!TextUtils.isEmpty(senders)) {
Collections.addAll(filteredSenders, senders.split(","));
}
}
@Override
public boolean processEvent(AccessibilityEvent event) {
// 获取当前群聊名称
String currentGroup = getCurrentGroupName();
// 获取红包发送者
String sender = getRedPacketSender(event);
// 检查是否需要过滤
if (filteredGroups.contains(currentGroup) || filteredSenders.contains(sender)) {
Log.d(TAG, "红包已过滤: 群聊=" + currentGroup + ", 发送者=" + sender);
return true; // 消费事件,阻止抢红包
}
return false;
}
// 获取当前群聊名称的实现
private String getCurrentGroupName() {
// 实现获取当前群聊名称的逻辑
return "";
}
// 获取红包发送者的实现
private String getRedPacketSender(AccessibilityEvent event) {
// 实现从事件中提取发送者信息的逻辑
return "";
}
@Override
public View getConfigUI() {
// 创建配置界面,允许用户输入过滤的群聊和发送者
// ...
return null;
}
@Override
public void onPreferenceChanged(String key) {
if ("filtered_groups".equals(key) || "filtered_senders".equals(key)) {
loadFilters(); // 重新加载过滤列表
}
}
}
5. 插件调试与测试
5.1 调试技巧
日志输出:
// 使用HongbaoLogger输出调试信息
HongbaoLogger.writeHongbaoLog("CustomPlugin", "processEvent", "红包事件处理");
断点调试:
- 在
onAccessibilityEvent方法设置断点 - 触发微信红包事件
- 观察事件处理流程
5.2 测试用例
| 测试场景 | 步骤 | 预期结果 |
|---|---|---|
| 插件加载测试 | 1. 安装带插件的APK 2. 启动无障碍服务 | 日志显示"插件加载成功" |
| 延迟抢红包测试 | 1. 设置延迟2秒 2. 发送红包 | 2秒后自动抢红包 |
| 红包过滤测试 | 1. 添加群聊到过滤列表 2. 在该群发送红包 | 不抢该群红包 |
6. 高级开发技巧
6.1 节点分析工具
使用Android Studio的Layout Inspector分析微信界面结构:
6.2 防检测策略
随机延迟策略:
private int getRandomDelay() {
// 生成1-3秒的随机延迟
return new Random().nextInt(2000) + 1000;
}
模拟人工点击轨迹:
private void simulateHumanClick(AccessibilityNodeInfo node) {
Rect rect = new Rect();
node.getBoundsInScreen(rect);
// 生成随机点击位置(节点范围内)
int x = rect.left + new Random().nextInt(rect.width());
int y = rect.top + new Random().nextInt(rect.height());
// 执行点击
Path path = new Path();
path.moveTo(x, y);
// ... 执行手势操作
}
7. 插件发布与分发
7.1 插件打包
将插件打包为独立的APK模块,或集成到主应用中:
// 插件模块build.gradle配置
apply plugin: 'com.android.library'
android {
// ...
}
dependencies {
implementation project(':app')
}
7.2 版本兼容性
确保插件兼容不同版本的WeChatLuckyMoney:
// 版本检查示例
if (BuildConfig.VERSION_CODE >= 100) {
// 新版本API调用
} else {
// 旧版本兼容代码
}
8. 常见问题解决
8.1 节点识别失败
可能原因:
- 微信版本更新导致界面结构变化
- 节点查找条件过于严格
解决方法:
- 使用更灵活的节点查找方式
- 适配不同微信版本的界面结构
8.2 插件冲突
冲突处理机制:
// 在插件中实现优先级机制
@Override
public int getPriority() {
return 100; // 数值越大优先级越高
}
9. 总结与展望
WeChatLuckyMoney插件系统为开发者提供了扩展抢红包功能的强大能力。通过本文介绍的开发方法,你可以实现各种自定义功能,如红包过滤、延迟抢取、自动回复等。
未来发展方向:
- 插件市场:建立集中式插件管理平台
- 远程配置:支持插件动态配置更新
- AI优化:使用机器学习优化红包识别算法
希望本指南能帮助你开发出功能丰富的自定义插件,为WeChatLuckyMoney生态系统贡献力量!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



