Shiply Flutter 动态化常见使用问题
一、明确不支持的场景
1. 构建环境芯片限制
目前 Conch SDK 仅支持 Linux、Mac Intel 芯片。(旧版本 Flutter 3.24 及以前仅支持 Mac)
Mac M 系列芯片(arm64)目前需要安装 Rosetta 才能使用。
2. 不支持 Isolate 热更
补丁热更中使用 Isolate 存在问题,不支持 Isolate 热更,也不支持热更 Isolate.spawn、compute 等切线程代码。新开启的线程无法读取 Conch 运行时实例,可用 @PatchExclude(onlyNode: true) 将 Isolate 调用位置排除出补丁。
另外,不支持非 Dart 代码热更新;差分补丁的 Record 语法在 Conch 1.8.0 之前不支持,1.8.0 及之后已支持。
3. 动态类型无法标记泛型
动态类型无法标记泛型,可能导致调用函数 AOT 时的泛型校验异常。
动态类型创建的对象在 AOT 使用时泛型校验无问题,因为创建动态对象后,会后置正确标记继承的基准类泛型。
同时满足以下三个条件才会触发:
- 继承链路上至少有两层是动态类
- 继承链路上有不定泛型传递,且不定泛型在热更中有两种及以上的使用
- 函数用了类上的不定泛型,且有做不定泛型的校验
二、常见问题
1. Conch 支持哪些 Flutter 版本?
| Flutter 版本 | Android | iOS | 鸿蒙 |
|---|---|---|---|
| 3.16.9 | 支持 | 支持 | — |
| 3.22.3 | 支持 | 支持 | — |
| 3.24.5 | 支持 | 支持 | — |
| 3.27.4 | 支持 | 支持 | 支持 |
| 3.32.8 | 支持 | 支持 | — |
| 3.41.9 | 支持 | 支持 | 支持 |
2. Conch-Flutter未生效
当项目配置文件中 enable: true 同时使用 release 模式编译时,Conch 才会生效。
未生效时常见日志样式:
[ConchLoaderAPI] ConchLoader#load() conch 仅在 release build 模式下生效 (当前为 debug 模式)
[ConchLoaderAPI] ConchLoader#init() conch 仅在 release build 模式下生效 (当前为 debug 模式)
问题排查: 如果没有输出 ConchLoader 的详细日志,说明 Conch 没有生效。此时需要:
- 尝试清理缓存
- 检查配置是否正确
- 确认编译是否为 release 模式
- 检查工程路径是否存在中文,要求英文路径
3. 如何开启 Debug 日志开关
调用 ConchCoreAPI.enableDebugLog() 后会输出详细的 Conch 日志,便于定位和调试。
注意: Debug 模式会影响 App 性能,产品上线前必须关闭。
4. 图片资源热更新未生效
Conch 支持对 App 内的图片资源进行热更新,此功能独立于代码热更新。其原理是通过自定义的 conchBundle,优先从本地的热更新补丁文件中加载图片资源。
4.1 自动更新(无需额外配置)
如果您的应用直接使用 Flutter 官方提供的 Image.asset、SvgPicture.asset、AssetImage 来加载图片,那么 Conch 在应用补丁后会自动处理这些加载请求。
只需在对应的函数上打上 @PatchOnly 注解并制作相应补丁,即可实现图片热更新。Conch 会优先从更新后的补丁文件中加载新图片。
4.2 手动配置(用于自定义图片加载方式)
对于非标准的或自定义的图片资源加载方式,Conch 无法自动识别。为了让热更新对这些图片生效,您需要手动将应用的默认 AssetBundle 替换为 Conch 提供的 conchBundle。
使用方法:
在 widget 树最外层套一层 DefaultAssetBundle,使所有资源加载都默认使用此 bundle:
DefaultAssetBundle(
bundle: conchBundle,
child: Widget(),
);
5. 制作补丁时报 IconTreeShakerException
在制作补丁时可能会遇到以下错误:
Target aot_android_asset_bundle failed: IconTreeShakerException: ConstFinder failure: Unhandled exception:
Bad state: Empty input given.
#0 BinaryBuilder._checkEmptyInput (package:kernel/binary/ast_from_binary.dart:657:29)
#1 BinaryBuilder.readComponent.<anonymous closure> (package:kernel/binary/ast_from_binary.dart:681:7)
#2 Timeline.timeSync (dart:developer/timeline.dart:173:22)
#3 BinaryBuilder.readComponent (package:kernel/binary/ast_from_binary.dart:679:21)
#4 loadComponentFromBytes (package:kernel/kernel.dart:33:28)
#5 loadComponentFromBinary (package:kernel/kernel.dart:28:10)
#6 ConstFinder.findInstances (package:const_finder/const_finder.dart:199:35)
#7 main (file:///Users/xydevops/tgclubDevops/devops_single/workspace/flutter_engine/src/flutter/tools/const_finder/bin/main.dart:103:41)
#8 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:295:33)
#9 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
To disable icon tree shaking, pass --no-tree-shake-icons to the requested flutter build command
解决方案:
在构建补丁时添加 --no-tree-shake-icons 参数:
flutter build patch --no-tree-shake-icons
6. 改动的内容不想打入补丁
如果有修改的内容不想打入补丁,可以用 @PatchExclude() 注解排除。@PatchExclude() 可以打在类或方法上。
@PatchExclude():默认排除整个文件,该文件都不能热修。@PatchExclude(onlyNode: true):只排除单个节点。
排除整个文件:
() // 整文件都不能热修
class SomeClass {
// 该文件的所有改动都不会被打入补丁
}
排除单个节点:
(onlyNode: true)
void someMethod() {
// 仅该方法的改动不会被打入补丁
}
7. 查看差分补丁的差异和扩散内容
打差分补丁时,进行如下配置可以查看对比差异和扩散的内容:
conch:
debugDiff: true # 打印对比的差异内容
debugDiffCall: true # 打印由差异点扩散的内容
8. 如何进行多版本的补丁打包?
多版本编译:在项目工程 /conch_base/ 下放入多个 conch_base_vxxxx.json 基准文件,编译时将针对不同版本输出多份补丁。
可选配置:
conch:
``# conch_base_vxx.json文件中的版本号
targetBaseVersions: v8.8.8.8、v9.8.8.8 # 有多份基准文件编译补丁时,自定义打哪些版本的补丁
9. 编译时报 AOT snapshotter 退出码 -9
此错误通常由以下两种原因导致:
9.1 macOS 安全限制
问题描述:macOS 系统阻止了 Flutter 引擎执行。
解决方案:
运行 SDK 包中的处理脚本,参照 SDK 接入指引中的 "macOS 弹窗问题处理方法",运行 SDK 包中的 xattr_quarantine_inFlutter.sh 脚本即可解决。
9.2 Android 堆内存不足
问题描述:在构建大型项目或资源密集型操作时出现内存不足。
解决方案:
修改 android/gradle.properties 文件,增加堆内存设置:
org.gradle.jvmargs=-Xmx8192M
三、进阶使用
1. 三方库热更新
默认只覆盖主工程。通过 dependencies 引入的 package 要热更,必须在构建基准包时用 moduleIncludes 把它配进业务范围,主工程本身不用再写一遍。配置后该模块支持函数热修,页面热更也会扩散到该模块,并在基准包中保留该范围内调用的 API。
范围只配实际会改的业务模块。配得过多会明显增大基准包体积,不建议把大量三方库加进去。
conch:
moduleIncludes:
- package:xxx
2. 原子组件 / 基类
改原子组件或基类(新增成员、改成员签名、改继承链路等)时,diff 模式下所有子类都会被扩散进补丁,补丁体积容易明显变大。基类尽量不要改动。