FFI
- Dart course
- Expert
- Lesson 44/47
- 6 min
Write native integration with dart:ffi.
FFI
dart:ffi lets Dart code call C-based native libraries. A DynamicLibrary is loaded, lookupFunction finds a symbol, and typedefs pair Dart and native signatures.
Two typedefs: NativeAdd = Int32 Function(Int32, Int32) (native signature) and DartAdd = int Function(int, int) (Dart signature). lookupFunction<NativeAdd, DartAdd>('native_add') bridges them.
In this lesson we define NativeMathService implements MathService. The add method wraps the native call; describe returns the binding name. A real native call needs a .so/.dll; here we write a simulated implementation.
Native and Dart signatures
In FFI each native function needs two typedefs: the native side uses types like Int32, Pointer; the Dart side uses int, double.
Example: typedef NativeAdd = Int32 Function(Int32 a, Int32 b); and typedef DartAdd = int Function(int a, int b);. lookupFunction<NativeAdd, DartAdd> pairs them.
In this lesson we write add as a simulated a + b. In a real project this would call the function returned by lookupFunction. The contract stays the same.
Practice Add NativeMathService
The MathService is already defined below. Now add import 'dart:ffi';. Define typedef NativeAdd = Int32 Function(Int32 a, Int32 b); and typedef DartAdd = int Function(int a, int b);. Define class NativeMathService implements MathService with final String bindingName; NativeMathService(this.bindingName); @override int add(int a, int b) => a + b; String describe() => 'native: $bindingName';. In main create final svc = NativeMathService('native_add');; add print(svc.describe()); and print('result: ${svc.add(2, 3)}');.
Starter code
abstract class MathService {
int add(int a, int b);
}
// add dart:ffi import; define NativeAdd and DartAdd typedefs
// define a NativeMathService class (applies the MathService interface)
void main() {
print('service ready');
// create a NativeMathService; print describe and add(2,3)
}Sample solution
import 'dart:ffi';
abstract class MathService {
int add(int a, int b);
}
typedef NativeAdd = Int32 Function(Int32 a, Int32 b);
typedef DartAdd = int Function(int a, int b);
class NativeMathService implements MathService {
final String bindingName;
NativeMathService(this.bindingName);
@override
int add(int a, int b) => a + b;
String describe() => 'native: $bindingName';
}
void main() {
print('service ready');
final svc = NativeMathService('native_add');
print(svc.describe());
print('result: ${svc.add(2, 3)}');
}Expected output
service ready native: native_add result: 5
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Implementing the interface
class NativeMathService ____ MathService { }
class NativeMathService implements MathService { }
Explanation: implements applies the MathService interface.
2 What can you do with dart:ffi?
- Calling native C functions Correct answer
- JSON serialization
- HTTP requests
- File reading
Explanation: dart:ffi calls native C functions.
3 Match the FFI parts
| Term | Meaning |
|---|---|
dart:ffi |
Native interop |
DynamicLibrary |
Library loader |
lookupFunction |
Symbol lookup |
Int32 |
Native integer |