WebToApp Shell模板构建流程:webview_shell.apk 如何从 :shell 模块生成并同步
【免费下载链接】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 是一款在手机上运行完整 APK 工坊的 Web 转 App 工具,其导出功能的核心正是"Shell 模板"——一个名为webview_shell.apk的运行时外壳 APK。本文完整梳理这个模板如何从:shell模块构建、又如何自动同步到宿主应用的 assets 目录,帮你理解"预览正常、导出却失效"这类问题的根源。
一个仓库,三个 Gradle 模块
WebToApp 的构建由 settings.gradle.kts 定义了三个模块,各自分工明确:
| 模块 | 角色 |
|---|---|
:app | 完整宿主:编辑器界面、导出管线、各运行时预览 |
:shell | Shell 模板模块,构建出webview_shell.apk |
:clone-host | APK 克隆/身份重塑支持库 |
关键规则只有一条:共享运行时代码写在app/里,而不是shell/里。shell/目录本身非常薄,只有 shell/src/main/AndroidManifest.xml 和 shell/src/main/java-overrides/ 下的少量覆写文件(如WebToAppApplication.kt、自动启动接收器),其余全部靠同步任务"注入"。
源码同步:syncShellRuntimeSources 任务
shell/build.gradle.kts 定义了两个核心同步任务:
syncShellRuntimeSources:一个Sync任务,按 include/exclude 名单从../app/src/main/java挑选运行时源码,输出到shell/build/generated/shellRuntimeSrc。包含清单覆盖ui/shell、ui/theme、core/webview、core/engine、core/extension、各语言运行时(core/nodejs、core/python、core/php、core/golang)等;排除清单则剔除了宿主专用文件(如WebToAppApplication.kt、EncryptedApkBuilder.kt、FaviconFetcher.kt等)。syncShellRuntimeAssets:一个Copy任务,把app/src/main/assets中的php_router_server.php与web_extensions/**镜像到 shell 的资源目录——这些是 Gecko 引擎安装内置桥接扩展所必需的资产。
两个任务都通过preBuild依赖挂入编译链(见 shell/build.gradle.kts),保证生成源码永远先于编译存在,且只落在build/目录,Git 工作区保持干净。
模板生成:一条命令的完整链路
构建 Shell 模板只需一条命令:
./gradlew :shell:assembleRelease :app:syncShellTemplateApk --no-configuration-cache它背后串联起三步:
:shell:assembleRelease—— 编译 shell 模块的 release 变体。注意它的特殊配置:targetSdk = 28(fork+exec 运行时的硬性前提,不可随意提升)、开启 R8 混淆与资源压缩、通过 shell/proguard-rules.pro 控制裁剪、并用packaging规则剔除omni.ja、Gecko 大体积 so、libcronet*.so等宿主专用二进制。- 产出
shell/build/outputs/apk/release/shell-release.apk—— 这就是模板的原始形态。 :app:syncShellTemplateApk—— app/build.gradle.kts 中注册的Copy任务,把上述 APK 复制到app/src/main/assets/template/并重命名为webview_shell.apk。
自动同步机制:preBuild 钩子与跳过开关
更巧妙的是,模板同步并不需要开发者手动触发:
// app/build.gradle.kts tasks.matching { it.name == "preBuild" }.configureEach { if (!skipShellTemplateSync.get()) { dependsOn("syncShellTemplateApk") } }- 本地构建:每次构建
:app前都会自动重建并同步模板,永远使用最新代码; - CI 场景:可用
-PskipShellTemplateSync=true跳过同步,加快流水线; - 不入库:
webview_shell.apk被.gitignore(*.apk规则)排除,新克隆仓库后首次构建即自动重新生成。
关于模板目录的权威说明见 app/src/main/assets/template/README.md,开发者文档 docs/developer/shell-sync.md 也完整记录了同步规则。
模板生成后如何被使用
模板就位后,导出管线 ApkBuilder 会以它为唯一基础做二进制级补丁:
- 从 assets 提取模板(缺失时才降级为宿主自身 APK,正常流程不应触达);
- 注入
assets/app_config.json配置,运行时由 ShellModeManager.kt 经 Gson 反序列化; - 改写包名、应用名、图标(AXML/ARSC 补丁),按应用类型嵌入运行时资源;
- 经
apksig完成 V1/V2/V3 签名,即最终可安装的 APK。
生成的 APK 启动后走固定路径:WebToAppApplication→ShellModeManager.isShellMode()检测app_config.json→ 解析ShellConfig→ 启动 WebView 与各运行时服务。
关键约束与常见问题清单
⚠️ 以下约束来自 AGENTS.md 与模板 README,是维护模板时最容易踩的坑:
- 唯一模板:禁止引入第二个模板 APK;
- 不要回喂:已签名/已改名的导出产物不能当作模板重新投入构建链;
- 改完要重建:修改 shell 成员关系(include/exclude 清单)或打包逻辑后,务必重跑完整
:shell:assembleRelease+ 模板同步——CI 的 check 任务只编译 debug 变体,不覆盖 R8 与模板管线; - 陈旧模板是高频故障源:"预览正常、导出坏掉"多半是模板未重建,或配置字段名在
ApkConfigJSON 与ShellModeManager的@SerializedName之间漂移,可用scripts/check_config_field_drift.py做门禁检查。
| 关注点 | 对应位置 |
|---|---|
| 什么代码进入 shell | shell/build.gradle.kts 的 include/exclude |
| 模板构建入口 | :shell:assembleRelease+:app:syncShellTemplateApk |
| 模板输出位置 | app/src/main/assets/template/webview_shell.apk |
| Shell 清单组件 | shell/src/main/AndroidManifest.xml |
| 配置漂移门禁 | scripts/check_config_field_drift.py |
总结
WebToApp 的 Shell 模板机制可以概括为一句话:源码在app/,构建在:shell,产物落回app/的 assets。syncShellRuntimeSources保证运行时代码单一源头,syncShellTemplateApk保证模板常新,preBuild钩子保证一切自动发生。理解这条"app → shell → app"的闭环链路,你就掌握了 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),仅供参考