Skip to main content

“使用 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 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 互操作性的信息,请查看以下视频: