使用 dart:ffi 绑定到原生 macOS 代码

Flutter 移动和桌面应用程序可以使用 dart:ffi 库来调用原生 C API。FFI 代表 外来函数接口。 类似功能的其他术语包括原生接口语言绑定。

在你的库或程序可以使用 FFI 库绑定到原生代码之前,你必须确保原生代码已加载并且其符号对 Dart 可见。此页面重点介绍在 Flutter 插件或应用程序中编译、打包和加载 macOS 原生代码。

本教程演示如何在 Flutter 插件中捆绑 C/C++ 源,并使用 macOS 上的 Dart FFI 库绑定到它们。在此演练中,你将创建一个实现 32 位加法的 C 函数,然后通过名为“native_add”的 Dart 插件公开它。

动态链接与静态链接

原生库可以动态或静态链接到应用程序中。静态链接的库嵌入到应用程序的可执行映像中,并在应用程序启动时加载。

可以使用 DynamicLibrary.executableDynamicLibrary.process 加载静态链接库中的符号。

相比之下,动态链接库分布在应用程序中的单独文件或文件夹中,并按需加载。在 macOS 上,动态链接库以 .framework 文件夹的形式分发。

可以使用 DynamicLibrary.open 将动态链接库加载到 Dart 中。

API 文档可从 Dart 开发频道获取:Dart API 参考文档

创建 FFI 插件

如果您已有插件,请跳过此步骤。

要创建一个名为“native_add”的插件,请执行以下操作

$ flutter create --platforms=macos --template=plugin_ffi native_add
$ cd native_add

这将在 native_add/src 中创建一个带有 C/C++ 源的插件。这些源由各种操作系统构建文件夹中的原生构建文件构建。

FFI 库只能绑定到 C 符号,因此在 C++ 中,这些符号标记为 extern "C"

您还应该添加属性以指示符号是从 Dart 引用的,以防止链接器在链接时优化期间丢弃这些符号。 __attribute__((visibility("default"))) __attribute__((used))

在 iOS 上,native_add/macos/native_add.podspec 链接代码。

本机代码在 lib/native_add_bindings_generated.dart 中从 dart 调用。

绑定使用 package:ffigen 生成。

其他用例

iOS 和 macOS

当应用程序启动时,动态链接库会自动由动态链接器加载。可以使用 DynamicLibrary.process 解析其组成符号。您还可以使用 DynamicLibrary.open 获取库的句柄以限制符号解析的范围,但目前尚不清楚 Apple 的审核流程如何处理此问题。

可以使用 DynamicLibrary.executableDynamicLibrary.process 解析静态链接到应用程序二进制文件中的符号。

平台库

要链接到平台库,请使用以下说明

  1. 在 Xcode 中,打开 Runner.xcworkspace
  2. 选择目标平台。
  3. 链接框架和库部分中,单击+
  4. 选择要链接到的系统库。

第一方库

第一方原生库可以作为源代码或(已签名).framework 文件包含在内。可能还可以包含静态链接归档,但需要进行测试。

源代码

要直接链接到源代码,请使用以下说明

  1. 在 Xcode 中,打开 Runner.xcworkspace
  2. 将 C/C++/Objective-C/Swift 源文件添加到 Xcode 项目。
  3. 将以下前缀添加到导出的符号声明中,以确保 Dart 可见

    C/C++/Objective-C

    extern "C" /* <= C++ only */ __attribute__((visibility("default"))) __attribute__((used))
    

    Swift

    @_cdecl("myFunctionName")
    

已编译(动态)库

要链接到已编译的动态库,请使用以下说明

  1. 如果存在已正确签名的Framework 文件,请打开Runner.xcworkspace
  2. 将框架文件添加到嵌入式二进制文件部分。
  3. 还将其添加到 Xcode 中目标的链接框架和库部分。

已编译(动态)库 (macOS)

要将闭源库添加到Flutter macOS 桌面应用,请使用以下说明

  1. 按照 Flutter 桌面说明创建 Flutter 桌面应用。
  2. 在 Xcode 中打开yourapp/macos/Runner.xcworkspace
    1. 将预编译库 (libyourlibrary.dylib) 拖到Runner/Frameworks
    2. 单击Runner 并转到构建阶段选项卡。
      1. libyourlibrary.dylib 拖到复制捆绑资源列表中。
      2. 嵌入库下,选中复制时代码签名
      3. 使用库链接二进制文件下,将状态设为可选。(我们使用动态链接,无需静态链接。)
    3. 单击Runner 并转到常规选项卡。
      1. libyourlibrary.dylib 拖到框架、库和嵌入式内容列表中。
      2. 选择嵌入和签名
    4. 单击运行器并转到构建设置选项卡。
      1. 搜索路径部分中,配置库搜索路径以包含 libyourlibrary.dylib 所在的路径。
  3. 编辑 lib/main.dart
    1. 使用 DynamicLibrary.open('libyourlibrary.dylib') 动态链接到符号。
    2. 在小组件中的某个位置调用您的本机函数。
  4. 运行 flutter run 并检查您的本机函数是否被调用。
  5. 运行 flutter build macos 以构建自包含的应用程序发布版本。

其他资源

要了解有关 C 互操作性的更多信息,请查看以下视频