这篇文章记录一个完整的实现过程:用 Web 项目写 Android 自动化逻辑,运行在 AssistsX 中,完成某音 App 的未读消息检查和未读消息列表采集。
最终实现的功能很明确:
- 自动打开某音 App
- 检查底部消息 Tab 是否有未读数
- 进入消息列表,逐页收集未读会话
- 解析昵称、未读数量、最后一条消息和消息时间
- 在日志浮窗中实时显示执行结果

Web 方式需要什么
这里不是写一个原生 Android App,而是写一个 Web 插件,让 AssistsX 在 Android 端加载并执行。先把需要的东西说清楚,后面再一步步创建项目、加载插件、写自动化逻辑。
需要哪些平台
需要两个端:
- 电脑端:用来开发 Web 项目,启动 Vite dev server
- Android 手机端:安装 AssistsX,并开启无障碍服务
整体链路是:Vue 页面和 assistsx-js 逻辑运行在 AssistsX 的 WebView 中,再由 AssistsX 调用 Android 无障碍能力去操作某音 App。
需要集成哪些库
核心库是 assistsx-js。它负责把 Web 端代码和 Android 自动化能力连接起来,常用能力包括:
- 查找节点:
findById、findByTags - 操作节点:点击、滚动
- 步骤编排:
Step.run、step.next - 浮窗和日志:用于显示执行过程
Web 项目用什么框架
这个项目使用 Vue 3、Vite、TypeScript、Vue Router 和 assistsx-js。本质上它还是一个前端项目,只是运行环境不是普通浏览器,而是 AssistsX 内部的 WebView。
创建 Web 项目
从零开始写一个 assistsx-js 项目,可以直接用脚手架创建:
bash
npx create-assistsx-vue@latest my-app
cd my-app
npm run dev
这个命令会生成一个 Vue 3 + Vite + TypeScript 项目,并且把 assistsx-js、路由、日志浮窗、测试面板和基础 Step 代码都准备好。后面只需要把默认步骤替换成自己的自动化逻辑即可。
如果想在当前目录初始化,也可以这样:
bash
mkdir my-app && cd my-app
npx create-assistsx-vue@latest --here
npm run dev
本文的某音未读消息功能就是在类似的项目结构上继续实现的。
如果已经拉取了本文源码,则进入项目后安装依赖:
bash
npm install
然后启动开发服务:
bash
npm run dev
项目里已经把 Vite 配成了局域网可访问,所以手机和电脑在同一个 Wi-Fi 下时,手机可以直接访问 http://<电脑IP>:5173。
配置插件信息
AssistsX 加载插件时会读取 public/config.json,里面是插件名称、入口文件、图标这些信息:
json
{
"name": "Message Automation",
"packageName": "com.dy.automation.example",
"index": "index.html",
"icon": "icon.png"
}
这里的 index 对应 Web 项目的入口页面,packageName 是插件自身的包名标识,不是目标 App 的包名。
安装平台并加载插件
手机端需要先安装 AssistsX:
- 下载地址:www.pgyer.com/assistsx
- 安装后打开无障碍服务
- 手机和电脑保持在同一个局域网
在 AssistsX 里用局域网加载插件,步骤如下:
- 电脑先执行
npm run dev,手机和电脑保持在同一 Wi-Fi - 打开 AssistsX,点击首页「+」
- 选择「扫描局域网」,等待扫描结果
- 找到本项目的 dev 地址(
http://<电脑IP>:5173),点击「安装」 - 返回首页,即可看到插件,点击启动

分析某音页面节点
写 Android 自动化最关键的一步,不是先写代码,而是先看页面节点。
比如要点击底部的「消息」,或者判断某一行是不是未读消息,需要知道这些控件在无障碍节点里长什么样。这里用到的是 AssistsX 的节点分析服务。
我的做法一般是这样:
分析时重点看这几个字段:
className:控件类型,比如android.widget.Button、android.widget.TextViewtext:界面上显示的文字,比如底部消息 Tab 上的未读数字des:无障碍描述,某音消息行里经常会把昵称、未读数、最后一条消息拼在这里id:资源 ID,有些页面可以直接用它定位
有了这些信息,代码里就可以用 findByTags、findById、filterDes 去找节点。这样比写死坐标稳定很多,页面尺寸或手机分辨率变了也不容易直接失效。

实现功能入口
插件主页只放两个入口:
- 检查未读消息
- 获取未读消息列表
按钮点击后会打开一个日志浮窗,并把要执行的动作通过 query 传过去:
ts
void float.open(`/examples/log-panel?action=${action}`, {
showBottomOperationArea: true,
})
日志浮窗负责两件事:一边显示执行日志,一边启动自动化流程。
启动流程的代码大概是这样:
ts
await Step.run(appLaunch.launch, {
data: {
appName: "DY",
packageName: "com.ss.android.ugc.aweme",
finishMethod: douyinMain.checkMainPage,
...flowData,
},
});
这里先从 appLaunch.launch 开始,负责把某音拉起来。启动成功后,再进入 douyinMain.checkMainPage,继续判断当前是不是某音首页。

实现自动化流程
代码主要在 src/steps/ 下面。我没有把所有逻辑都塞到一个函数里,而是拆成几个步骤,靠 step.next() 往下走。
大概流程是:
text
启动某音
↓
确认回到某音首页
↓
检查底部消息 Tab 未读数
↓
如果要收集列表,点击消息 Tab
↓
消息列表滚动到顶部
↓
逐页收集未读消息
检查未读消息比较直接:找到底部导航里的「消息,按钮」,再看它附近有没有纯数字的 TextView。有数字就说明有未读。
收集未读消息列表稍微麻烦一点。进入消息列表后,先找到屏幕里的 RecyclerView,再遍历里面的消息行。消息行本身通常是 android.widget.Button,未读角标在右侧,具体内容在这一行的 des 里。
比如节点描述可能长这样:
text
早上好咸鱼翻面,未读1条消息,hgff8分钟前
互动消息,未读1条消息,咸鱼翻面 近期访问过你的主页05/13
这里要解析出四个字段:
nickname:昵称unreadCount:未读数量lastMessage:最后一条消息内容time:消息时间,最后会转成时间戳
如果 des 里没有 未读X条消息,就说明这行不是未读消息,直接跳过。
列表滚动时有一个小坑:上下页之间可能会重复扫到同一条消息。所以收集时会把已经拿到的数据存在类变量里,如果 nickname、unreadCount、lastMessage、time 四个字段都一样,就当作重复数据跳过。
日志里最后看到的效果类似这样:
text
【未读消息】
昵称:早上好咸鱼翻面
未读:1 条
内容:hgff
时间:2026-05-30 08:12:00
【配图建议:放一张日志浮窗截图,展示未读消息被解析后的输出】
运行功能
准备条件不多:
- Android 手机上安装 AssistsX,并开启无障碍服务
- 手机已安装某音 App
- 电脑和手机在同一个局域网
- 本机有 Node.js 环境
启动项目:
bash
npm install
npm run dev
插件安装好后,在 AssistsX 首页打开即可。进入插件后,点「检查未读消息」或「获取未读消息列表」开始运行。
运行过程中日志浮窗会一直显示当前执行到哪里。如果流程跑偏了,或者想手动停止,可以点浮窗里的「停止」按钮,内部调用的是:
ts
Step.stop()
【GIF 建议:录一个完整流程,从点击「获取未读消息列表」到日志输出收集结果】
如果只是想先看效果,也可以直接在 AssistsX 的插件商店中搜索并安装本文实现的功能,不需要本地启动 Web 项目。
源码
完整源码放在这里:
相关项目:
- AssistsX(源码)
- assistsx-js:github.com/ven-coder/a...
合规说明
本文内容仅用于学习 Web 方式开发 Android 自动化。实际使用时请遵守相关平台规则和法律法规,避免用于违规采集、骚扰或其他不合规场景。