Flutter原生函数接口插件universal_ffi的使用
Flutter原生函数接口插件universal_ffi的使用
简介
universal_ffi
是一个基于 wasm_ffi
和 dart:ffi
的包装器,旨在提供跨平台一致的API。它还包含一些辅助方法,使使用更加方便。
特性
- 动态库异步加载:
DynamicLibrary.openAsync()
方法使得dart:ffi
和wasm_ffi
都可以异步加载动态库。 - 模块路径解析:
FfiHelper.load()
方法可以解析模块路径,并根据不同的平台加载相应的库文件。 - 内存管理:提供了
FfiHelper.safeUsing
和FfiHelper.safeWithZoneArena
方法,确保使用特定库的内存。
安装
dart pub add universal_ffi
或者
flutter pub add universal_ffi
生成绑定文件
使用 package:ffigen
生成绑定文件,并将 import 'dart:ffi' as ffi;
替换为 import 'package:universal_ffi/ffi.dart' as ffi;
。
使用 FfiHelper
以下是一个简单的示例,展示了如何使用 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';
class Example {
final FfiHelper helper;
final NativeExampleBindings bindings;
Example._(this.helper) : bindings = NativeExampleBindings(helper.library);
static Future<Example> create(String libPath) async {
final helper = await FfiHelper.load(libPath);
return Example._(helper);
}
String getLibraryName() =>
bindings.getLibraryName().cast<Utf8>().toDartString();
String hello(String name) {
return helper.safeUsing(
(Arena arena) {
final cString = name.toNativeUtf8(allocator: arena).cast<Char>();
return bindings.hello(cString).cast<Utf8>().toDartString();
},
);
}
int intSize() => bindings.intSize();
int boolSize() => bindings.boolSize();
int pointerSize() => bindings.pointerSize();
}
void main() async {
final example = await Example.create('path/to/native_library');
print('Library Name: ${example.getLibraryName()}');
print('Hello, World!: ${example.hello('World')}');
print('int size: ${example.intSize()}');
print('bool size: ${example.boolSize()}');
print('pointer size: ${example.pointerSize()}');
}
动态库异步加载
DynamicLibrary.openAsync()
方法使得 dart:ffi
和 wasm_ffi
都可以异步加载动态库。这对于跨平台开发非常有用。
FfiHelper.load()
FfiHelper.load()
方法可以根据不同的平台解析模块路径并加载相应的库文件。支持的选项包括:
- 简单使用:假设所有平台从相同的相对路径加载共享库。
- isStaticallyLinked:指定是否静态链接。
- isFfiPlugin:用于 Flutter FFI 插件。
- Overrides:为特定平台指定模块路径。
多个 wasm_ffi 模块
如果在同一个项目中有多个 wasm_ffi
模块,全局内存将只引用第一个加载的模块。为了避免意外行为,可以显式使用 library.allocator
或者使用 FfiHelper.safeUsing
和 FfiHelper.safeWithZoneArena
方法。
贡献
欢迎贡献!🚀
希望这个示例能帮助你更好地理解和使用 universal_ffi
插件。如果有任何问题或建议,请随时提出。
更多关于Flutter原生函数接口插件universal_ffi的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter原生函数接口插件universal_ffi的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter中使用universal_ffi
插件来调用原生函数接口的示例代码。universal_ffi
插件允许你在Flutter中通过FFI(Foreign Function Interface)来调用C/C++等原生代码。
步骤 1: 配置项目
首先,你需要配置你的Flutter项目来使用universal_ffi
插件。
- 在
pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
universal_ffi: ^0.x.x # 请替换为最新版本号
- 运行
flutter pub get
来安装依赖。
步骤 2: 创建原生库
创建一个简单的C/C++库,例如native_lib.c
:
// native_lib.c
#include <stdint.h>
int32_t add(int32_t a, int32_t b) {
return a + b;
}
编译这个C文件生成共享库(例如,在Linux上生成.so
文件,在macOS上生成.dylib
文件,在Windows上生成.dll
文件)。
步骤 3: 在Flutter中加载原生库
在Flutter项目中,你需要编写Dart代码来加载并调用这个原生库。
- 创建一个Dart文件,例如
ffi_loader.dart
:
import 'dart:ffi';
import 'dart:typed_data';
import 'package:universal_ffi/universal_ffi.dart';
// 定义原生函数类型
typedef NativeAddFunc = Int32 Function(Int32 a, Int32 b);
// 加载原生库
class NativeLibraryLoader {
late DynamicLibrary _nativeLibrary;
late NativeAddFunc _addFunc;
NativeLibraryLoader() {
// 根据平台选择合适的库文件路径
var libraryPath = Platform.isAndroid
? 'libnative_lib.so'
: Platform.isIOS
? 'libnative_lib.dylib'
: Platform.isWindows
? 'native_lib.dll'
: 'libnative_lib.so'; // 默认情况(例如Linux)
// 使用Universal FFI加载库
var ffi = Ffi.fromAsset(libraryPath);
_nativeLibrary = ffi.library!;
// 获取原生函数指针
_addFunc = _nativeLibrary
.lookup<NativeFunction<NativeAddFunc>>('add')
.uncheckedCast<NativeAddFunc>();
}
int add(int a, int b) {
return _addFunc(a, b);
}
}
-
在
lib
目录下创建一个assets
文件夹,并将编译好的原生库文件(例如libnative_lib.so
)放在其中。 -
在
pubspec.yaml
中声明库文件作为资产:
flutter:
assets:
- assets/libnative_lib.so
- assets/libnative_lib.dylib # 如果需要支持iOS
- assets/native_lib.dll # 如果需要支持Windows
步骤 4: 使用原生函数
现在你可以在你的Flutter应用中使用这个原生函数了。
import 'package:flutter/material.dart';
import 'ffi_loader.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('FFI Example'),
),
body: Center(
child: NativeFunctionExample(),
),
),
);
}
}
class NativeFunctionExample extends StatefulWidget {
@override
_NativeFunctionExampleState createState() => _NativeFunctionExampleState();
}
class _NativeFunctionExampleState extends State<NativeFunctionExample> {
late NativeLibraryLoader _nativeLibraryLoader;
late int _result;
@override
void initState() {
super.initState();
_nativeLibraryLoader = NativeLibraryLoader();
_result = _nativeLibraryLoader.add(5, 3);
}
@override
Widget build(BuildContext context) {
return Text('Result of add(5, 3): $_result');
}
}
这个示例展示了如何在Flutter中使用universal_ffi
插件来加载和调用C语言编写的原生函数。根据你的实际情况,你可能需要调整路径和函数名等配置。