README.md
Pixel WeChat Auto-Reply — Plugin for Hermes
在 Pixel 手机本地实现微信全自动闭环,通过 hermes API 生成回复,息屏时通过通知监听兜底。
运行环境:Pixel 10 Fold / Android 15 / WeChat 8.0.72
架构(双轨制)
主流程:Node.js Plugin(推荐)
sqlcipher 直接查询 EnMicroMsg.db
│
▼
┌─────────────────────────────────┐
│ AndroidWechatTrackerSQLCipher │────→ 轮询 message 表 (msgId > last)
│ (Node.js EventEmitter) │ PRAGMA key="e03ce81"
└─────────────────────────────────┘
│
▼
┌─────────────────────────┐
│ auto-reply.js │
│ handleMessage() │
│ - 判断单聊/群聊@/引用 │
│ - 检查 cooldown │
│ - 息屏唤醒微信 │
└─────────────────────────┘
│
▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ callHermesApi() │────→│ POST 127.0.0.1:8642 │
│ buildHermesMessages() │ │ /v1/chat/completions │
│ OpenAI messages 格式 │ │ (OpenAI-compatible) │
└─────────────────────────┘ └─────────────────────────┘
│ │
│ ▼
│ ┌─────────────────────────┐
│ │ hermes-agent │
│ │ (lemonPCRM wrapper) │
│ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ JSON 提取 content │────→│ 回复文本 │
└─────────────────────────┘ └─────────────────────────┘
│
▼
┌─────────────────────────┐
│ 微信在前台? │ No → am start LauncherUI
└─────────────────────────┘ + (息屏时) wakeWechat()
│Yes
▼
┌──────────────────────────────────────────────────────────┐
│ am broadcast -a com.hermes.wechat.SEND_MSG │
│ --es toUser <wxid> │
│ --es toUserDisplayName <nickname> ← 必传! │
│ --es content <text> │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ HermesAccessibilityService (lsposed-wechat-sendmsg 模块) │
│ 1. startActivity(LauncherUI, CLEAR_TASK) │
│ 2. 点搜索按钮 (id=jha) │
│ 3. ACTION_SET_TEXT 输入 nickname → 点搜索结果 │
│ 4. 进入聊天后 ACTION_SET_TEXT 写入 content │
│ 5. 点发送按钮 (id=bql) │
└──────────────────────────────────────────────────────────┘
│
▼
微信走自己正常的发送流程 → 服务器 → message 表 isSend=1
优势:
- 不依赖反射 hook 微信内部 NetSceneSendMsg(在 WeChat 8.0.72 上主线程提交持续 NPE 失败)
- 不依赖 Frida 注入(Frida 17 + 微信 8.0.72 注入会触发反调试 / 进程崩溃)
- sqlcipher 直接查询,数据完整(含群聊名称、发送者等)
- 走 UI 是慢一点(~8s/条)但唯一稳定可用
- 通过 hermes-agent API 享受完整的 Agent 编排、工具调用、记忆能力
⚠️ 历史遗留命名警告:
android-wechat-sender-frida.js中的sendTextMessageFrida写入.frida_queue/queue.jsonl的设计已废弃。同样地,README 早期版本把 Frida daemon 描述为主路径——那是错的。所有发送最终都走am broadcast→ A11y service。
备用流程:Python Daemon
hermes_wechat_daemon.py 作为备用通道,当 Node.js plugin 不可用时运行:
- DB 轮询检测
- 优先调用 hermes API,fallback 到直接 LLM API
- 同样支持通知监听兜底
息屏兜底:通知监听 + Termux 保活
息屏后微信/Termux 被冻结
│
▼
微信消息到来 → 系统通知栏产生通知
│
▼
┌─────────────────────────┐
│ termux-notification-list │────→ 每 3 秒轮询(独立线程)
│ (Node.js plugin 内) │
└─────────────────────────┘
│
▼
检测到微信通知
│
▼
isWechatForeground()? No → wakeWechat() → sleep 3s
│
▼
微信唤醒 → LSPosed 恢复写日志 → tail -f 捕获 → 正常处理
保活措施:
termux-wake-lock— 防止息屏后 CPU 被冻结- 关闭电池优化(Termux / Termux:API / 微信)
keepalive.sh进程守护 — hermes / auto-reply 死了自动重启
文件清单
| 文件 | 用途 | 环境 |
|---|---|---|
../../server/services/wechat/auto-reply.js |
主 plugin:tracker → hermes-agent API → sender | proot Ubuntu |
../../server/services/wechat/android-wechat-tracker-sqlcipher.js |
主推 消息跟踪(sqlcipher 轮询 DB) | proot Ubuntu |
../../server/services/wechat/android-wechat-sender-frida.js |
主推 消息发送(Frida daemon 队列) | proot Ubuntu |
../../server/services/wechat/android-wechat-tracker.js |
备用消息跟踪(tail -f LSPosed 日志) | proot Ubuntu |
../../server/services/wechat/android-wechat-sender.js |
备用消息发送(am broadcast / content insert) | proot Ubuntu |
hermes_wechat_daemon.py |
备用 daemon:DB 轮询 → hermes/LLM API → sender | Termux / proot |
config.json |
运行时配置 | Termux / proot |
keepalive.sh |
保活脚本:wake-lock + 进程守护 | Termux |
test_env.py |
环境预检 | Termux / proot |
test_send_msg.py |
发送消息测试 | Termux / proot |
run_all_tests.sh |
一键运行全部测试 | Termux / proot |
快速开始
1. 前置设置(必须手动)
Android 设置中关闭电池优化:
- 设置 → 应用 → Termux → 电池优化 → 不优化
- 设置 → 应用 → Termux:API → 电池优化 → 不优化
- 设置 → 应用 → 微信 → 电池优化 → 不优化
- 设置 → 应用 → Termux → 允许自启动 / 后台运行
Termux:API 权限:
- 安装 Termux:API 应用
- 设置 → 应用 → Termux:API → 通知访问权限 → 允许
2. 部署
# Mac 上推送
adb push server/services/wechat /data/data/com.termux/files/home/hermes-wechat
adb push wechat_plain/scripts/local-testkit /data/data/com.termux/files/home/local-testkit
# Pixel 上
cp -r /sdcard/hermes/local-testkit ~/local-testkit
cd ~/local-testkit
3. 启动 hermes-agent(如果还没运行)
hermes-agent 是 lemonPCRM 的 OpenAI-compatible wrapper,默认监听 127.0.0.1:8642:
proot-distro login ubuntu --user ubuntu -- bash -c \
"cd /data/data/com.termux/files/home/hermes-wechat && . .env && node server/index.js"
或后台运行:
nohup proot-distro login ubuntu --user ubuntu -- bash -c \
"cd /data/data/com.termux/files/home/hermes-wechat && . .env && node server/index.js" \
> hermes-server.log 2>&1 &
确认 agent 就绪:
curl http://127.0.0.1:8642/v1/chat/completions -X POST \
-H "Content-Type: application/json" \
-d '{"model":"hermes-agent","messages":[{"role":"user","content":"hi"}]}'
4. 启用 HermesAccessibilityService(发送端依赖)
A11y service 是消息真正能发出去的唯一路径——务必确认启用:
# 启用
adb shell "su -c 'settings put secure enabled_accessibility_services com.hermes.wechat.xposed/com.hermes.wechat.xposed.accessibility.HermesAccessibilityService; settings put secure accessibility_enabled 1'"
# 验证
adb shell "settings get secure enabled_accessibility_services"
adb shell "dumpsys accessibility | grep -A3 Hermes"
# 应看到: Bound services / Enabled services 都包含 HermesAccessibilityService
enabled_accessibility_services 在系统重启 / 微信或模块更新 / 用户在设置里关闭后会变成 null,发送会静默失败——把这个检查写进保活脚本里。
5. 启动 auto-reply plugin(推荐主流程)
cd ~/hermes-wechat/server/services/wechat
export MY_WXID=wxid_xxxxxx
export MY_NICKNAME=你的昵称
export HERMES_HOST=127.0.0.1
export HERMES_PORT=8642
nohup node auto-reply.js > auto-reply.log 2>&1 &
6. 启动保活脚本(推荐)
cd ~/local-testkit
export MY_WXID=wxid_xxxxxx
export MY_NICKNAME=你的昵称
export HERMES_DIR=/data/data/com.termux/files/home/hermes-wechat
chmod +x keepalive.sh
nohup ./keepalive.sh > keepalive.log 2>&1 &
7. 备用:启动 Python daemon
cd ~/local-testkit
python3 hermes_wechat_daemon.py --daemon
配置说明
auto-reply.js 环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
MY_WXID |
— | 你的微信 wxid(必填) |
MY_NICKNAME |
— | 你的微信昵称(必填,用于判断群聊@) |
HERMES_HOST |
127.0.0.1 |
hermes-agent API 地址 |
HERMES_PORT |
8642 |
hermes-agent API 端口(OpenAI-compatible) |
NOTIFICATION_ENABLED |
true |
是否启用通知监听兜底(息屏唤醒) |
Python daemon config.json
{
"hermes": {
"host": "localhost",
"port": 3010,
"timeout_sec": 120,
"default_session_prefix": "wx-",
"system_hint": "你是一个微信智能助手...",
"api_url": "",
"api_key": "",
"provider": "anthropic",
"model": ""
}
}
host/port:本地 hermes API 地址api_url/api_key/provider/model:hermes 不可用时 fallback 到直接 LLM API 的配置
故障排查
| 问题 | 排查步骤 |
|---|---|
发送接口返回 ok 但 yibooo 没收到 / message 表没新行 |
最常见:A11y service 未启用。adb shell "settings get secure enabled_accessibility_services" 若为 null 即是。重新启用见上文 |
A11y 日志 Root package=com.termux 后退出 |
广播触发时微信不在前台。先 am start -n com.tencent.mm/.ui.LauncherUI 再发 broadcast |
A11y 日志 Search button not found |
当前页面不是主界面 / nickname 错。检查 toUserDisplayName 必须是好友的 WeChat 昵称(如"火星人"),不是 wxid |
[HermesWX] Send result: true 但 DB 没新消息 |
LSPosed 反射路径的误报,是已知 bug。看 HermesA11y:* 日志才反映真实状态 |
| auto-reply 收不到消息 | 检查 sqlcipher 能否查询:su -c "sqlcipher /data/.../EnMicroMsg.db 'PRAGMA key=\\\"e03ce81\\\"; SELECT COUNT(*) FROM message;'" |
| hermes-agent API 返回空 | 检查 hermes-agent 是否运行:curl http://127.0.0.1:8642/v1/chat/completions ... |
| 息屏后完全失效 | 确认电池优化已关闭;检查 keepalive.sh 是否运行;检查通知权限 |
| Python daemon 查询不到新消息 | 检查微信是否在前台;检查 sqlcipher_key;确认 WAL 已复制 |
Claude CLI 报错 root/sudo privileges |
hermes 必须以 proot 内 ubuntu 用户 运行,不能是 root |
目录结构
local-testkit/
├── hermes_wechat_daemon.py # 备用守护进程(DB 轮询)
├── config.json # 运行时配置
├── keepalive.sh # 保活脚本
├── test_env.py # 环境预检
├── test_send_msg.py # 发送消息测试
├── run_all_tests.sh # 一键测试
└── docs/
├── README.md # 本文档
├── HERMES_WECHAT_ARCHITECTURE.md
├── REVERSE_ENGINEERING_LOG.md
├── NOTIFICATION_STRATEGY.md
└── plan.md
server/services/wechat/ # 主 plugin(Node.js)
├── auto-reply.js # 主入口:tracker → hermes-agent → sender
├── android-wechat-tracker-sqlcipher.js # **主推** 消息跟踪(sqlcipher 轮询 DB)
├── android-wechat-sender-frida.js # **主推** 消息发送(Frida daemon 队列)
├── android-wechat-tracker.js # 备用消息跟踪(tail -f LSPosed 日志)
├── android-wechat-sender.js # 备用消息发送(am broadcast / content insert)
├── index.js # 统一入口
└── README.md # plugin 文档