跳到主要内容

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. 继承链路上至少有两层是动态类
  2. 继承链路上有不定泛型传递,且不定泛型在热更中有两种及以上的使用
  3. 函数用了类上的不定泛型,且有做不定泛型的校验

二、常见问题​

1. Conch 支持哪些 Flutter 版本?​

Flutter 版本AndroidiOS鸿蒙
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 没有生效。此时需要:

  1. 尝试清理缓存
  2. 检查配置是否正确
  3. 确认编译是否为 release 模式
  4. 检查工程路径是否存在中文,要求英文路径

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 模式下所有子类都会被扩散进补丁,补丁体积容易明显变大。基类尽量不要改动。

这篇文档对您有帮助吗?