棉宇宙App采用原生宿主 + Flutter模块(Add-to-App) 架构,并非纯Flutter应用,因此Flutter热更无法仅通过简单集成SDK实现,必须深度联动现有Jenkins整包流水线、Metax出包体系与自研控制面,形成标准化落地链路。本文聚焦项目实际落地流程,不阐述FlutterPatch控制面从零搭建逻辑。
一、核心落地结论
1. 流水线核心:两条核心Jenkins任务
| Jenkins Job类型 | 核心职责 | 关联能力与参数 |
|---|---|---|
| 整包Job | 打包生成APK/IPA安装包,同步完成OTA基线版本登记,为后续热更提供基准版本 | 依托metax upload能力,绑定版本信息、渠道属性,产出热更基线快照 |
| 热更Job | 基于已上线的基线版本,生成差分热更补丁,完成补丁校验、发布与放量 | 依赖PLATFORM、RELEASE版本参数,支持白名单、预检校验、灰度回滚能力 |
2. 设备侧核心能力
设备端复用Shorebird updater底层能力,自定义对接内部自研控制面(对内命名Meta Code Push),核心规则如下:
- 补丁生效:Dart代码补丁需冷启动生效,无热重启即时生效能力
- 资源热更:图片等静态资源不依赖原生Assets加载,需专用热更API适配
- 链路隔离:设备OTA请求、补丁校验请求均指向内部专属地址,不走官方公共域名
二、技术架构选型原因
项目未采用"简单接入热更SDK"的轻量化方案,是基于早期落地踩坑后的最优决策,核心约束条件有三点:
1. 必须自建热更控制面
官方Shorebird云服务无法适配内网研发环境,存在数据出域风险、国内网络下载不稳定、内网制品无法互通等问题。因此仅复用Shorebird引擎构建能力,设备数据、补丁校验、制品管理全部迁移至内部控制面,彻底隔离官方云服务链路。
2. 统一Metax出包入口
项目所有打包流程(Unity子模块、多渠道包、Appwrite缓存、原生宿主打包)均基于Metax体系。若热更单独搭建命令行流程,会提升研发成本、增加流程出错概率。因此将flutterpatch能力封装至Metax内部,统一开关、环境变量、版本发布、缓存回填的操作入口。
3. 整包与热更规范强对齐
热更补丁必须基于整包Job登记的基线版本生成,严格按照release-version(buildName+buildNumber)版本号对齐。版本不匹配会直接导致补丁下发失败、设备解析异常、功能不生效等问题,因此两套流水线必须遵循同一套版本规范与出包环境。
综上,棉宇宙Flutter热更完整落地链路为:Jenkins → Metax → FlutterPatch → 自研控制面,核心载体是流水线体系,而非单一SDK。
三、工程侧接入规范
1. 双配置文件开关隔离
工程通过两个独立配置文件区分「出包热更开关」和「设备热更链路配置」,禁止混用、新增自定义字段:
(1)metaapp_flutter/pubspec.yaml
仅用于控制打包阶段是否开启FlutterPatch热更能力,不参与设备运行逻辑:
yaml
metax:
shorebird_enabled: true
(2)metaapp_flutter/shorebird.yaml
仅保留控制面认可的标准字段,新增自定义字段会触发CLI报错,配置如下:
yaml
app_id: <uuid>
base_url: https://ota.example.com # 设备OTA、控制面统一请求地址
auto_update: false # 按需配置产品自动更新策略
upload_baselines: true
upload_patch_resources: true
2. 热更开关优先级规则
热更启用优先级从高到低依次为:命令行--useFlutterPatch > 环境变量 > pubspec的metax.shorebird_enabled > 默认关闭。禁止通过配置文件是否存在判断热更状态,鸿蒙系统、源码编译场景会强制屏蔽热更链路,与文件无关。
3. 原生宿主适配改造
Android端
引入FlutterPatch专属Maven依赖坐标,开启keepDebugSymbols配置,保留调试符号,为补丁差分计算提供依赖,避免补丁解析失败。
iOS端
嵌入专属引擎xcframework,产物同步时将ShorebirdFlutter.xcframework重命名为宿主识别的Flutter.xcframework,适配CocoaPods宿主依赖规则。
所有原生适配规则均固化在metax init flutterpatch接入清单中,出包前需执行预检命令,避免流水线末端打包失败。
四、业务侧适配
热更接入后最常见的问题是「补丁下发成功,但图片资源不生效」,核心原因是FlutterGen原生.image()方法为实例方法,Dart扩展无法重写覆盖,无法适配热更资源差分逻辑。
1. 错误写法(无法热更)
arduino
Assets.images.home.icSearchHome.image(width: 24, height: 24);
2. 正确热更写法
arduino
// 写法1:专用热更图片API
Assets.images.home.icSearchHome.patchImage(width: 24, height: 24);
// 写法2:通用热更资源加载API
FlutterPatch.assetImage(Assets.images.home.icSearchHome.path);
代码评审核心卡点:所有静态图片资源必须替换为上述热更专属API,禁止保留原生Assets加载方式。
五、完整流水线落地流程
1. 整包流水线:基线版本登记(热更前置条件)
市场包、测试包沿用原有metax upload打包逻辑,开启shorebird_enabled后自动新增热更基线处理流程:
- 自动生成FLUTTERPATCH_RELEASE_VERSION版本号(x.y.z+build),与应用版本强绑定;
- 根据包类型自动打环境标签:市场包标记prod、测试包标记test,用于控制台筛选管理;
- 执行flutterpatch release命令,编译生成AAR/引擎框架产物,上传至控制面形成基线快照;
- 产物缓存至本地并同步至Appwrite,后续宿主版本未变更时可复用产物,避免重复编译。
出包机环境硬性要求
- 配置全局FLUTTERPATCH_TOKEN,控制面仅校验该令牌权限;
- 禁止配置SHOREBIRD_HOSTED_URL,打包流程会自动清空该配置,防止链路指向官方云服务;
- 出包前执行预检命令:
metax init flutterpatch,校验CLI、Token、base_url、FVM版本合法性。
核心逻辑:整包Job成功执行,即代表商店包与热更基线同步完成,为后续热更补丁提供有效适配靶版本。
2. 热更流水线:补丁生成与放量
仅针对Dart逻辑、可热更资源变更场景使用,版本基线无变更时无需整包,流水线流程如下:
- 参数录入:填写PLATFORM(平台)、RELEASE(基线版本号),可选配置白名单、设备唯一ID;
- 合法性预检:执行
metax check-ota,生成资源适配报告,输出unsupported/supported/resources三种状态,不支持热更的变更直接中断流程; - 补丁生成:校验通过后执行
metax patch,生成对应平台差分补丁; - 灰度放量:默认白名单真机灰度,验证通过后关闭白名单全量发布;
- 异常回滚:问题版本直接控制台rollback撤销发布,不使用反向补丁兜底。
核心参数说明
- CHECK_ONLY=true:仅生成OTA适配检测报告,不产出补丁,用于评审变更是否支持热更;
- FORCE_PATCH:跳过预检强制生成补丁,高危操作,仅用于线上排障,与CHECK_ONLY互斥;
- WHITELIST/UNIQUE_IDS:设备灰度管控,规避全量发布风险。
关键约束
iOS热更仅真机有效,模拟器无法验证Shorebird补丁生效状态,所有测试必须基于真机完成。
3. 设备端生效链路
- Dart代码补丁:设备发起校验 → 差分补丁下载 → 应用冷启动后生效;
- 图片资源补丁:资源合法性校验 → 差分资源拉取 → 业务通过patchImage API加载生效。
补充:桌面客户端支持本地工程预览、线上状态查询、临时补发能力,但正式线上发版以Jenkins流水线为准,值班运维仅需关注流水线参数配置。
六、热更能力边界
1. 支持热更范围
- Dart业务逻辑代码变更;
- 图片 音频 视频 基础资源(需要提前代码写好也可以写完走热更)
2. 不支持热更、必须整包场景
- 原生代码、插件、Flutter引擎大版本变更;
- 字体文件等特殊资源变更(check-ota可自动拦截);
- 应用核心用途变更、违规文案修改(审核红线);
- 无有效整包基线版本,无法匹配差分补丁。
技术定位:本方案基于Shorebird Dart补丁能力+自研控制面实现,区别于Fair动态化方案,热更仅用于线上紧急修复、轻度运营迭代,无法替代应用商店整包发布。