如何给WebToApp导出APK新增一个功能开关:从Model到Shell配置的端到端Recipe
【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app
📱 WebToApp 是 Android 上功能最全的 Web 转 APK 工具包——一个完全运行在手机上的一站式 APK 工坊,能把网站、HTML、Node.js/PHP/Python/Go 项目打包成可安装应用。本文带你走一遍它最有代表性的开发流程:如何给 APK 导出新增一个功能开关,并解释为什么"预览能用、导出生效不了"是这个项目里最常见的坑。
先看懂链路:一个开关如何从编辑器走到生成的APK
WebToApp 的导出不是一步到位的,而是把WebApp编辑器模型逐层"透传"进 shell 模板。整条链路如下:
| 环节 | 关键文件 | 职责 |
|---|---|---|
| ① 编辑器模型 | WebApp.kt | 所有功能开关的单一事实来源(data class+ 嵌套*Config) |
| ② 导出映射 | ApkBuilder.kt | WebApp.toApkConfig()把模型转成ApkConfig |
| ③ 配置 Schema | ApkConfig.kt | 按功能分块的*Block数据类(MetaBlock、AdBlockBlock、SplashBlock…) |
| ④ JSON 序列化 | ApkConfigJsonFactory.kt | 生成"key" to value键值对,写入app_config.json |
| ⑤ Shell 读取 | ShellModeManager.kt | 用 Gson 解析 JSON,字段靠@SerializedName精确对齐 |
| ⑥ 运行时消费 | shell 同步的运行时代码 | 真正读取开关值并生效 |
⚠️核心陷阱:Shell 端用 Gson 解析配置,而 Gson 对未知/缺失字段静默丢弃——不报错、不打日志。只要 ④ 里的 JSON 键和 ⑤ 里的
@SerializedName差一个字母,这个功能就会"编辑器里开着、导出的 APK 里没生效"。项目把这类问题称为Config Field Drift(配置字段漂移),详见 config-drift.md。
端到端Recipe:新增开关的5步标准动作
官方在 recipes.md 中明确总结:"停在哪一层都不算完"。下面以新增一个readingModeEnabled(阅读模式)开关为例,给出完整步骤:
第1步:Model 层加字段 + 编辑器UI绑定
在 WebApp.kt 的WebApp中加val readingModeEnabled: Boolean = false(复杂配置则新建嵌套*Config类),并在编辑器界面按邻近开关的写法绑定 UI。
第2步:导出映射层(ApkConfig + toApkConfig)
- 在 ApkConfig.kt 合适的
*Block中加对应字段(新领域就加新 Block)。 - 在
ApkBuilder.kt的toApkConfig(...)中把webApp.readingModeEnabled映射进去——这一步日志里通常已有logger.logKeyValue惯例可参考。
第3步:JSON 序列化层加键
在 ApkConfigJsonFactory.kt 的 payload 中追加一行,格式与邻居完全一致:
"readingModeEnabled" to readingMode.enabled,第4步:Shell 配置类型对齐(最关键)
在 ShellModeManager.kt 的ShellConfig数据类中加:
@SerializedName("readingModeEnabled") val readingModeEnabled: Boolean = false,JSON 键名必须与第3步逐字符一致。然后在 shell 同步的运行时消费点(core/shell、core/webview、core/engine等共享包)读取该值并实现行为——注意:shell 的targetSdk很低、依赖集很薄,改动要"外科手术式",不要引入宿主侧依赖。
第5步:跑漂移检查 + 单元测试
./gradlew :app:checkConfigFieldDrift --no-configuration-cache python3 scripts/check_config_field_drift.pyCI 门禁 check_config_field_drift.py 会解析ApkConfigJsonFactory.kt的 payload 键与ShellModeManager.kt的@SerializedName注解并报告不匹配(豁免名单在 config_field_drift_allowlist.json)。涉及打包与 shell 成员变更时,再按 recipes.md 的验证命令构建 shell 模板与增量缓存:
./gradlew :shell:assembleRelease :app:syncShellTemplateApk --no-configuration-cache自检清单:预览正常但导出失效时按顺序排查
- 运行时的 shell 配置 JSON 里真的含有这个字段吗?
- 导出工厂的键名与 shell 端
@SerializedName完全一致吗?(跑checkConfigFieldDrift) - 运行时消费点是否在shell 同步的包里,而不是宿主独占代码?
- 改完同步后是否重建了 shell 模板?(模板过期是高频漏点)
延伸阅读
- 开发文档首页:docs/developer/ —— 架构、导出管线、shell 同步与 i18n 全在此
- 导出管线详解:export-pipeline.md —— 从 AXML/ARSC 二进制补丁到 V1/V2/V3 签名的完整流程
- Shell 同步机制:shell-sync.md
想动手实践的话,先拉一份源码阅读:git clone https://gitcode.com/GitHub_Trending/web/web-to-app,然后沿着本文的5步链路把任意一个现成开关(比如splashEnabled,从 WebApp.kt 到 ShellModeManager.kt)完整读一遍——这是理解 WebToApp 配置透传体系最快的方式。
【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考