C interop using dart:ffi (original) (raw)
Contents keyboard_arrow_down keyboard_arrow_up
- Download example files
- Bundle and load C libraries
- Interface with native types
- Generate FFI bindings with package:ffigen
- Build and bundle native code
more_horiz
Dart mobile, command-line, and server apps running on the Dart Native platform can use the dart:ffi
library to call native C APIs, and to read, write, allocate, and deallocate native memory. FFI stands for foreign function interface. Other terms for similar functionality include native interface and language bindings.
API documentation is available in the dart:ffi API reference.
Download example files
To work with the examples in this guide, download the full ffi samples directory. It includes the following examples show how to use the dart:ffi
library:
Example | Description |
---|---|
hello_world | How to call a C function with no arguments and no return value. |
primitives | How to call C functions that have arguments and return values that are ints or pointers. |
structs | How to use structs to pass strings to and from C and to handle simple and complex C structures. |
test_utils | Common testing utilities for all of these examples. |
Review the hello_world example
The hello_world example has the minimum necessary code for calling a C library. This example can be found in the samples/ffi
you downloaded in the previous section.
The hello_world
example has the following files:
Building the C library creates several files, including a dynamic library file named libhello.dylib
(macOS), libhello.dll
(Windows), or libhello.so
(Linux).
Build and execute
The commands to build the dynamic library and execute the Dart app would resemble the following series.
cd hello_library
cmake .
...
make
...
cd ..
dart pub get
dart run hello.dart
Hello World
Leverage dart:ffi
To learn how to call a C function using the dart:ffi
library, review the hello.dart file. This section explains the contents of this file.
- Import
dart:ffi
.
dart
import 'dart:ffi' as ffi;
- Import the path library that you'll use to store the path of the dynamic library.
dart
import 'dart:io' show Platform, Directory;
import 'package:path/path.dart' as path;
- Create a typedef with the FFI type signature of the C function.
To learn about the most used types according to thedart:ffi
library consult Interfacing with native types.
dart
typedef hello_world_func = ffi.Void Function();
- Create a
typedef
for the variable to use when calling the C function.
dart
typedef HelloWorld = void Function();
- Create a variable to store the path of the dynamic library.
dart
final String libraryPath;
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',
);
} else {
libraryPath = path.join(
Directory.current.path,
'hello_library',
'libhello.so',
);
}
- Open the dynamic library that contains the C function.
dart
final dylib = ffi.DynamicLibrary.open(libraryPath);
- Get a reference to the C function, and put it into a variable. This code uses the
typedefs
from steps 2 and 3, along with the dynamic library variable from step 4.
dart
final HelloWorld hello = dylib
.lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
.asFunction();
- Call the C function.
Once you understand the hello_world
example, consult the other dart:ffi examples.
Bundle and load C libraries
The method to bundle / package / distribute then load a native C library depends on the platform and library type.
To learn how, consult the following pages and examples.
- Flutter
dart:ffi
for Android apps - Flutter
dart:ffi
for iOS apps - Flutter
dart:ffi
for macOS apps - dart:ffi examples
Interface with native types
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. |
Generate FFI bindings with package:ffigen
For large API surfaces, it can be time-consuming to write the Dart bindings that integrate with the C code. To have Dart create FFI wrappers from C header files, use the package:ffigen binding generator.
Build and bundle native code
Dart build hooks (formerly known as native assets) enable packages to contain more than just Dart source code. Packages can now contain native code assets that are transparently built, bundled, and made available at runtime.
This feature simplifies how Dart packages depend on and use native code:
- Build the native code or obtain the binaries using a package's build hook in
hook/build.dart
. - Dart and Flutter bundle the CodeAssets that the build hook reports.
- Access the code assets at runtime through declarative
@Native<>() extern
functions using the assetId.
Flutter and standalone Dart automatically bundle the native code of all packages used by the app and make it available at runtime. This works for flutter (run|build)
as well as dart (run|build)
.
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 when running the run
, build
, and test
commands. The native_add_app example showcases a use of native_add_library
.
Review build hooks API docs
API documentation can be found for the following packages:
- To learn about support for code assets in Dart FFI, consult the
dart:ffi
API reference for Native and DefaultAsset. - To learn about the
hook/build.dart
build hook, consult the package:hooks API reference.
Provide feedback
To provide feedback, consult these tracking issues:
Was this page's content helpful?
Thank you for your feedback! Please let us know what we can do to improve.
Unless stated otherwise, the documentation on this site reflects Dart 3.8.1. Page last updated on 2025-05-22. View source or report an issue.