失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Dart FFi

Dart FFi

时间:2022-11-30 18:08:36

相关推荐

Dart FFi

Dart FFi

FFI: 全称Foregin Function Interface,外部函数接口,是dart sdk的一个新的语言特性,提供了一套动态库加载器,能直接查找内存中已有的函数符号,也支持将指定路径的库加加载到内存中.通在dart侧持有这个库的文件句柄,利用dart暴露的lookupSymbol方法查找对应的native方法返回给dart调用,从而提交与native通信的效率,相比较JNI和iOS的混编,它为开发者提供了一套额外的技术方案.

示例

实例代码可以参考 https://dart.dev/guides/libraries/c-interop这里的例子,官方给出了4个示例

hello_world: 通过dart调用一个基本的native无返回值无参数的使用方法.

primitives: 一个简易的数值计算,主要包括了参数和返回值的指针传递,以及在使用后销毁它们

structs: 一个操作native结构体对象的实例,介绍了如何将native的结构体转换成dart端的可操作的对象

sqlite: 基于ffi封装的mini版本的sqlite

执行流程

Dart进入某个feature入口时,如果有使用到某个库,则将其加载到内存中,通过DynamicLibrary引用库文件句柄,这里的c方法也可以是main执行文件中全局符号通过DynamicLibrary可以访问都改库的函数符号表并返回natiive的函数指针给dart侧Dart侧对Native函数的返回值和参数类型进行转换(这里的类型是有dartRuntime定义的)Dart使用对应的native函数执行native的代码执行完毕后如果涉及到Dart新创建的指针类型,需要由dart去手动释放

Note:

在windows上不支持获取主程序符号表(processMainExecute)

/// Creates a dynamic library holding all global symbols.////// Any symbol in a library currently loaded with global visibility/// (including the executable itself) may be resolved through this library.////// This feature is not available on Windows.external factory DynamicLibrary.process();

如果加载的库文件比较大,可以通过创建一个新的isolate来加载

DynamicLibrary实现

~/versions/2.5.3/bin/cache/dart-sdk/lib/ffi/dynamic_library.dart:可以找到它的具体实现,通过调用系统库函数生成文件句柄,返回给dart用于查找符号,同时利用vm定义的dart基本数据类型实现和c基本类型之间的转换

runtime/lib/:71 72: DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) {73 GET_NON_NULL_NATIVE_ARGUMENT(String, lib_path, arguments->NativeArgAt(0));// 加载动态库,返回文件句柄static void* LoadExtensionLibrary(const char* library_file) {...void* handle = dlopen(library_file, RTLD_LAZY);...return handle;// 根据动态库句柄和符号,获取函数地址,提供给dart层调用static void* ResolveSymbol(void* handle, const char* symbol) {...void* pointer = dlsym(handle, symbol);

原生工程的集成

android通过ndk引入c/c++的代码生成libxx.so文件

DynamicLibrary.open('libsqlcipher.so');

iOS则通过embbed或者直接link到主执行文件中

DynamicLibrary.open('sqlite3.framework/sqlite3');

flutter侧通过libxx的名字就能加载该库

FFi自动转换

由于所有的函数和使用类型都需要进行C和dart的转换,定义的函数会翻倍,所以当业务庞大后,代码量会很大,而且手动编写容易错误.

// C multi sum function - int multi_sum(int nr_count, ...);//// Example of how to call C functions with varargs with a fixed arg count in// Darttypedef MultiSumFunc = Int32 Function(Int32 numCount, Int32 a, Int32 b, Int32 c);typedef MultiSum = int Function(int numCount, int a, int b, int c);// example calling a C function with varargs// calls int multi_sum(int nr_count, ...);final multiSumPointer =dylib.lookup<NativeFunction<MultiSumFunc>>('multi_sum');final multiSum = multiSumPointer.asFunction<MultiSum>();print('3 + 7 + 11 = ${multiSum(3, 3, 7, 11)}');

官方推出了一个插件ffigen用于自动生成dartc之间的绑定的代码. 不过目前这个插件还不能很好的兼容C++,尤其是class的调用。

总结

ffi相比较传统的JNI以及iOS的混编,减少了中间的一层包装,可以省去一些中间层封装代码。但需要进行类型匹配和定义,有一些额外的维护工作量,其次在内存管理上增加代码的复杂度,如果是是增对简单的借口或者有同样模版的命令调用可以考虑使用ffi,这样写出来的代码会比较统一和整体,如果是增对复杂的业务逻辑处理,这个就得看实际情况了

如果觉得《Dart FFi》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。