77 lines
6.8 KiB
Markdown
77 lines
6.8 KiB
Markdown
# DSH 工作台(Android)
|
||
|
||
DSH Web Manager 的 Android 客户端:使用随 APK 打包的 Mozilla GeckoView 内核,不依赖手机的系统 WebView。全部构建在 Docker 内完成,宿主机无需安装 Flutter/Android SDK。
|
||
|
||
## 特性
|
||
|
||
- 内置 GeckoView:Flutter 平台视图连接原生 GeckoSession,各设备使用同一发布版本的内核
|
||
- 登录状态持久化:使用非隐私 Gecko profile,持久 Cookie + DOM 存储跨重启保留(会话有效期仍由站点控制)
|
||
- 全面屏适配:edge-to-edge、刘海/挖孔 `shortEdges`、深色启动底色无白闪
|
||
- 文件上传:`<input type="file">` 走系统文件选择器(工作区上传、备份导入)
|
||
- 普通文件上传通过系统授权 URI 流式复制到应用私有临时目录后交给 Gecko,兼容下载目录和文档提供程序;需要足够的本地临时空间。已交给页面的临时文件保留至浏览会话关闭,避免提前删除中断上传。
|
||
- 文件下载:直接保存 Gecko 已认证请求的响应流,由系统“另存为”选择位置,不通过系统 WebView 获取 Cookie
|
||
- 下载状态通知:保存时显示进度和已下载大小,完成、失败或取消后更新状态;通知不提供打开文件或目录的操作。未知总大小时显示不定进度。Android 13+ 首次下载请求通知权限,拒绝不会阻止下载。
|
||
- 返回键:优先回退页面历史,无历史时退出应用
|
||
- 加载失败重试页、JS 原生对话框桥接
|
||
|
||
## 构建
|
||
|
||
前置:本机可用 Docker(构建通过代理访问 Google/Gradle 源时需在环境变量中提供 `http_proxy`/`https_proxy`)。
|
||
|
||
Java/Gradle 不自动使用上述代理变量。需要时另外设置 `JAVA_TOOL_OPTIONS`,例如 `-Dhttp.proxyHost=代理主机 -Dhttp.proxyPort=端口 -Dhttps.proxyHost=代理主机 -Dhttps.proxyPort=端口`;`build.sh` 会将其传入镜像构建和 APK 构建容器。代理必须能从容器访问,不要把宿主机的 `127.0.0.1` 直接当成容器代理地址。Java 会输出此变量,切勿在其中放入密码或其他秘密。
|
||
|
||
```sh
|
||
./build.sh https://panel.example.com --keystore /安全路径/dsh-release.jks --alias dsh-release
|
||
```
|
||
|
||
脚本做两件事:
|
||
|
||
1. 若本地没有 `dsh-appbuilder:3.47.7` 镜像,先构建它(Flutter 3.47.7 + Android SDK + 预热 Gradle/NDK 缓存,首次约 20–40 分钟)。
|
||
2. 在容器内执行 `flutter build apk --release --split-per-abi --obfuscate`。
|
||
|
||
产物在 `build/app/outputs/flutter-apk/`:
|
||
|
||
- `app-arm64-v8a-release.apk`:主流 64 位手机(一般装这个)
|
||
- `app-armeabi-v7a-release.apk`:老设备
|
||
- `app-x86_64-release.apk`:模拟器/ChromeOS
|
||
|
||
## 配置
|
||
|
||
站点地址由 `build.sh` 的第一个参数传入,通过 `--dart-define=DSH_SITE_URL=...` 编译进 APK,无需修改源码,应用启动时也无需输入。必须使用完整 HTTPS URL,可带端口和路径,不能带账号密码、空白、查询参数或片段。脚本在编译前验证地址并运行测试;地址不会写入 Docker 镜像。示例域名仅供说明,请替换为真实站点。
|
||
|
||
需要强制重建工具链镜像时,在上述命令后加 `--no-cache`。更换地址必须重新打包,已有 APK 不会自动更新。
|
||
|
||
## Release 签名
|
||
|
||
`--keystore` 指向包含私钥的 JKS/PKCS12 密钥库(不是网站 TLS 证书,也不是仅含公钥的 .cer);`--alias` 指定私钥条目。相对路径基于运行命令时的目录。脚本需要 Bash,密码默认隐藏输入,私钥密码回车时沿用密钥库密码。
|
||
|
||
CI 可通过 secret 管理器注入 `DSH_STORE_PASSWORD` 和 `DSH_KEY_PASSWORD` 环境变量;后者省略时沿用前者。不支持把密码作为命令参数。密码会传入临时容器环境,Docker 管理员可查看,因此仅在可信的 Docker 主机上构建。不要使用 shell 跟踪(`bash -x`)或把密码打印到日志。
|
||
|
||
密钥库以只读 bind mount 提供给容器,不复制进镜像。推荐把密钥库放在仓库外;常见密钥扩展名及 signing/ 已从 Docker 构建上下文排除。密钥库和密码必须备份,覆盖升级需要保持包名与签名一致。
|
||
|
||
## 注意事项
|
||
|
||
- **系统要求**:当前 GeckoView 158 最低支持 Android 8.0(API 26),构建使用 Android SDK 37.0;旧 Android 设备不能安装此版本。已有工具链镜像可用 `--no-cache` 重建以预装新 SDK。
|
||
- **证书**:反代必须使用 Gecko 信任的有效证书(如 Let's Encrypt)。不提供忽略 TLS 错误或自签证书放行开关。
|
||
- **签名**:release 必须提供外部密钥库;缺失配置或密码/alias 不正确时构建失败,不回退到 debug 签名。此前的 debug 签名 APK 无法被新签名直接覆盖安装。
|
||
- **升级迁移**:旧版系统 WebView 的 Cookie/LocalStorage 不会迁移到 Gecko;首次升级需重新登录,服务器端数据不受影响。
|
||
- **内核更新**:GeckoView 版本固定在 `android/app/build.gradle.kts`,来自 Mozilla 官方 Maven 仓库。内核随 APK 发布,不会自动下载替换;应定期检查稳定版安全更新,更新版本并完成回归后发布新 APK。
|
||
- **开源许可**:GeckoView/Gecko 包含 MPL 2.0 等许可证下的组件。分发 APK 时需保留上游许可声明并履行相应源码提供义务;参见 [Mozilla 许可说明](https://www.mozilla.org/MPL/) 与 [GeckoView 项目](https://mozilla.github.io/geckoview/)。
|
||
- **体积**:APK 包含 Gecko 原生库,体积会明显增加;继续按 ABI 分包,用户只安装匹配设备架构的 APK。
|
||
- **下载生命周期**:保存过程中请保持应用运行;退出应用或进程被系统终止会中断下载,不提供系统 DownloadManager 的后台续传能力。
|
||
- **图标**:使用仓库根目录的 `logo.webp`。API 26+ 使用浅冰蓝底色的自适应图标,旧系统使用同一 logo 的传统图标;各密度资源均已生成。
|
||
|
||
## 内核升级回归
|
||
|
||
发布前除 `flutter analyze`、`flutter test` 和 APK 构建外,应在真实 Android 设备上检查:
|
||
|
||
- 登录后重启应用,确认站点的持久登录状态及本地存储保留。
|
||
- 工作区单文件/多文件上传、选择器取消、配置备份导入。
|
||
- 从下载目录、内部存储及云盘提供程序选择文件;验证中文名、同名多选、空文件、大文件、复制失败及复制中退出。目录上传仍走 Gecko 原有目录 URI 处理路径,需单独验收。
|
||
- 需要登录的文件、目录 ZIP、配置备份下载,检查保存内容及取消流程。
|
||
- 下载通知:已知/未知总大小、多个下载、断网/保存失败、退出取消;Android 13+ 通知权限允许和拒绝,以及系统关闭通知的情况。
|
||
- JS alert/confirm/prompt、输入法、页面滚动、SPA 返回键、横竖屏及前后台切换。
|
||
- 断网重试与无效证书拒绝;确认没有绕过 TLS 校验。
|
||
|
||
Flutter 桥接单测不运行 Gecko 内核,不能替代上述真机测试。
|