目录

使用 dart:ffi 与 C 进行交互

Dart 的移动端、命令行和服务端应用所运行的 Dart 原生平台,均可以使用 dart:ffi 库调用原生的 C 语言 API,用于读、写、分配和销毁原生内存。 FFI 指的是 外部函数接口。类似的术语包括 原生接口语言绑定

相关的 API 文档可在 dart:ffi API 文档 查看。

下载示例文件

#

以下的示例将展示如何使用 dart:ffi 库:

示例 描述
hello_world 如何调用无参数和返回值的 C 语言函数。
primitives 如何调用参数和返回值为 整型和指针 的 C 语言函数。
structs 如何与 C 语言互相传递字符串,以及如何处理 C 语言定义的结构
test_utils 所有示例的通用测试工具。

回顾 hello_world 示例

#

hello_world 示例 展示了如何用最少的代码调用 C 语言库。该示例可在上一节下载的 samples/ffi 中找到。

文件

#

hello_world 示例包含了以下文件:

源文件 描述
hello.dart 使用了 C 语言库中的 hello_world() 函数的文件。
pubspec.yaml Dart pubspec 文件,最低 SDK 限制为 3.4。
hello_library/hello.h 声明了 hello_world() 函数。
hello_library/hello.c 该 C 文件导入了 hello.h 并实现了 hello_world() 函数。
hello_library/hello.def 包含 DLL 构建信息的模块定义。
hello_library/CMakeLists.txt 将 C 文件代码编译为动态库的 CMake 文件。

构建 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

#

要学习如果使用 dart:ffi 库调用 C 函数,请查看 hello.dart 文件。本节将分析该文件的内容。

  1. 导入 dart:ffi

    dart
    import 'dart:ffi' as ffi;
  2. 导入 path 库用于合成动态库的路径。

    dart
    import 'dart:io' show Platform, Directory;
    import 'package:path/path.dart' as path;
  3. 用 C 函数的 FFI 类型签名定义一个 typedef。
    请参阅 定义原生类型的接口 来了解 dart:ffi 库中定义的常用类型。

    dart
    typedef hello_world_func = ffi.Void Function();
  4. 为调用 C 函数的变量定义一个 typedef

    dart
    typedef HelloWorld = void Function();
  5. 定义一个变量来保存动态库的路径。

    dart
    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');
    }
  6. 加载包含 C 函数的动态库。

    dart
    final dylib = ffi.DynamicLibrary.open(libraryPath);
  7. 获取该 C 函数的引用,接着将其赋予变量。这段代码使用了步骤 2 和 3 定义的 typedef,以及步骤 4 定义的动态库变量。

    dart
    final HelloWorld hello = dylib
        .lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
        .asFunction();
  8. 调用 C 函数。

    dart
    hello();

当你理解 hello_world 示例的内容后,可以进一步学习 其他的 dart:ffi 示例

集成并加载 C 库

#

根据平台和库的类型的不同,集成 / 打包 / 分发后加载原生 C 库的方式,也有所不同。

请参考以下页面和示例,来了解如何使用。

定义原生类型的接口

#

The dart:ffi library provides multiple types that implement NativeType and represent native types in C. You can instantiate some native types. Some other native types can be used only as markers in type signatures.

Can instantiate these type signature markers

#

The following native types can be used as markers in type signatures. 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.

Serve as type signature markers only

#

The following list shows which platform-agnostic native types that serve as markers in type signatures. They 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. To learn how these types map on specific platforms, consult the API documentation linked in the following table.

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 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 包装,从而减少时间消耗。

Build and bundle native assets

#

The Native Assets feature should 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.

This feature should simplify how Dart packages depend on and use native code. Native Assets should provide the following benefits:

  • Build the native code or obtains the binaries using a package's hook/build.dart build hook.
  • Bundle the native Asset that the build.dart build hook reports.
  • Make native assets available at runtime through declarative @Native<>() extern functions using the assetId.

When you opt in to the native experiment, The flutter (run|build) and dart (run|build) commands build and bundle native code with the Dart code.

Review the native_add_library example

#

The native_add_library example includes the minimum code to build and bundle C code in a Dart package.

The example includes 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.
hook/build.dart A build hook 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, it invokes the hook/build.dart build hook on run, build, and test commands. The native_add_app example showcases a use of native_add_library.

Review Native Asset API documentation

#

API documentation can be found for the following packages:

Opt-in to the experiment

#

To learn how to enable the experiment and provide feedback, consult these tracking issues: