Skip to content

vm75/universal_ffi

Repository files navigation

universal_ffi

build_badge github_badge universal_ffi_pub_ver universal_ffi_pub_points universal_ffi_pub_popularity universal_ffi_pub_likes license_badge

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! 🚀

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published