1. 环境
| 项 | 值 | 说明 |
|---|---|---|
| JDK | 8 或 11 | 工程用 AGP 4.0.0 + Gradle 6.1.1,JDK 17 会直接报错 |
| Gradle | 6.1.1(wrapper 自带) | gradle/wrapper/gradle-wrapper.properties 指向腾讯云镜像 |
| Android SDK | compileSdk 30 / buildTools 30.x | targetSdk 30、minSdk 24 |
| Kotlin | 1.3.72 | 别升级,AGP 4 与新版 Kotlin 不兼容 |
Android Studio 版本也别太新:用能打开 AGP 4.0 的版本(如 4.0/4.1),或者干脆纯命令行构建。
2. 构建
cd sevfish-comvbot-app
./gradlew assembleDebug
# 产物:app/build/outputs/apk/debug/app-debug.apk
Windows:compile_only.bat(仅编译)/ build_and_install.bat(编译并安装到已连接设备)。 安装:adb install -r app/build/outputs/apk/debug/app-debug.apk
首次构建需联网下载 Gradle 与依赖;国内可用腾讯云镜像(wrapper 里已配)。
3. 安装后必须做的三件事
- 开无障碍服务:系统设置 → 无障碍 → SevFishComVBot → 开启。APP 内有引导页;没有这一步,客户端能连上但什么也做不了。
- 允许后台/关闭电池优化:否则息屏几分钟后循环被系统杀掉,表现为"设备在线但不回复"。
- 填服务器地址:APP → 设置 → 服务器(
192.168.1.10:8765,可带ws://)。地址存在本地 SP(Constant.DEFAULT_HOST为空,必须手填)。
另外:悬浮窗权限用于回到 APP 首页;"获取名字"按钮用于让服务端知道本机企微昵称(群聊 @ 判定需要)。
4. 开源版本与原商业版本的差异
原商业版本里接入过几个不能随开源再分发的第三方 SDK,开源版已移除,行为相应降级:
| 移除的东西 | 原用途 | 开源版行为 |
|---|---|---|
libs/lib_wwapi-*.aar(腾讯企业微信 WWAPI) | 把链接/小程序以卡片形式分享进会话 | utils/IWWAPIUtil.kt 改为存根,两个方法恒返回 false,调用方走普通文本兜底 |
libs/SaaS_TalkingDataSDK_*.jar(TalkingData 统计) | 埋点 | 删除 |
com.umeng.umsdk:*(友盟统计/APM) | 崩溃与活跃统计 | 删除 |
因此开源版没有任何埋点、崩溃上报、自动分享卡片。需要这些能力请自行接自己的服务(不要把别人的 SDK 密钥提交进来)。
5. 命名与包名
- 应用名
SevFishComVBot,applicationIdcom.sevfish.comvbot,rootProject.nameSevFishComVBot。 - 包名与源码目录已整体迁移(
com/audio/soundamplifier→com/sevfish/comvbot)。 applicationId变了:与旧版本(伪装名)不能覆盖安装,必须先卸载旧 APP。旧版本的本地 SP 配置(服务器地址、开关)不会继承。- 无障碍服务名、系统设置里显示的名称也会变成
SevFishComVBot。
6. 发布到你自己的构建
6.1 先搞清楚"签名"是什么
安卓要求每个 APK 带一个数字签名,用来回答两个问题:这个包是不是同一个人做的、能不能覆盖安装旧版。
- debug 签名:
./gradlew assembleDebug自动用~/.android/debug.keystore签,密码是公开的android。能装能用,只适合自己用/内测。 - release 签名:用你自己的 keystore(一个
.jks文件 + 口令)签,这是"你的身份"。对外分发必须用它。
三条铁律:
- keystore 文件绝不进仓库(
.jks/.keystore已在.gitignore里)。 - 丢了就不能更新:签名不同的新版本无法覆盖安装,只能卸载重装(本地配置全丢)。所以 keystore 要像密钥一样备份到仓库之外。
- 不同 applicationId 之间互不影响:本项目把
applicationId改成了com.sevfish.comvbot,所以它与旧版本(伪装名)是两个独立应用,可以共存,也可以各自签名。
6.2 生成并配置
# 1. 生成 keystore(有效期 25 年以上;-dname 填你自己的信息)
keytool -genkeypair -v \
-keystore sevfish-release.jks -alias sevfish \
-keyalg RSA -keysize 2048 -validity 10000
# 2. 放在仓库之外,例如 ~/.keys/,然后让构建设置从环境变量读口令
app/build.gradle 里加一段签名配置(口令走环境变量或 local.properties,不要写死进 gradle 文件):
android {
signingConfigs {
release {
storeFile file(System.getenv("SEV_RELEASE_STORE_FILE") ?: "../.keys/sevfish-release.jks")
storePassword System.getenv("SEV_RELEASE_STORE_PASSWORD")
keyAlias System.getenv("SEV_RELEASE_KEY_ALIAS") ?: "sevfish"
keyPassword System.getenv("SEV_RELEASE_KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
}
}
}
export SEV_RELEASE_STORE_FILE=../.keys/sevfish-release.jks
export SEV_RELEASE_STORE_PASSWORD=***
export SEV_RELEASE_KEY_PASSWORD=***
./gradlew assembleRelease
# 产物:app/build/outputs/apk/release/app-release.apk
.gitignore 里补齐:.keys/、*.jks、*.keystore、local.properties。
6.3 本项目怎么选
- 只自己部署:用 debug APK 就够,不碰 keystore。
- 给团队/客户装:出 release APK,
applicationId固定、keystore 自己保管、只从你自己可控的渠道发(这也是为什么开源仓不发预编译 APK——别人拿你的包重新签名就是另一个应用,出了问题找不到人)。
6.4 改品牌
res/values/strings.xml的app_name与accessibility_desc,以及applicationId。- 改默认服务器地址:
Constant.kt的DEFAULT_HOST(开源版故意留空,强制手填,避免误连别人的服务端)。
7. 调试界面定位(改版时)
- 在平板(或手机)上打开企业微信到目标页面 →
adb shell uiautomator dump /sdcard/ui.xml adb pull /sdcard/ui.xmlpython3 tools/parse_ui.py ui.xml(仓库自带)→ 看节点树与resource-id- 对照
service/WeworkOperationImpl.kt里同类操作的定位方式修改
仓库不包含真实的界面 dump(里面有真实客户名、手机号)。自己抓、自己留。