在 iOS 中使用 dart:ffi 调用本地代码
Flutter 移动版可以使用 dart:ffi 库来调用本地的 C API。 FFI 代表 外部功能接口。类似功能的其他术语包括本地接口和语言绑定。
你必须首先确保本地代码已加载,并且其符号对 Dart 可见,然后才能在库或程序使用 FFI 库绑定本地代码。本页主要介绍如何在 Flutter 插件或应用程序中编译、打包和加载 iOS 原生代码。
本教程演示了如何在 Flutter 插件中捆绑 C/C++ 源代码,并在 iOS 上使用 Dart FFI 库绑定和使用。
在本示例中,你将创建一个实现 32 位的加法 C 函数,然后通过名为 "native_add" 的 Dart 插件暴露它。
动态链接 vs 静态链接
#本地库可以动态或静态地链接到应用程序中。一个静态链接库会被嵌入到应用程序的可执行映像中,并在应用程序启动时加载。
静态链接中的符号可以使用 DynamicLibrary.executable
或 DynamicLibrary.process
来加载.
相比之下,动态链接库则分布在应用程序中的单独的文件或文件夹中,并按需加载。在 iOS 上,它是作为 .framework
文件夹分发的。
动态链接库在 Dart 中可以通过 DynamicLibrary.open
加载。
请查看 API 文档: Dart API 参考文档.
创建 FFI 插件
#如果要创建一个名为 "native_add" 的插件,你需要这么做:
flutter create --platforms=android,ios,macos,windows,linux --template=plugin_ffi native_add
cd native_add
C/C++ 源代码会被创建至 native_add/src
。这些源代码在不同平台构建时会生成在不同平台的构建文件夹。
FFI 库只能绑定 C 语言的符号,所以 C++ 语言的符号会被标记为 extern "C"
。
FFI 库只能与 C 符号绑定,因此在 C++ 中,这些符号添加 extern C
标记。还应该添加属性来表明符号是需要被 Dart 引用的,以防止链接器在优化链接时会丢弃符号。
__attribute__((visibility("default"))) __attribute__((used))
.
在 iOS 上 native_add/android/build.gradle
负责关联这些代码。
原生代码会从 lib/native_add_bindings_generated.dart
被 Dart 调用。
代码由 package:ffigen 生成。
其他的用例
#iOS 和 macOS
#动态链接库在应用程序启动时由动态链接器自动加载。它们的组成符号可以用 DynamicLibrary.process
。你还可以使用 DynamicLibrary.open
来限制符号解析的范围,但目前仍然不确定苹果的审查程序将如何处理两者的使用。
你可以使用 DynamicLibrary.executable
或 DynamicLibrary.process
解析静态链接到应用程序二进制文件的符号。
平台库
#要链接到平台库,请按照如下说明:
-
在 Xcode 中,打开
Runner.xcworkspace
。 -
选择目标设备。
-
在 Linked Frameworks and Libraries 中点击 +。
-
选择要链接的系统库。
第一方库
#第一方本地库可以作为源文件或(已签名的).framework
文件被包含在内。它也可能包括静态链接的档案,但需要测试。
源码
#要直接链接到源代码,请按照如下说明:
-
在 Xcode 中,打开
Runner.xcworkspace
。 -
添加 C/C++/Objective-C/Swift 源码到 Xcode 工程中。
-
将以下前缀添加到导出的符号声明中,以确保它们对 Dart 可见:
C/C++/Objective-C
objcextern "C" /* <= C++ only */ __attribute__((visibility("default"))) __attribute__((used))
Swift
swift@_cdecl("myFunctionName")
已编译的动态库
#要链接到已编译过的动态库,请按照如下说明:
-
如果存在已进行签名的
Framework
文件,请打开Runner.xcworkspace
。 -
添加 framework 文件到 Embedded Binaries 区域中。
-
同时将其添加到 Xcode 中目标的 Linked Frameworks & Libraries 部分。
开源的三方库
#要创建一个包含 C/C++/Objective-C 和 Dart 代码的 Flutter 插件,请按照如下说明:
-
在你的插件项目打开
ios/<myproject>.podspec
. -
添加本地代码到
source_files
字段。
本地代码会被静态链接到任何使用这个插件的应用二进制中。
闭源三方库
#要创建包含 Dart 源代码,但 C/C++ 部分是以二进制形式分发的库的 Flutter 插件,请按照如下说明:
-
在你的插件目录打开
ios/<myproject>.podspec
。 -
添加
vendored_frameworks
字段。参考 CocoaPods 示例。
精简 iOS 符号表
#当创建一个 release 档案(IPA)时,符号会被 Xcode 删除。
-
在 Xcode 中, 点击 Target Runner > Build Settings > Strip Style.
-
将 All Symbols 修改为 Non-Global Symbols。
Other Resources
#To learn more about C interoperability, check out these videos:
除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-12-02。 查看文档源码 或者 为本页面内容提出建议。