09 · 客户端构建

1. 环境

项值说明
JDK8 或 11工程用 AGP 4.0.0 + Gradle 6.1.1,JDK 17 会直接报错
Gradle6.1.1(wrapper 自带)gradle/wrapper/gradle-wrapper.properties 指向腾讯云镜像
Android SDKcompileSdk 30 / buildTools 30.xtargetSdk 30、minSdk 24
Kotlin1.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. 安装后必须做的三件事

  1. 开无障碍服务:系统设置 → 无障碍 → SevFishComVBot → 开启。APP 内有引导页;没有这一步,客户端能连上但什么也做不了。
  2. 允许后台/关闭电池优化:否则息屏几分钟后循环被系统杀掉,表现为"设备在线但不回复"。
  3. 填服务器地址: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,applicationId com.sevfish.comvbot,rootProject.name SevFishComVBot。
  • 包名与源码目录已整体迁移(com/audio/soundamplifier → com/sevfish/comvbot)。
  • applicationId 变了:与旧版本(伪装名)不能覆盖安装,必须先卸载旧 APP。旧版本的本地 SP 配置(服务器地址、开关)不会继承。
  • 无障碍服务名、系统设置里显示的名称也会变成 SevFishComVBot。

6. 发布到你自己的构建

6.1 先搞清楚"签名"是什么

安卓要求每个 APK 带一个数字签名,用来回答两个问题:这个包是不是同一个人做的、能不能覆盖安装旧版。

  • debug 签名:./gradlew assembleDebug 自动用 ~/.android/debug.keystore 签,密码是公开的 android。能装能用,只适合自己用/内测。
  • release 签名:用你自己的 keystore(一个 .jks 文件 + 口令)签,这是"你的身份"。对外分发必须用它。

三条铁律:

  1. keystore 文件绝不进仓库(.jks/.keystore 已在 .gitignore 里)。
  2. 丢了就不能更新:签名不同的新版本无法覆盖安装,只能卸载重装(本地配置全丢)。所以 keystore 要像密钥一样备份到仓库之外。
  3. 不同 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. 调试界面定位(改版时)

  1. 在平板(或手机)上打开企业微信到目标页面 → adb shell uiautomator dump /sdcard/ui.xml
  2. adb pull /sdcard/ui.xml
  3. python3 tools/parse_ui.py ui.xml(仓库自带)→ 看节点树与 resource-id
  4. 对照 service/WeworkOperationImpl.kt 里同类操作的定位方式修改

仓库不包含真实的界面 dump(里面有真实客户名、手机号)。自己抓、自己留。

需要有人帮忙落地?可以联系定制开发、私有化部署、联合交付或技术咨询。