diff --git a/交接文档.md b/交接文档.md new file mode 100644 index 0000000..2091247 --- /dev/null +++ b/交接文档.md @@ -0,0 +1,421 @@ +# WorkTool 项目交接文档 + +本文档面向后续接手的开发人员,帮助快速理解 WorkTool 的整体架构、运行机制以及关键代码位置,便于后续维护与二次开发。 + +--- + +## 1. 项目概述 + +- 项目名称:WorkTool +- 主要功能:依附于企业微信 / 微信运行的无人值守群管理机器人,通过无障碍服务和企业微信官方 SDK 实现自动收发消息、建群、拉人、踢人等能力。 +- 客户端形态:Android 原生 APP(需运行在一台专用手机上),通过 WebSocket 与后端任务调度平台长连接通信。 +- 法规与安全:基于 Android 官方无障碍服务和企业微信官方 SDK,无 Hook / 无 Root / 无内存修改,注意遵守腾讯运营规范与相关法律法规。 + +更多面向使用方的说明及 API 文档,可参考: + +- 项目 README:[README.md](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/README.md) +- 后端协议文档:[BACKEND_PROTOCOL.md](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/BACKEND_PROTOCOL.md) + +--- + +## 2. 技术栈与运行环境 + +- 平台:Android +- 语言:Kotlin + Java 混合 +- 构建工具:Gradle(使用仓库自带 `gradlew`) +- 最低支持版本:`minSdkVersion 24` +- 目标版本:`targetSdkVersion 30` +- 编译版本:`compileSdkVersion 30` +- Java 版本:`sourceCompatibility 1.8` / `targetCompatibility 1.8` +- IDE 建议:Android Studio(Arctic Fox 及以上版本均可正常打开) + +涉及的关键第三方依赖(不完整列举): + +- 工具库:`com.blankj:utilcodex`(通过 `com.blankj.utilcode.util.*` 等类使用) +- 日志:`LogUtils`(见 [LogUtilsInit.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/utils/LogUtilsInit.kt)) +- Toast:`com.hjq:toast`(`ToastUtils`) +- UI 组件:`Material Components`(`MaterialAlertDialogBuilder`)、`QMUI` 对话框 +- 网络通信:`OkHttp` WebSocket(见 [WebSocketManager.java](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java)) +- 埋点统计:友盟 (`UMConfigure`),TalkingData (`TalkingDataSDK`) +- 企业微信 SDK:`lib_wwapi-*.aar`(位于 `app/libs/`) + +--- + +## 3. 工程结构总览 + +根目录主要文件与模块: + +- `app/`:主 APP 工程(业务逻辑、UI、无障碍自动化、与后端通信等全部在此) +- `baselibrary/`:基础 UI / Adapter 等通用组件 +- `floatwindow/`:悬浮窗相关实现 +- `BACKEND_PROTOCOL.md`:客户端与后台 WebSocket 协议说明 +- `README.md`:面向使用方的简要说明与版本更新记录 + +多模块声明见: + +- [settings.gradle](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/settings.gradle) +- [app/build.gradle](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/build.gradle) + +### 3.1 app 模块结构 + +路径:`app/src/main/java/org/yameida/worktool/` + +主要包与职责: + +- `activity/` + - `ListenActivity`:主控制面板,配置链接号(robotId)、后端 host、开关无障碍与悬浮窗,是日常运维主要入口。 + - `LoginActivity`:登录相关界面。 + - `SettingsActivity` / `SettingsAdvanceActivity`:基础及高级设置。 + - `AccessibilityGuideActivity` / `FloatViewGuideActivity`:权限引导页面。 + - `BrowserActivity`、`GetScreenShotActivity`:辅助操作页面。 +- `service/` + - `WeworkService`:无障碍服务实现,负责监控和操作企业微信界面,是自动化的核心。 + - `WeworkController`:统一调度控制,无障碍操作入口,管理循环任务状态。 + - `WeworkLoopImpl` / `WeworkOperationImpl` / `WeworkInteractionImpl` / `WeworkGetImpl`:对企业微信不同操作的具体实现(循环拉取任务、执行发送消息、拉群、获取信息等)。 + - `PlayNotifyService` / `PlayNotifyManager`:前台服务与通知控制,保障机器人在前台或长时间运行。 + - `GlobalMethod.kt` / `MyLooper.kt`:封装通用操作和循环执行器。 +- `utils/` + - 网络相关:`HttpUtil.kt`(REST 接口访问)、`OkHttpUtil.kt`、`WebSocketManager.java`。 + - 无障碍与权限:`AccessibilityUtil.kt`、`AccessibilityExtraUtil.kt`、`PermissionHelper.kt`、`FlowPermissionHelper.kt`、`PermissionPageManagement.java`。 + - 悬浮窗:`FloatWindowHelper.kt`,配合 `floatwindow` 模块实现全局悬浮按钮。 + - 屏幕与截图:`capture/` 包下的 `ScreenCaptureUtil`、`ScreenCaptureUtilByMediaPro`、`MediaProjectionHolder.kt` 等。 + - 配置与缓存:`CacheUtil.kt`、`PropUtil.kt`、`HostTestHelper.kt`。 + - 其他工具:`RegexHelper.kt`、`RuntimeUtil.kt`、`WeworkRoomUtil.kt`、`WeworkTextUtil.kt` 等。 +- `model/` + - `network/`:与后端通信的返回体,例如 `CheckUpdateResult.java`、`GetMyConfigResult.java`。 + - `operation/`:执行结果封装,如 `SelectResult.kt`。 + - `WeworkMessageBean.java` / `WeworkMessageListBean.kt`:WebSocket 消息封装,与 `BACKEND_PROTOCOL.md` 一一对应。 + - `AppUpdate.java`、`MyConfigBean.kt` 等:应用更新 / 机器人配置相关模型。 +- `notification/`:通知栏相关封装(`PlayNotifyManager.kt`)。 +- `config/`:全局异常处理(`GlobalException.java`)。 +- `observer/`:文件监听等辅助(`MultiFileObserver.java`)。 +- 顶层文件: + - `MyApplication.kt`:全局 Application,完成 SDK 初始化、前台服务启动等。 + - `Constant.kt`:全局常量与配置(可持久化到 `SPUtils`)。 + - `Demo.kt`:示例或测试代码(如有使用可再确认)。 + +### 3.2 baselibrary 模块 + +路径:`baselibrary/` + +- 主要保存通用 UI 组件与 Adapter,例如 `RvSimpleAdapter`、`RvViewHolder`。 +- 资源文件中包含通用 `styles`、`strings` 等。 +- 项目中作为 `app` 的依赖模块,无业务逻辑。 + +### 3.3 floatwindow 模块 + +路径:`floatwindow/` + +- 浮窗管理:`FloatWindowManager.kt`、`BaseFloatWindow.java`、`DefaultFloatService.kt`。 +- 监听器:`listener/` 包下 `FloatWindowListener.kt`、`OnClickListener.kt` 等。 +- 视图:`view/HiderView.java` 与相关布局、图片资源。 +- 为 `app` 提供悬浮窗入口、暂停 / 启动机器人等操作。 + +--- + +## 4. 运行流程与关键逻辑 + +### 4.1 App 启动流程 + +入口类: + +- `AndroidManifest.xml` 中配置 `MyApplication` 作为 `application`,主 Activity 为登录或 Listen 页(视具体配置而定)。 +- [MyApplication.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/MyApplication.kt) 负责: + - 初始化 `Utils`、日志配置(`LogUtilsInit`)、`Gson` 代理。 + - 初始化 `ToastUtils`。 + - 初始化友盟埋点(`UMConfigure`),通过 `SPUtils` 中 `uminit` 标记隐私协议同意状态。 + - 初始化 TalkingData(`TalkingDataSDK.init(...)`),`Constant.robotId` 作为渠道维度之一。 + - 初始化企业微信 SDK(`IWWAPIUtil.init(this)`)。 + - 初始化应用更新框架(`UpdateAppUtils.init(this)`)。 + - 启动前台通知(`PlayNotifyManager.show()`)。 + - 设置全局异常捕获(`GlobalException`),异常时自动重启。 + +### 4.2 ListenActivity 配置流程 + +核心界面:[ListenActivity.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt)。 + +主要职责: + +- 展示并编辑链接号(`robotId`): + - 文本框 `et_channel` 显示当前 `Constant.robotId`。 + - 点击“保存”按钮: + - 将输入写入 `Constant.robotId`(内部通过 `SPUtils` 持久化)。 + - 发送广播通知 `Constant.WEWORK_NOTIFY`,类型为 `modify_channel`。 + - 调用 `HttpUtil.getMyConfig(toast = false)` 拉取机器人配置。 + - 将链接号上报给友盟 `MobclickAgent.onProfileSignIn(channel)`。 +- 配置 WebSocket host: + - 文本 `tv_host` 显示 `Constant.host`。 + - 点击:弹出历史 host 列表(来自 `SPUtils` 的 `host_list`),支持一键切换并调用 `HostTestHelper.testWs()` 进行连通性检测。 + - 长按:弹出编辑对话框,支持新增 / 删除 host,新增时校验是否符合 `ws://` 或 `wss://` 开头格式。 +- 权限开关: + - 无障碍开关 `sw_accessibility`: + - 校验是否填写链接号。 + - 校验是否已开启系统无障碍;如未开启,跳转到引导页 `AccessibilityGuideActivity` 或系统设置。 + - 如检测到 Hook / Root 环境,进行风险提示并控制运行。 + - 关闭时调用 `WeworkController.weworkService.disableSelf()`(在部分 ROM 上会转跳到系统设置)。 + - 悬浮窗开关 `sw_overlay`: + - 开启时跳转 `FloatViewGuideActivity` 引导授权。 + - 已授权时显示悬浮窗(`FloatWindowHelper.showWindow()`)或引导前往权限设置页。 +- 环境检测: + - 设备信息、Root 状态、Hook 状态写入 `SPUtils`,用于后续分析。 + - 检查企业微信当前版本是否在 `Constant.AVAILABLE_VERSION` 列表内,给出“已适配 / 可能存在兼容性问题”等提示。 +- 初始化数据: + - 在 `initData` 中设置默认 `Constant.robotId` 与 `Constant.host`(可以视需要调整或移除默认值)。 + - 调用 `HttpUtil.getMyConfig(toast = false)` 拉取机器人配置。 + - 调用 `CacheUtil.autoDelete()` 清理旧缓存。 + +### 4.3 与后端的通信 + +WebSocket 链接: + +- WebSocket 地址统一由 `Constant.getWsUrl()` 生成,格式为:`/webserver/wework/`。 + - 默认 host 在 `Constant.DEFAULT_HOST` 中配置:`ws://8.166.130.74:18680`。 + - host 与 robotId 最终都持久化在 `SPUtils` 中,方便修改。 +- 具体 WebSocket 管理由 [WebSocketManager.java](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java) 实现: + - 维护 WebSocket 连接、心跳(每 5 秒一次)、自动重连。 + - 发送和确认消息(`WeworkMessageListBean` 封装),写入日志。 + - 断线时关闭新消息接收(`WeworkController.setEnableLoopRunning(false)`),重连成功后再恢复。 + - 当长时间连接正常且未开启截屏模式时,如果检测到长时间未重连且仍在运行,会通过 Toast 提示“机器人运行中 请勿人工操作手机~”。 + +协议格式: + +- 完整协议说明见 [BACKEND_PROTOCOL.md](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/BACKEND_PROTOCOL.md): + - 连接 URL 格式、心跳机制。 + - `WeworkMessageListBean`、`WeworkMessageBean` 的字段含义。 + - 常用指令类型(如 `203` 发送消息、`218` 推送文件、`505` 获取最近聊天列表、`101` 接收消息列表等)。 + - 执行结果回调、错误码定义。 +- 代码中 `type`、`socketType` 等字段与文档一一对应,建议修改协议前同时修改此文档与对应模型类。 + +### 4.4 自动化执行流程(企业微信侧) + +高层流程(简化): + +1. 后端下发任务(通过 WebSocket)。 +2. 客户端解析为 `WeworkMessageBean` / `WeworkMessageListBean`。 +3. `WeworkController` 调度对应的 `Wework*Impl` 实现执行操作: + - 打开企业微信指定页面。 + - 定位目标群 / 联系人。 + - 根据控件树执行点击、输入文本、长按、转发等操作。 +4. 执行完成后,将结果封装回 WebSocket 消息上报服务端,包含成功 / 失败列表、错误原因等。 + +关键依赖: + +- 无障碍服务:`WeworkService` + `AccessibilityUtil` / `AccessibilityExtraUtil`。 +- 文本匹配与房间识别:`RegexHelper`、`WeworkRoomUtil`、`WeworkTextUtil`。 +- 循环任务:`MyLooper`、`WeworkLoopImpl`。 + +--- + +## 5. 配置项与敏感信息 + +### 5.1 host 与 robotId + +相关代码: + +- [Constant.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/Constant.kt) +- [ListenActivity.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt) + +说明: + +- `Constant.host` + - 默认值:`DEFAULT_HOST = "ws://8.166.130.74:18680"`。 + - 通过 `SPUtils` 持久化,键为 `"host"`。 + - 可在 ListenActivity 中通过 host 列表 / 编辑弹窗进行修改。 + - 业务上可视为“后端 WebSocket 网关地址”,如需要更换环境(测试 / 生产)时重点关注。 +- `Constant.robotId` + - 通过 ListenActivity 的输入框配置。 + - 底层持久化键为 `"robotId"`,同时兼容历史 `"LISTEN_CHANNEL_ID"`。 + - 后端一般将其视为“链接号 / 机器人唯一 ID”,用于区分不同设备 / 账号。 + +注意事项: + +- 在更改默认 host 或引导用户填写 robotId 时,需要与后端保持一致(确保后台任务调度平台识别该 robotId)。 +- 如需要支持多环境(测试 / 预发 / 生产),可以在现有 host 列表机制上扩展 UI 与配置管理。 + +### 5.2 企业微信兼容版本 + +相关代码: + +- [Constant.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/Constant.kt) 中 `AVAILABLE_VERSION` 与 `AVAILABLE_VERSION_MAP`。 +- ListenActivity 中通过 `AppUtils.getAppInfo(Constant.PACKAGE_NAMES)?.versionName` 获取企业微信版本。 + +说明: + +- `AVAILABLE_VERSION` 列出了当前已适配的企业微信版本号(例如 `4.1.8`、`4.1.9`、`4.1.10` 等)。 +- `AVAILABLE_VERSION_MAP` 用于将版本号映射为内部的整数版本,用于兼容性判断。 +- 当检测到企业微信版本不在列表内时,会提示“可能存在部分兼容性问题”,但仍允许使用。 + +后续维护建议: + +- 当企业微信版本升级后,需要: + - 手动测试各项自动化功能。 + - 若确认兼容,将新版本号加入 `AVAILABLE_VERSION` 与 `AVAILABLE_VERSION_MAP`。 + - 如需要针对特定版本调整逻辑,可结合 `Constant.version` 做分支处理。 + +### 5.3 统计与第三方 SDK key + +相关代码: + +- [MyApplication.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/MyApplication.kt) + +说明: + +- 友盟统计: + - `val key = "6284a3a3d024421570f97c3c"` + - 通过 `UMConfigure.preInit` / `UMConfigure.init` 初始化。 + - 隐私协议同意状态通过 `SPUtils` 中 `"uminit"` 字段控制。 +- TalkingData: + - `TalkingDataSDK.init(this, "80E9C84E39904DAFB28562910FF7C86C", getString(R.string.app_name) + "_master", Constant.robotId)` + - 依赖 `Constant.robotId` 作为渠道维度。 + +接手后如需更换统计账号或关闭统计: + +- 调整或移除相应初始化代码。 +- 同时评估对现有数据分析的影响,必要时与产品 / 运维同步。 + +--- + +## 6. 构建、打包与发布流程 + +### 6.1 本地开发环境搭建 + +1. 克隆仓库到本地: + - 建议完整克隆含子模块(当前项目无 Git 子模块,仅多 module)。 +2. 使用 Android Studio 打开仓库根目录。 +3. 确保本地已安装: + - JDK 8(或 Android Studio 自带 JDK)。 + - Android SDK 30 及对应 Build Tools。 +4. 首次打开时,按 IDE 提示同步 Gradle,等待依赖下载完成。 + +### 6.2 常用构建命令 + +在项目根目录下,可以使用仓库自带 Gradle Wrapper: + +- 编译 Debug 包: + + ```bash + ./gradlew assembleDebug + ``` + +- 编译 Release 包: + + ```bash + ./gradlew assembleRelease + ``` + +注意: + +- `app/build.gradle` 中 `release` 构建类型启用了混淆: + - `minifyEnabled true` + - 混淆配置文件:`proguard-android-optimize.txt`(默认)与 `app/proguard-rules.pro` +- 签名配置可能未在仓库中直接提供(如使用本地 `keystore`),如需正式发布包,请向原维护人员或运维团队索取签名文件与配置。 + +### 6.3 打包注意事项 + +- 由于集成了企业微信 SDK(`libs/lib_wwapi-*.aar`)及多个三方 SDK,混淆配置需要保持当前状态,避免将关键类混淆导致运行崩溃。 +- 如新增依赖,请同步更新 `proguard-rules.pro`。 +- Release 包上线前建议至少在以下维度自测: + - 不同 Android 版本(特别是 API 24~30)。 + - 不同厂商 ROM(华为、小米、OPPO、VIVO 等)的无障碍与后台保活行为。 + - 至少一种已适配的企业微信版本。 + +--- + +## 7. 日常调试与常见问题 + +### 7.1 日志查看 + +- 项目统一使用 `LogUtils` 输出日志,初始化在 `LogUtilsInit` 中。 +- 日志输出位置、格式可在 [LogUtilsInit.kt](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/app/src/main/java/org/yameida/worktool/utils/LogUtilsInit.kt) 中调整。 +- 联调时建议: + - 在关键流程(WebSocket 收发、无障碍执行)增加必要的日志。 + - 结合后端日志与手机本地日志定位问题。 + +### 7.2 无障碍与权限问题 + +常见现象: + +- 无法自动跳转 / 点击: + - 检查系统无障碍设置中是否已为 WorkTool 授权。 + - 检查是否被 ROM 的“电池优化 / 后台保护”策略限制。 +- 悬浮窗不显示: + - 检查“悬浮窗权限”是否开启。 + - 检查 `FloatWindowHelper.showWindow()` 是否被调用。 + +相关工具类: + +- `PermissionHelper`:无障碍权限判断与相关操作。 +- `FlowPermissionHelper`:后台启动、悬浮窗等权限判断。 +- `PermissionPageManagement`:跳转至系统设置页面。 + +### 7.3 WebSocket 连接异常 + +排查步骤: + +1. 在 ListenActivity 中确认 `host` 与 `robotId` 配置正确。 +2. 使用 `HostTestHelper.testWs()`(ListenActivity 操作 host 时自动调用)测试连通性。 +3. 查看 `WebSocketManager` 日志,确认是否存在频繁断线重连。 +4. 确认服务端配置与 `BACKEND_PROTOCOL.md` 版本一致。 + +进一步建议(针对日志中偶发 `Connection closed` 场景): + +- 现象判定: + - 若出现“断开后 1~2 秒内自动重连成功,且同一 clientId 可继续收发消息”,通常是短时网络抖动或网关空闲回收,不一定是严重故障。 + - 若出现“周期性断开(如每几分钟一次)”或“重连失败持续告警”,优先排查配置问题。 +- 归因方法(客户端 / 服务端 / 网关): + - 客户端(Android)补充日志:在 `WeworkService.EchoWebSocketListener` 的 `onClosing/onClosed/onFailure` 打印 `code`、`reason`、`throwable`。 + - 服务端补充日志:在 WebSocket Handler 的关闭与异常回调中打印 `clientId`、`sessionId`、关闭码、异常栈。 + - 网关层补充日志:Nginx / LB 记录 upstream 连接关闭原因与空闲超时触发记录。 + - 通过同一时间窗口对齐三端日志,判断“谁先发起关闭、关闭码是什么、是否有网络异常”。 +- 常见根因: + - 手机网络切换(Wi-Fi/移动网络)或弱网导致 TCP 断开。 + - 网关 / 反向代理空闲超时过短,主动关闭 WebSocket。 + - 心跳机制仅业务层保活,未启用 WebSocket ping,导致中间设备误回收长连接。 + - Android 省电策略导致后台网络能力受限。 +- 建议优化项(按优先级): + - 客户端统一复用 `OkHttpClient`,并开启 `pingInterval`(建议 20~30 秒)。 + - 网关与服务端 idle timeout 应明显高于心跳周期(建议至少 30~60 秒)。 + - 重连策略增加“指数退避 + 抖动”,避免批量设备同时重连。 + - 在运维侧统计“每设备每小时断线次数、重连耗时、连续失败次数”,作为健康度指标。 + +相关代码入口: + +- WebSocket 管理:`app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java` +- 监听与回调:`app/src/main/java/org/yameida/worktool/service/WeworkService.kt` + +--- + +## 8. 后续可扩展与注意事项 + +- 协议变更: + - 修改 WebSocket 协议或新增指令类型时,需同时更新: + - `WeworkMessageBean` / `WeworkMessageListBean` 数据结构。 + - `Wework*Impl` 中对新指令的处理逻辑。 + - 文档 [BACKEND_PROTOCOL.md](file:///Users/tan/Documents/project/lzwcai-terminal-worktool/BACKEND_PROTOCOL.md)。 +- 新企业微信版本适配: + - 新版本上线后,需实机测试高频功能。 + - 确认后更新 `Constant.AVAILABLE_VERSION` 及相关逻辑。 +- 安全与合规: + - 严禁在代码中硬编码任何生产环境账号密码。 + - 涉及数据采集、上传时注意隐私合规(特别是好友信息、聊天内容等)。 + +--- + +## 9. 交接建议 + +建议接手同学优先按以下顺序熟悉项目: + +1. 阅读 README 与本交接文档,理解整体定位与功能。 +2. 在测试环境跑通完整链路: + - 编译安装 APP。 + - 配置测试后端 host 与 robotId。 + - 打开无障碍与悬浮窗权限。 + - 使用后台调度平台下发几种典型任务(发送文本、发送图片、获取最近聊天列表等)。 +3. 深入阅读核心代码: + - `MyApplication`(启动流程)。 + - `ListenActivity`(配置入口)。 + - `WeworkService` + `WeworkController` + `Wework*Impl`(自动化执行)。 + - `WebSocketManager` + 协议模型类(通讯层)。 +4. 根据实际需要再进一步梳理业务细节与扩展点。 + +如后续对具体模块或逻辑有疑问,可在对应类文件中逐步补充更细的内部文档或注释,并与团队同步更新本交接文档。