Dart:ffi上手二:C语言基本函数的调用
Dart 对 C 语言的调用我个人感觉比 Java 的 jni 要简单得多,用不着还在 C 语言中创建出对应的函数才能调用,Dart 都能直接调用 C 语言原有的那些函数,因为 java jni 调用 C 语言的完整流程我也上手写过,Dart 还是简易多了,不用打乱已有 C 语言的结构
Dart:ffi 思想
在使用 ffi 的时候,只需要把 C 语言或者 C++语言的方法或者函数与 Dart 中一一对应起来
yaml 导入 ffi 包
在上手 ffi 了半天,官方的 example 弄到 Flutter 项目报错,提示 import ‘package:ffi/ffi.dart’;没有找到,我还以为是 Flutter 中的 Dart 没有这个包,因为我想到最初 Dart 支持 ffi 的时候 Flutter 中的 Dart Sdk 没有,然后自己**了半天,发现这是个 Dart Packages
所以
pubspec.yaml
1 | ffi: ^0.1.3 |
调用 C 语言方法(void)
由于是在 Flutetr 中使用 ffi,并不是在纯 Dart 中,所以 C 语言的任何 Printf 都是看不到的,不会反馈到 Flutter 的控制台
一个简单的 C 语言方法
1 | void hello_word(){ |
编译好后,重新调试一下 App,才会更新新编译的 So 库
需要这两个包的导入
Dart:
1 | import 'dart:ffi'; |
参照官方,如果要调用一个 C 语言函数写上两个 typedef,这的确会带来很多方便
1 | typedef hello_word=Void Function(); |
这里一定要注意,Void 的 V 是 V 不是 v,这部分声明 C 语言中的函数,涉及到的所有类型必须全部用 ffi 中对应的 NativeType,而这个原生函数的声明后不是拿来调用的,切记,不是拿来调用的,是要用它跟下面 Dart 的方法绑定起来
接下来
1 | typedef HelloWord=void Function(); |
这就是 Dart 中需要调用的方法,也有坑,这部分的原则就是,如果 Dart 有原生的那种类型就用 dart 已经有的类型,如果没有,还是得用 NativeType
举个例子
原生函数
1 | int add(int a,int b) |
这个时候对应的 dart 函数该怎么写呢,原生的 int,dart 也有,所以 dart 韩式也是返回 int,形参中也都是 int,所以
1 | typedef Add=int Function(int a,int b); |
涉及到其他类型下面说,接下来
1 | final dylib = DynamicLibrary.open("libterm.so"); |
这行的作用就是找到对应的 so 库,记住这儿是相对路径,找的就是打包进 apk 中的 so,与 libflutter.so 同级
它的作用跟 java 中 jni 的 loadlibrary 类似
导入了一个动态库
找到原生方法的指针
1 | final helloWordPointer = dylib |
用了刚才的 dylib 对象的 lookup 方法,中间的一堆<<>>都是泛型,NativeFunction 的泛型就是第一个 typedef,也是第一个 typedef 唯一用到的地方,最后 lookup 需要传入一个字符串,这个字符串就语言中的方法或者函数的名字,它返回的是一个 Pointer 类型,就是指针的意思,dart 用了自己对应的类型来表示原生中的一些类型
然后定义并且初始化第二个 typedef 的方法
1 | HelloWord helloWord = helloWordPointer.asFunction<HelloWord>(); |
通过 Ponter 对象的 asFunction
调用它
1 | helloword(); |
这部分的打印是看不到的
调用 C 语言带返回值的 int 函数
C:
1 | int add(int a,int b){ |
上面也提到了这个
两个 typedef
1 | typedef add_func=Int32 Function(Int32 a,Int32 b); |
执行代码
1 | var path = 'libterm.so'; |
控制台输出,避免内存泄漏,所有的指针类型用完需要调用
1 | free(pointer); |
传 char 到 C 语言,并获取返回的 char
这个相对来说难一点也麻烦一点,不过 ffi 官方文档有这个例子,挺不错的,我直接拿来用,dart 中对应 c char 的类型是 Utf8,
Utf8.toUtf8(“”)返回指针,即对应原生的 char *,用这玩意注意释放,不要把它当匿名对象使用,把它保存在一个对象里面,不然不好控制内存的释放
Utf8.fromUtf8(pointer)返回 str,切记,这个坑就是它只能转换最后以\0 结尾的字符
补上自己的注释
1 | char *reverse(char *str, int length) |
dart 部分声明
1 | typedef reverse_func = Pointer<Utf8> Function(Pointer<Utf8> str, Int32 length); |
调用
1 | final reversePointer = dylib.lookup<NativeFunction<reverse_func>>('reverse'); |
注意官方示例的所有指针全部没有释放,Utf8.toUtf8(‘’)还有 dylib.lookup()方法都会调用 allocate 函数,这个就会让原生给你动态分配空间,会执行 malloc 函数,我也看到一些大佬的帖子提到不释放是会内存泄漏的
OK 这篇结束,任何问题欢迎评论区留言,下一篇是传 char **和原生遍历这个 char **
Dart:ffi上手二:C语言基本函数的调用
http://blog.nightmare.press/2020/02/23/Dart-ffi上手二-C语言基本函数的调用/