Flutter 移动和桌面应用可以使用 dart:ffi 库调用原生 C API。FFI外部函数接口 的缩写。其他类似的术语包括原生接口语言绑定

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

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

动态链接与静态链接

#

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

可以通过 DynamicLibrary.executableDynamicLibrary.process 加载静态链接库的符号。

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

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

API 文档可从 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. 在 **Linked Frameworks and Libraries** 部分单击 **+**。
  4. 选择要链接的系统库。

第一方库

#

第一方原生库可以包含为源文件,也可以包含为(已签名的).framework 文件。可能也可以包含静态链接的存档,但这需要进行测试。

源文件

#

要直接链接到源文件,请按照以下说明操作:

  1. 在 Xcode 中,打开 Runner.xcworkspace

  2. 将 C/C++/Objective-C/Swift 源文件添加到 Xcode 项目。

  3. 在导出的符号声明中添加以下前缀,以确保它们对 Dart 可见:

    C/C++/Objective-C

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

    Swift

    swift
    @_cdecl("myFunctionName")

已编译(动态)库

#

要链接到已编译的动态库,请按照以下说明操作:

  1. 如果存在已正确签名的 Framework 文件,请打开 Runner.xcworkspace
  2. 将框架文件添加到 **Embedded Binaries** 部分。
  3. 也将其添加到 Xcode 中目标的 **Linked Frameworks & Libraries** 部分。

已编译(动态)库(macOS)

#

要为 Flutter macOS 桌面 应用添加闭源库,请按照以下说明操作:

  1. 按照 Flutter 桌面应用的说明创建 Flutter 桌面应用。
  2. 在 Xcode 中打开 yourapp/macos/Runner.xcworkspace
    1. 将您的预编译库(libyourlibrary.dylib)拖到 Runner/Frameworks 文件夹中。
    2. 单击 Runner 并转到 **Build Phases** 选项卡。
      1. libyourlibrary.dylib 拖到 **Copy Bundle Resources** 列表中。
      2. Embed Libraries 下,勾选 Code Sign on Copy
      3. Link Binary With Libraries 下,将状态设置为 Optional。(我们使用动态链接,无需静态链接。)
    3. 单击 Runner 并转到 **General** 选项卡。
      1. libyourlibrary.dylib 拖到 **Frameworks, Libraries and Embedded Content** 列表中。
      2. 选择 **Embed & Sign**。
    4. 单击 **Runner** 并转到 **Build Settings** 选项卡。
      1. 在 **Search Paths** 部分配置 **Library Search Paths**,以包含 libyourlibrary.dylib 所在路径。
  3. 编辑 lib/main.dart
    1. 使用 DynamicLibrary.open('libyourlibrary.dylib') 来动态链接符号。
    2. 在小部件中的某个位置调用您的原生函数。
  4. 运行 flutter run 并检查您的原生函数是否被调用。
  5. 运行 flutter build macos 来构建一个自包含的发布版本应用。

其他资源

#

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