跳至主要内容

使用 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. 在“链接的框架和库”部分中点击+
  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. 将框架文件添加到“嵌入的二进制文件”部分。
  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. 点击 Runner 并转到“构建设置”选项卡。
      1. 在“搜索路径”部分中,配置“库搜索路径”以包含 libyourlibrary.dylib 所在的路径。
  3. 编辑 lib/main.dart
    1. 使用 DynamicLibrary.open('libyourlibrary.dylib') 动态链接到符号。
    2. 在小部件中的某个位置调用您的原生函数。
  4. 运行 flutter run 并检查您的原生函数是否被调用。
  5. 运行 flutter build macos 以构建应用程序的自包含发布版本。

其他资源

#

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