在 Flutter 中使用
接着就要开始在 Flutter 中使用了,和在 dart vm 中使用不一样,不能使用环境变量,而是需要将库置入到项目中。
创建仓库
直接使用 flutter create -t plugin native_add
的方式即可。
cpp 文件
native_add.cpp
#include <stdint.h> extern "C" { // __attribute__((visibility("default"))) __attribute__((used)) int32_t native_add(int32_t x, int32_t y) { return x + y; } double double_add(double x, double y) { return x + y; } }
dart 文件
final DynamicLibrary dylib = Platform.isAndroid ? DynamicLibrary.open("libnative_add.so") : DynamicLibrary.open("native_add.framework/native_add"); final int Function(int x, int y) nativeAdd = dylib .lookup<NativeFunction<Int32 Function(Int32, Int32)>>("native_add") .asFunction(); final double Function(double, double) doubleAdd = dylib .lookup<NativeFunction<Double Function(Double, Double)>>("double_add") .asFunction();
界面:
class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter = nativeAdd(_counter, 1); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.display1, ), Text( "native double value = ${doubleAdd(_counter.toDouble(), _counter.toDouble())}"), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
iOS
iOS 中,直接将 cpp 文件置入 ios/classes 文件夹内即可,然后因为 podspec 中包含默认配置的原因,这个文件会被自动引入项目。
s.source_files = 'Classes/**/*'
运行项目:
Android
Android 中其实有两种方法,一是用传统的 ndk 方式,就是 Android.mk 那种方案,我们略过这种方案,因为配置比较复杂,我们使用第二种方案,官方推荐的 CMake 方案。 因为 iOS 中,文件被置入源码中,我这里直接使用相对路径去引入这个文件。
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1) # for example add_library( native_add # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). ../ios/Classes/native_add.cpp )
- 指定源码对应的库是哪个库。
- 指定库的类型,这里是动态库,所以用 SHARED。
- 指定源码目录。
然后因为我们使用了 cmake,为了让安卓项目知道,我们需要修改 gradle 文件。
android{ // ... externalNativeBuild { cmake { path "CMakeLists.txt" } } }
这里在 Android 节点下,添加属性即可,这里是指定 CMake 使用的文件。
简单总结
现在 ffi 处于初始阶段,还有诸多不足。比如,文档的缺失,现在如何传递字符串,数组都是问题,虽然有结构体的定义,也能看到部分说明,但没有简单的示例帮助开发者快速使用。只有基本数据类型,目前可能还不需要借用 c 来解决,未来则要看 ffi 会开放到什么程度。