使用 dart:ffi 与 C 进行交互
示例
快速上手的 hello_world
集成并加载 C 库
- Interfacing with native types
使用 package:ffigen 生成 FFI 的绑定
- Building and bundling native assets
Dart 的移动端、命令行和服务端应用所运行的 Dart 原生平台,均可以使用 dart:ffi
库调用原生的 C 语言 API,用于读、写、分配和销毁原生内存。
FFI 指的是 外部函数接口。类似的术语包括 原生接口 和 语言绑定。
相关的 API 文档可在
dart:ffi
API 文档
查看。
示例
以下的示例将展示如何使用 dart:ffi
库:
|
|
---|---|
hello_world | |
primitives | |
structs | |
sqlite |
快速上手的 hello_world
hello_world 示例 展示了如何用最少的代码调用 C 语言库。
文件
hello_world 示例包含了以下文件:
|
|
---|---|
hello.dart | hello_world() 函数的文件。 |
pubspec.yaml | |
hello_library/hello.h | hello_world() 函数。 |
hello_library/hello.c | hello.h 并实现了 hello_world() 函数。 |
hello_library/hello.def | |
hello_library/CMakeLists.txt |
构建 C 代码库时将创建几个文件,包括动态库
libhello.dylib
(仅 macOS)、
libhello.dll
(仅 Windows)或 libhello.so
(仅 Linux)。
构建并运行
以下是构建动态库并执行 Dart 应用的示例:
$ cd hello_library
$ cmake .
...
$ make
...
$ cd ..
$ dart pub get
$ dart run hello.dart
Hello World
使用 dart:ffi
hello.dart
文件
阐述了使用 dart:ffi 调用 C 函数的步骤:
-
导入
dart:ffi
。 -
导入
path
库用于合成动态库的路径。 -
为 C 函数的 FFI 类型签名的定义一个类型。
-
为调用 C 函数的变量定义一个类型。
-
利用一个变量保存动态库的路径。
-
加载包含 C 函数的动态库。
-
创建该 C 函数的引用,接着将其赋予变量。
-
调用 C 函数。
以下是每一个步骤对应的代码。
-
导入 dart:ffi。
import 'dart:ffi' as ffi;
-
导入
path
库用于合成动态库的路径。
import 'dart:io' show Platform, Directory;
import 'package:path/path.dart' as path;
-
为 C 函数的 FFI 类型签名的定义一个类型。
参阅 定义原生类型的接口 了解dart:ffi
库中定义的常用类型。
typedef hello_world_func = ffi.Void Function();
-
为调用 C 函数的变量定义一个类型。
typedef HelloWorld = void Function();
-
利用一个变量保存动态库的路径。
var libraryPath = path.join(Directory.current.path, 'hello_library',
'libhello.so');
if (Platform.isMacOS) {
libraryPath = path.join(Directory.current.path, 'hello_library',
'libhello.dylib');
} else if (Platform.isWindows) {
libraryPath = path.join(Directory.current.path, 'hello_library',
'Debug', 'hello.dll');
}
-
加载包含 C 函数的动态库。
final dylib = ffi.DynamicLibrary.open(libraryPath);
-
创建该 C 函数的引用,接着将其赋予变量。这段代码使用了步骤 2 和 3 定义的类型,以及步骤 4 创建的动态库变量。
final HelloWorld hello = dylib
.lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
.asFunction();
-
调用 C 函数。
hello();
当你理解 hello_world 示例的内容后,可以进一步学习 其他的 dart:ffi
示例。
集成并加载 C 库
根据平台和库的类型的不同,捆绑(或 打包 和 分发) C 库到 package 或应用并进行加载的方式,有所不同。
Interfacing with native types
The dart:ffi
library provides multiple types
that implement NativeType
and represent native types in C.
Some native types are only used as markers in type signatures while others (or their subtypes) can be instantiated.
Instantiable native types
The following native types can be used as markers in type signatures and they (or their subtypes) can be instantiated in Dart code:
Dart type | Description |
---|---|
Array | A fixed-sized array of items. Supertype of type specific arrays. |
Pointer | Represents a pointer into native C memory. |
Struct | The supertype of all FFI struct types. |
Union | The supertype of all FFI union types. |
Purely marker native types
The following are platform-agnostic native types that are used only as markers in type signatures, and can’t be instantiated in Dart code:
Dart type | Description |
---|---|
Bool | Represents a native bool in C. |
Double | Represents a native 64 bit double in C. |
Float | Represents a native 32 bit float in C. |
Int8 | Represents a native signed 8 bit integer in C. |
Int16 | Represents a native signed 16 bit integer in C. |
Int32 | Represents a native signed 32 bit integer in C. |
Int64 | Represents a native signed 64 bit integer in C. |
NativeFunction | Represents a function type in C. |
Opaque | The supertype of all opaque types in C. |
Uint8 | Represents a native unsigned 8 bit integer in C. |
Uint16 | Represents a native unsigned 16 bit integer in C. |
Uint32 | Represents a native unsigned 32 bit integer in C. |
Uint64 | Represents a native unsigned 64 bit integer in C. |
Void | Represents the void type in C. |
There are also many ABI specific marker native types that extend AbiSpecificInteger. Refer to their linked API documentation for more information and a guideline on what types they map to on specific platforms:
Dart type | Description |
---|---|
AbiSpecificInteger | The supertype of all ABI-specific integer types. |
Int | Represents the int type in C. |
IntPtr | Represents the intptr_t type in C. |
Long | Represents the long int (long ) type in C. |
LongLong | Represents the long long type in C. |
Short | Represents the short type in C. |
SignedChar | Represents the signed char type in C. |
Size | Represents the size_t type in C. |
UintPtr | Represents the uintptr_t type in C. |
UnsignedChar | Represents the unsigned char type in C. |
UnsignedInt | Represents the unsigned int type in C. |
UnsignedLong | Represents the unsigned long int (unsigned long ) type in C. |
UnsignedLongLong | Represents the unsigned long long type in C. |
UnsignedShort | Represents the unsigned short type in C. |
WChar | Represents the wchar_t type in C. |
package:ffigen
生成 FFI 的绑定
使用 为大量的 API 编写绑定可能要花费你的大量时间。你可以使用 package:ffigen
绑定生成器,自动地从 C 头文件生成 FFI 包装,从而减少时间消耗。
Building and bundling native assets
The Native Assets feature aims to resolve a number of issues associated with the distribution of Dart packages that depend on native code. It does so by providing uniform hooks for integrating with various build systems involved in building Flutter and standalone Dart applications.
The Native Assets feature aims to make it seamless for Dart packages to depend on and use native code:
- It builds (if needed) the native code or
obtains the binaries using a package’s
build.dart
script. - It bundles the native
Asset
reported by thebuild.dart
script. - It makes the native assets available at runtime through
declarative
@Native<>() extern
functions using theassetId
.
The flutter run
/ flutter build
and dart run
/ dart build
tools
will now build and bundle native code when
opted in to the native experiment.
native_add_library
Walkthrough of The native_add_library
example has the minimum necessary code for
building and bundling C code in a Dart package.
The example has the following files:
Source file | Description |
---|---|
src/native_add_library.c |
The C file containing the code for add . |
lib/native_add_library.dart |
The Dart file that invokes the C function add in asset package:native_add_library/native_add_library.dart through FFI. (Note that asset id defaults to the library uri.) |
test/native_add_library_test.dart |
A Dart test using the native code. |
build.dart |
A script for compiling src/native_add_library.c and declaring the compiled asset with id package:native_add_library/native_add_library.dart . |
When a Dart or Flutter project depends on package:native_add_library
,
the build.dart
script will automatically be
invoked on run
, build
, and test
commands.
The native_add_app
example showcases a use of native_add_library
.
API documentation for the native assets in Dart FFI is available in
the dart:ffi
API reference for Native
and DefaultAsset
.
API documentation for the build.dart
script is available
on the package:native_assets_cli
API reference.
Experiment opt-in
For more information on how to enable the experiment and provide feedback, please refer to the tracking issues: