PAYATHON 2026

Flutter 如何通过 Dart Hooks 集成闭源动态库并排查 Bare 加载失败?

数据阿明

结论:先修正插件解析目标,再检查动态库是否可加载

当前最明确的异常是:Android 打包代码提供了 libbare-dns.2.1.4.so,Bare 却尝试加载 linked:libbare-dns.2.1.4.dylib。两个名称不一致,应先检查 JavaScript bundle 的目标平台和插件解析结果。

现有日志不足以确定是否同时存在 APK 缺库、ABI 不匹配或依赖库缺失的问题。日志末尾被截断,材料中也没有实际的 APK 截图。

为什么添加 CodeAsset 后仍会失败?

CodeAsset 和 DynamicLoadingBundled() 用于向 Dart、Flutter 构建流程声明需要随应用分发的代码资产,但不会自动改写 JavaScript bundle 中 Bare 插件的解析名称。code_assets 官方说明

因此,需要同时满足两个条件:

  • Flutter 构建产物中包含目标设备能够使用的动态库。
  • Bare 解析出的插件名称与原生加载器实际能够找到的库相符。

简单 JavaScript 能运行,说明基本执行链路已经打通。调用 bare-tcp 后才出现失败,应重点排查新增的原生插件依赖。

1. 为 Android 重新生成 JavaScript bundle

如果使用 bare-pack,先检查打包命令是否明确指定了目标平台。它默认以执行打包命令的宿主平台和架构为目标;在 macOS 上打包时,不能依赖默认值生成 Android 所需的解析结果。bare-pack 官方文档

针对当前 Android ARM64 场景,可参考:

npx bare-pack --host android-arm64 --linked --out ipc_test.bundle <实际入口文件>

将 <实际入口文件> 替换为项目的 JavaScript 入口。该示例以所用 bare-pack 版本支持这些选项为前提,可以先通过 npx bare-pack --help 核对。

--linked 让原生插件使用 linked: 解析。官方文档给出的 Android、Linux 命名形式为 linked:libaddon.1.0.0.so。bare-pack 链接选项说明

开发机是 macOS,错误中的候选名称又以 .dylib 结尾,bundle 可能保留了 macOS 的解析结果。但没有原始打包命令,暂时无法确认。重新打包后,还要确保 Flutter 实际加载的是更新后的 bundle。

不要通过把 .so 改名为 .dylib 来掩盖差异。改名不会改变二进制的目标平台、ABI 或插件解析配置。

2. 检查 Hooks 使用的是目标平台配置

现有代码将文件路径固定到了 Android ARM64:

output.assets.code.add(
  CodeAsset(
    package: input.packageName,
    name: 'libbare-dns.2.1.4.so',
    linkMode: DynamicLoadingBundled(),
    file: input.packageRoot.resolve(
      'lib/src/bare/libs/android/arm64/arm64-v8a/'
      'libbare-dns.2.1.4.so',
    ),
  ),
);

这个片段用于打包预编译库,前提是对应的 Android ARM64 产物存在且兼容。构建其他平台或架构时,需要根据 hook 输入的目标 OS 和目标架构选择文件,不能依据运行 hook 的开发机平台选库。

CodeAsset.name 用于组成 Dart 侧的资产标识。将它设为库文件名,并不意味着 Bare 会通过该标识查找插件,也不能仅凭这个字段确认 APK 内的最终文件路径。Dart Hooks 资产说明

3. 核对 APK 中的实际库名和 ABI

修正 bundle 后,再检查最终安装包:

  1. 是否包含 libbare-dns.2.1.4.so,名称是否与 Bare 的候选名称一致。
  2. 对 Android ARM64 构建,是否包含对应的 arm64-v8a 原生库。
  3. 文件是否确实为 Android ELF 共享库,而非 macOS Mach-O 文件。
  4. Bare 使用的加载方式是否能访问该库所在位置。
  5. 是否包含插件所需的其他动态库,而不只是 bare-dns 这一项。

文件存在于 APK 中只能证明它被打包,不能保证运行时加载成功。

如果 Hooks 的最终打包结果无法满足 Bare 按库名加载的要求,可以参考 Bare 官方 Android 示例,将原生插件纳入 Android 构建流程。该示例通过 Gradle 把插件产物包含到 APK 中;迁移时应避免同一库被重复打包。Bare Android 示例

4. 根据完整 dlopen 错误继续排查

重新运行后,保留完整的 dlopen failed 信息:

  • 仍然寻找 .dylib:继续检查 bundle 的目标平台、解析配置,以及实际加载的 bundle 是否已更新。
  • 寻找 .so 但提示找不到:检查最终文件名、打包位置和加载器搜索路径。
  • 提示其他依赖库找不到:检查该插件的传递依赖是否完整。
  • 提示架构错误或符号找不到:核对 ABI,以及插件与 bare-kit 的二进制兼容性。

当前应优先解决 .dylib 与 .so 的解析差异,再根据完整错误判断是否需要调整 Hooks 或 Android 原生库打包方式。

备注:内容仅供参考。