WeChatLuckyMoney扩展开发指南:编写自定义插件

WeChatLuckyMoney扩展开发指南:编写自定义插件

【免费下载链接】WeChatLuckyMoney :money_with_wings: WeChat's lucky money helper (微信抢红包插件) by Zhongyi Tong. An Android app that helps you snatch red packets in WeChat groups. 【免费下载链接】WeChatLuckyMoney 项目地址: https://gitcode.com/gh_mirrors/we/WeChatLuckyMoney

1. 插件开发概述

WeChatLuckyMoney作为一款高效的微信抢红包插件,提供了灵活的扩展机制允许开发者编写自定义插件。本指南将详细介绍插件开发的核心概念、架构设计和实现步骤,帮助开发者快速上手插件开发。

1.1 插件系统架构

WeChatLuckyMoney插件系统基于Android无障碍服务(Accessibility Service)构建,主要通过以下组件实现扩展功能:

mermaid

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", "红包事件处理");

断点调试:

  1. onAccessibilityEvent方法设置断点
  2. 触发微信红包事件
  3. 观察事件处理流程

5.2 测试用例

测试场景步骤预期结果
插件加载测试1. 安装带插件的APK
2. 启动无障碍服务
日志显示"插件加载成功"
延迟抢红包测试1. 设置延迟2秒
2. 发送红包
2秒后自动抢红包
红包过滤测试1. 添加群聊到过滤列表
2. 在该群发送红包
不抢该群红包

6. 高级开发技巧

6.1 节点分析工具

使用Android Studio的Layout Inspector分析微信界面结构:

mermaid

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生态系统贡献力量!

【免费下载链接】WeChatLuckyMoney :money_with_wings: WeChat's lucky money helper (微信抢红包插件) by Zhongyi Tong. An Android app that helps you snatch red packets in WeChat groups. 【免费下载链接】WeChatLuckyMoney 项目地址: https://gitcode.com/gh_mirrors/we/WeChatLuckyMoney

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值