跳到主内容

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

要在 Flutter 程序中使用 C 代码,请使用 dart:ffi 库。

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

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

本教程演示了如何在 Flutter 插件中捆绑 C/C++ 源代码,并使用 Dart FFI 库在 macOS 上与其绑定。在本演练中,您将创建一个实现 32 位加法的 C 函数,然后通过名为“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 Desktop 应用程序,请使用以下说明

  1. 按照 Flutter desktop 的说明创建 Flutter desktop 应用程序。
  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 互操作性的信息,请查看以下视频