常见改动配方
日常工作的默认做法。把每条链路走到底;停在 UI 或宿主专属代码上,正是预览与导出分叉的原因。
1. 添加或修改宿主 UI 字符串
- 在正确的
Strings*拆分中添加属性,覆盖全部 10 种语言。 - 像相邻代码那样从 Compose/UI 引用它。
见国际化。
2. 添加一个必须影响生成 APK 的编辑器设置
追踪并更新全部:
- 模型(
WebApp/ 嵌套配置)与编辑器 UI 绑定。 - 导出映射(
ApkBuilder/ApkConfig/ApkConfigJsonFactory)。 - shell 配置类型(
ShellModeManager/ shell 配置数据类),如果运行时读取它们。 - shell 同步代码中的运行时使用点。
- 当开关变化时,为导出接线编写单元测试。
见配置字段漂移。
3. 修改每个生成应用都用的 shell 运行时行为
- 编辑
app/下的源码(共享运行时)。 - 确认该文件被
syncShellRuntimeSources包含。 - 若需验证打包,重建 shell 模板。
- 保持改动外科手术式精准;shell 有低
targetSdk和精简依赖集。 - 若触及 FGS / 通知渠道创建,通过
SafeNotificationChannels软失败。
4. 添加宿主专属功能(编辑器、市场、工具)
- 把实现放在宿主专属包(
core/apkbuilder、宿主界面、sample/market、core/host……)。 - 不要把宿主专属依赖拉进
shell/build.gradle.kts。
5. 触及 APK 导出或增量重建
- 优先用
ApkBuildCache/ 内容哈希,而非时间戳。 - 加密构建保持全量重建。
- 不要把已签名输出当作模板。
- 若模板字节变化,确保缓存键正确失效。
6. 修改通知 / 引擎 / 网络加固
- 优先用现有渠道抽象(polyfill / 轮询 / WebSocket / FCM)。
- 默认不要添加 OEM 推送 SDK。
- FGS 渠道创建路径必须容忍 OEM/渠道失败。
7. 模块市场 / modules/
- 遵循
modules/README.md的目录布局(registry.json+ 模块文件夹)。 - 若随生成 APK 一起发布,运行时消费仍走扩展/shell 路径。
8. 本地服务运行时 / 下载路径
- 通过
PortManager以配置的冲突策略分配端口;实现真正的停止处理器。 - 当 fork+exec 进程需要宿主 DNS/proxy 环境时,接入
LocalDnsBridgeProxy。 - 大型依赖 / 引擎 / 运行时下载使用
NetworkModule.downloadClient。
9. Node.js / Go 导出
- Node.js: 确保
injectNodeJsNativeLibs嵌入libnode_bridge.so+libnode.so(经ElfAligner16k16KB 对齐)+libc++_shared.so。Node 二进制解析优先nativeLibraryDir,回退到下载缓存。 - Go: 确保
injectGoExecLoaderNativeLib嵌入libgo_exec_loader.so。 NodeService运行在独立的:nodejs操作系统进程中,使 V8 生命周期与宿主隔离。
验证命令
bash
./gradlew :shell:assembleRelease :app:syncShellTemplateApk --no-configuration-cache
./gradlew :app:compileDebugKotlin -x syncCloneHostDex --no-configuration-cache
./gradlew :app:checkConfigFieldDrift --no-configuration-cache
python3 scripts/check_config_field_drift.py当你改动 shell 成员、导出打包或配置字段时使用这些。对于宿主专属的 UI/字符串工作,通常对 :app 做定向编译即可。
附近编辑后常值得运行的聚焦测试:ApkBuildCacheTest、AdBlockerHostRuntimeTest、AdBlockExportWiringTest、PortManagerTest、BuildInputPreflightTest、GoBuildEnvironmentTest、RuntimePermissionSyncTest。
