Files
prop-ai-hr/docs/MOBILE_APP_PACKAGING.md
T

135 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# mobile-uni 原生 App 打包
`mobile-uni/` 采用 uni-app Vue 3 的 App-Plus 目标,同时保留 H5。App 不是将线上 H5 包进 WebView;前端资源通过 `npm --prefix mobile-uni run build:app` 编译,再由 HBuilderX 的自定义基座或云端打包生成 Android/iOS 原生安装包。
## 当前约定
- Android applicationId 与 iOS Bundle ID 预设为 `com.yincheng.wygj`。在首次签名或注册 App ID 前,发布负责人必须确认企业实际拥有该标识;变更时 Android、iOS 必须同步修改。
- App 直接请求 `https://peilian.njzhmj.top/dev-api`。不依赖 H5 开发服务器的 `/dev-api` proxy;地址是公开配置,不得在 App 包中放入短信、模型、签名或任何服务端密钥。
- `manifest.json` 只保留不含秘密的发布配置。`.keystore`、`.p12`、`.mobileprovision` 与证书密码只能由发布负责人在 HBuilderX 云打包界面或受控 CI 秘密变量中提供,绝不能提交 Git。
- Android 最低试点设备为 Android 10,`manifest.json` 显式固定 `targetSdkVersion=35`,避免回落到 DCloud 默认 API 28 兼容模式;iOS 最低试点设备为 iOS 15。每次发版提升 `versionCode`,再更新 `versionName`。
- Android 设备信息与外部存储权限固定为启动时不申请;Camera/Record 模块仅在用户进入相应功能后走运行时授权。不要为了消除系统权限声明而删除实际使用的媒体模块,也不要恢复启动即申请。
- 当前编译链与本机 HBuilderX 5.22 对齐:GUI 产品版本为 `5.22.2026071707`,`D:\HBuilderX\cli.exe version` 返回 `5.22.2026072503-alpha`;`@dcloudio/uni-app`、`@dcloudio/uni-app-plus`、`@dcloudio/uni-h5`、`@dcloudio/vite-plugin-uni` 均固定为 `3.0.0-alpha-5020220260725001`。这是 HBuilderX/uni-app 编译器版本,不是 Android `minSdkVersion`。
- 四个 DCloud 编译包必须保持同一批次;否则 npm 版 uni-ui 的 easycom 解析可能落入不同的 `uni-cli-shared` 实例,表现为 `<uni-forms>`、`<uni-easyinput>` 等组件无法解析。
## 本地验证与出包
```bash
npm --prefix mobile-uni run generate:app-assets
npm --prefix mobile-uni run verify:app-assets
npm --prefix mobile-uni run typecheck
npm --prefix mobile-uni run build:h5
npm --prefix mobile-uni run build:app
```
云打包完成后必须校验实际 APK,不能只看 HBuilderX 的“打包成功”:
```powershell
npm --prefix mobile-uni run verify:android-apk
```
该命令默认校验 `mobile-uni/dist/debug/android_debug.apk` 自定义基座,包括包名、源码版本、`targetSdkVersion`、调试属性、单签名、APK Signature Scheme v2 和 SHA-256。脚本使用 HBuilderX `app-safe-pack` 内的只读 APK 工具;非默认安装目录可通过 `-HBuilderHome` 指定。
Android 内测包或正式 RC 使用版本化的 `mobile-uni/.env` 保存两个公开法务地址,确保 npm 和 HBuilderX 云打包得到同一配置。地址不是秘密,可由 PowerShell 环境变量覆盖;正式发布前仍须由公司法务签认正文:
```powershell
Remove-Item Env:VITE_DEV_SMS_HINT_ENABLED -ErrorAction SilentlyContinue
Remove-Item Env:VITE_DEV_SMS_HINT_VALUE -ErrorAction SilentlyContinue
npm --prefix mobile-uni run configure:app-legal
npm --prefix mobile-uni run build:app
npm --prefix mobile-uni run verify:app-release
```
`configure:app-legal` 会校验 HTTPS、公网域名和两个地址互不相同,并从模板生成被 Git 忽略的 `mobile-uni/src/androidPrivacy.json`;其唯一职责是明确 `prompt=none`,不再提供启动原生确认。`build:app` 将该配置复制到 `dist/build/app/androidPrivacy.json`,并把项目根的 `AndroidManifest.xml` 与 `nativeResources/android/res/xml/network_security_config.xml` 同步到云打包输入目录。源码、编译产物和实际 APK 都纳入门禁。兼容别名 `configure:app-privacy` 暂时保留。`verify:app-release` 还会确认:
- `manifest.json` 使用 `useOriginalMsgbox=false`,`androidPrivacy.json` 使用 `prompt=none`;
- 登录页默认未勾选协议,服务协议与隐私政策链接来自本次 App 编译的 `VITE_APP_TERMS_URL`、`VITE_APP_PRIVACY_URL`;
- 发送验证码和登录均先通过同一个 `ensureLegalConsent()` 门禁;
- 两个页面可通过公网 HTTPS 访问并包含可识别的协议正文;
- `VITE_DEV_SMS_HINT_ENABLED` 与 `VITE_DEV_SMS_HINT_VALUE` 均未进入发布环境;
- 编译产物不含手机号、固定测试验证码、私钥或常见云端/API 令牌格式。
- Android 清单与网络安全配置均禁止明文 HTTP,并只信任系统证书。
登录页默认不勾选协议。协议地址缺失或不合规时,页面允许查看但禁止发送验证码和登录;测试验证码快捷提示只有开发环境同时显式设置 `VITE_DEV_SMS_HINT_ENABLED=true` 和本机 `VITE_DEV_SMS_HINT_VALUE` 才显示。源码不再内置固定验证码值。
1. 用 HBuilderX 打开 `mobile-uni`,先生成 Android/iOS **自定义运行基座**。标准基座不会加载当前的包名、权限、启动图或原生配置。
2. 在真实 Android 与 iPhone 上验证手机号登录、录音并转写、TTS 播放、图片/视频/文件上传、附件下载、拒绝权限、前后台切换、刘海和底部安全区。
3. Android 试点使用企业签名的正式 APK;上架渠道按渠道要求导出相应制品。iOS 使用企业 Apple Developer 账号的 Distribution 证书和 provisioning profile,先走 TestFlight。
标准基座可用于日常 JavaScript/WebView 兼容性调试,但不能替代自定义基座或签名包的权限、图标、启动图和原生配置验收。
HBuilderX 5.22 当前实测中,自定义调试基座不支持安心打包,新应用也不能再使用公共测试证书;调试基座改用 DCloud 云端证书并通过普通云打包生成,CLI 项目的产物位于 `mobile-uni/dist/debug/android_debug.apk`。该云端证书和调试 APK 不替代企业正式签名资产。
自定义基座 APK 只包含原生调试运行壳,业务 `www` 资源由 HBuilderX 真机运行时另行同步,因此不能要求登录页法务链接出现在基座 APK 内。可直接安装分发的 DCloud 云证书内测包必须使用非自定义基座打包,并用 `dcloud-test` 模式复核包内 `prompt=none`、`app-service.js` 的两个登录页地址和未勾选拦截:
```powershell
& '.\mobile-uni\scripts\verify-android-apk.ps1' `
-ApkPath '.\mobile-uni\dist\debug\bangdao-0.1.13-dcloud-test.apk' `
-BuildKind dcloud-test
```
APK 门禁还会比较包内与当前 `dist/build/app/app-service.js` 的 SHA-256,避免用同版本号的旧包冒充当前源码,并在反编译结果中复查敏感文件、手机号、固定测试验证码、私钥和常见令牌格式;`dcloud-test` 与 `release` 模式都拒绝 `usesCleartextTraffic=true`。
完成代码评审并提交冻结后,从仓库根目录执行统一 RC 证据脚本。默认拒绝脏工作区;`-AllowDirtyRehearsal -SkipBuild` 只能用于验证脚本和 APK,生成的证据会明确标记为不可发布:
```powershell
.\scripts\prepare-aug1-rc.ps1 `
-ApkPath '.\mobile-uni\dist\debug\bangdao-0.1.13-dcloud-test.apk' `
-BuildKind dcloud-test
```
脚本会复跑移动端测试/类型检查/H5/App 构建、管理端构建、后端定向测试和打包,验证 APK 后在被 Git 忽略的 `output/aug1-rc/` 生成标准文件名、哈希及 JSON/Markdown 证据。它不执行生产同步、数据库迁移、服务重启或登录页人工同意操作。
2026-07-28 最终自定义基座大小为 `21,158,193` 字节,SHA-256 为 `82D3352FF96A86F5DB4AC0C71DCB0ED6CEC98F2A785F6EAED2FE8D4FC0C5F704`。2026-07-29 当前独立内测候选包为 `bangdao-0.1.13-dcloud-test.apk`:包名 `com.yincheng.wygj`、版本 `0.1.13 (113)`、`targetSdkVersion=35`,大小 `33,921,543` 字节,SHA-256 为 `FA2D2A6DC84AE759714E6D16D146C1E1552A0F3F53C046069422012361D1D0C0`,签名证书 SHA-256 为 `AB06ECC0DE544DE73C385F3F0690B22966EBC12887FB8BEE1830CDBEFDEBEF5D`。APK 反编译门禁确认包内业务资源等于当前 App-Plus 编译产物、启动原生隐私提示已关闭、登录页法务链接与未勾选拦截及身份加载失败关闭已进入包体,并通过敏感值、`usesCleartextTraffic=false`、`networkSecurityConfig` 和系统证书信任检查。干净提交 `af8af2f6dd169e4616a4ca0ca724e8b809502ab3` 的统一 RC 已完成,`releaseEligible=true`,证据在 `output/aug1-rc/0.1.13-113-af8af2f6-frozen/`;候选后端 JAR SHA-256 为 `93AD272118F6A28F88C2BFA305F5C450E163CBE22577FF5BE3E85B3BD3958DAD`。当前双提交交付包为 `output/aug1-release/bangdao-aug1-0.1.13-113-af8af2f6-opsfee80877.zip`,大小 `192,938,105` 字节、SHA-256 为 `4C7951B185E6CC6689ABAABA1E8783EBF58F82893D242B91DA072BB149A0972C`,17 个条目和内部哈希已复核;包内包含固定码认证复验、内容候选校验和业务内容与五通道签认材料,`opscc1865a9`、`0.1.12` 及更早 RC/交付 ZIP 只保留为历史基线。当前 AVD 为 `x86_64`,APK 原生库仅含 `arm64-v8a/armeabi-v7a`;安装和原生外壳可由系统转译运行,但 DCloud Weex JS 进程实际出现 `spinWaitPeer`/IPC 超时,页面主体空白不能用于判断产品页面。浏览器验证只作补充,不替代 App 运行;不会为了模拟器改变正式 ABI、回退为 H5 壳或增加业务兜底。该包仍使用 DCloud 云端测试证书,只能作为 8 月 1 日受控内测包;企业正式 release 还必须使用签认后的企业证书摘要。
企业正式签名 APK 还必须用发布负责人保管的证书摘要执行 release 模式核验;该模式会额外拒绝 `debuggable=true`、明文 HTTP 和签名摘要不一致:
```powershell
& '.\mobile-uni\scripts\verify-android-apk.ps1' `
-ApkPath '<企业签名 RC APK 绝对路径>' `
-BuildKind release `
-ExpectedSignerSha256 '<已签认的企业证书 SHA-256>'
```
## 发布前尚需提供的资产
- 当前受控内测版《服务协议》《隐私政策》已部署到 `https://peilian.njzhmj.top/legal/`,服务器发布前备份为 `/opt/wygj/backups/www-20260728224710`;仍需公司法务对正文、处理者信息、第三方清单和保存期限正式签认。Android 登录页已使用实际链接且启动不再弹出原生确认;iOS 仍需在后续出包时复核相应的麦克风、相机、相册/文件用途说明。
- 无透明通道的 1024×1024 App Store 图标,以及 Android 自适应图标/启动图。
- 企业持有的 Android 签名证书、Apple Team、Bundle ID 注册与 iOS 发布证书。上述资产缺失时可以完成代码与真机调试,不能声称已具备商店上架条件。
## 已接入的资产与隐私模板
- 图标和启动图由 `scripts/generate-app-assets.sh` 从现有 `src/static/brand-logo.png` 生成,输出位于 `src/static/app/`,并由 `manifest.json` 显式关联。iOS App Store 图标为 1024×1024、无 alpha、未预制圆角;生成后可用 `npm --prefix mobile-uni run verify:app-assets` 校验尺寸和映射。
- 现有品牌源图仅为 64×64,因此这里生成的是**可用于自定义基座和测试包的派生资产**。正式提交商店前应替换为品牌方提供的高分辨率母版,再重新执行生成和预检。
- `androidPrivacy.json.example` 是原生提示策略模板,固定 `prompt=none`;生成文件被 Git 忽略,模板和校验逻辑才是版本化事实源。两个公开法务 URL 的版本化事实源是 `mobile-uni/.env`,`configure:app-legal` 会校验它们,登录页和 APK 门禁必须使用同一组地址。
- iOS 已按实际功能填写麦克风和照片库用途说明;不申请相机、定位、通讯录、蓝牙或广告追踪权限。
- `build:app` 依赖 `@dcloudio/uni-app-plus`,它必须与 `@dcloudio/uni-app`、`@dcloudio/uni-h5`、`@dcloudio/vite-plugin-uni` 同版本。缺少 App 编译器时命令**不报错**,只静默产出带 `/h5/` 基路径的 H5 空壳,产物里没有 `app-service.js` 与 `app-renderjs.js`,App 平台代码等于从未编译。判定 `build:app` 是否真的成功要看产物中是否存在 `app-service.js`、`app-renderjs.js`、`manifest.json`,不能只看 `DONE Build complete.`。
- App-Plus 实时对练通过 `renderjs` 在系统 WebView 中执行媒体/WebRTC;认证 SDP 与工具请求仍由逻辑层代理。发布前必须在 Android/iOS 真机验证麦克风授权、实时转写、远端语音播放、前后台切换和断线降级。
- 真机步骤和证据口径见 `docs/MOBILE_APP_DEVICE_ACCEPTANCE.md`。资源预检通过不等于 Android/iOS 真机或应用商店验收通过。
## 调试基座版本不匹配
若真机提示“本应用使用 HBuilderX X 或对应 CLI 版本编译,而手机端 SDK 版本是 Y”,先核对编译依赖与基座,不要修改 Android `minSdkVersion`:
```bash
node -e "for (const n of ['@dcloudio/uni-app','@dcloudio/uni-app-plus','@dcloudio/uni-h5','@dcloudio/vite-plugin-uni']) console.log(n, require('./mobile-uni/node_modules/'+n+'/package.json').version)"
```
Windows PowerShell 再核对 HBuilderX CLI 与设备;项目已导入 HBuilderX 且设备在线后,才执行最后一条运行命令:
```powershell
& 'D:\HBuilderX\cli.exe' version
& 'D:\HBuilderX\cli.exe' devices list --platform android
& 'D:\HBuilderX\cli.exe' launch app-android `
--project (Resolve-Path '.\mobile-uni').Path --deviceId <adb-serial> `
--playground standard --native-log true
```
标准基座可先验证编译器/SDK 兼容、启动和页面交互;完整权限验收必须先生成 5.22 自定义基座,再把上面的 `standard` 改为 `custom` 重跑。不要在真机运行命令中加 `--compile true`,该参数表示“只编译代码”,不会安装或启动手机端应用。
当前项目依赖已与 HBuilderX 5.22 统一;升级后必须重新生成并安装 5.22 自定义运行基座,旧的 5.15 基座不能继续用于真机验收。命令行资源构建通过只证明编译链可用,不等同于已完成真机基座验证。
## 更新策略
涉及原生权限、插件、证书或 App 壳的改动必须重新云打包并通过应用商店/TestFlight 发布。仅 JavaScript/CSS/静态资源的热更新(WGT)不作为首个试点版本的发布方式;如后续启用,须有版本兼容、完整性校验、灰度与回滚方案。