universal_ffi 1.1.3
universal_ffi: ^1.1.3 copied to clipboard
A drop-in replacement for dart:ffi for all platforms including web (using wasm_ffi).
universal_ffi #
universal_ffi
is a wrapper on top of wasm_ffi
and dart:ffi
to provide a consistent API across all platforms.
It also has some helper methods to make it easier to use.
wasm_ffi
has a few limitations, so some of the features of dart:ffi
are not supported. Most notably:
- Array
- Struct
- Union
Usage #
Install #
dart pub add universal_ffi
or
flutter pub add universal_ffi
Generate binding files #
Generates bindings using package:ffigen
.
Replace import 'dart:ffi' as ffi;
with import 'package:universal_ffi/ffi.dart' as ffi;
in the generated binding files.
Using FfiHelper #
import 'package:universal_ffi/ffi.dart';
import 'package:universal_ffi/ffi_helper.dart';
import 'package:universal_ffi/ffi_utils.dart';
import 'native_example_bindings.dart';
...
final ffiHelper = await FfiHelper.load('ModuleName');
final bindings = WasmFfiBindings(ffiHelper.library);
// use bindings
using((Arena arena) {
...
}, ffiHelper.library.allocator);
...
Features #
DynamicLibrary.openAsync() #
DynamicLibrary.open is synchronous for 'dart:ffi', but asynchronous for 'wasm_ffi'. This helper method uses both asynchronously.
FfiHelper.load() #
FfiHelper.load resolves the modulePath to the platform specific path in a variety of ways.
Simple usage
In the case, it is assumed that all platforms load a shared library from the same relative path. For example, if the modulePath = 'path/name', then the following paths are used:
- Web: 'path/name.js' or 'path/name.wasm' (if
isStandaloneWasm
option is specified) - Linux & Android: 'path/name.so'
- Windows: 'path/name.dll'
- macOS & iOS: 'path/libname.dylib'
Option: isStaticallyLinked
If the modulePath = 'path/name' and isStaticallyLinked
option is specified, then the following paths are used:
- Web: 'path/name.js' or 'path/name.wasm' (if
isStandaloneWasm
option is specified) - All other platforms: Instead of loading a shared library, calls DynamicLibrary.process().
Option: isFfiPlugin (used for Flutter Ffi Plugin)
If the modulePath = 'path/name' and isFfiPlugin
option is specified, then 'path' is ignored and the following paths are used:
- Web: 'assets/package/name/assets/name.js' or 'assets/package/name/assets/name.wasm' (if
isStandaloneWasm
option is specified) - Linux & Android: 'name.so'
- Windows: 'name.dll'
- macOS & iOS: 'name.framework/name'
Overrides
Overrides can be used to specify the path to the module to be loaded for specific [AppType]. Override strings are used as is.
Multiple wasm_ffi modules in the same project
If you have multiple wasm_ffi modules in the same project, the global memory will refer only to the first loaded module. So unless the memory is explicitly specified, the memory from the first loaded module will be used for all modules, causing unexpected behavior. One option is to explicitly use library.allocator for wasm & malloc/calloc for ffi. Alternatively, you can use FfiHelper.safeUsing or FfiHelper.safeWithZoneArena:
FfiHelper.safeUsing()
FfiHelper.safeUsing
is a wrapper for using
. It ensures that the library-specific memory is used.
FfiHelper.safeWithZoneArena()
FfiHelper.safeWithZoneArena
is a wrapper for withZoneArena
. It ensures that the library-specific memory is used.
Contributions are welcome! 🚀