编写自定义flutter插件(安卓篇)
最近在搞flutter插件化。感觉插件化开发还是很有必要,其实无论是否真的有用到跟原生的交互,只要你把某写功能模块分成一个个插件,后期无论是拓展还是复用都更加方便。只要引入一个个插件就可以了。
看一下怎么来创建flutter插件吧。选择新建flutter plugin项目。
这里如果要跟安卓原生交互的话。kotlin不熟悉的就不要勾选这个勾了。因为勾了默认mainActivity就会用kotlin 生成了。
项目建好后就比较简单了。如果是要跟原生交互的话,就直接在android 子项目中开发就行了。
我就是再原来的项目下建了一个pulgins的目录来放插件的:
我这个项目主要是要集成虹软SDK的一些功能。
要跟flutter交互就要实现 MethodChannel.MethodCallHandler 这个接口,实现onMethodCall方法就行了:
/**
* <p></p>
* <p></p>
*
* @author jinzhenhua
* @version 1.0 ,create at:2020/7/23 10:02
*/
@SuppressWarnings("unchecked")
public class ArcfaceCheckImageHandler implements MethodChannel.MethodCallHandler {
public static final String CHANNEL = "Arcface_Android";
private FaceEngine faceEngine;
private int faceEngineCode = -1;
private final Context context;
private boolean isInit = true;
/**
* 被处理的图片
*/
private Bitmap mBitmap = null;
public ArcfaceCheckImageHandler(Activity activity, Context context, BinaryMessenger messenger){
this.context = context;
}
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
switch (call.method) {
case "findFaces": {
process(result,call.argument("path"));
break;
}
case "initEngine": {
initEngine(result);
break;
}
case "unInitEngine": {
unInitEngine();
break;
}
case "activeEngine": {
activeEngine(result);
break;
}
}
}
public void process(MethodChannel.Result result, String path) {
processImage(path,result);
}
/**
* 主要操作逻辑部分
*/
public void processImage(String path, MethodChannel.Result result) {
...
}
/**
* 初始化引擎
*/
private void initEngine(MethodChannel.Result result) {
...
}
/**
* 销毁引擎
*/
private void unInitEngine() {
if (faceEngine != null) {
faceEngineCode = faceEngine.unInit();
faceEngine = null;
}
}
/**
* 激活引擎
*
*/
public void activeEngine(MethodChannel.Result result) {
...
}
}
call.method 就是fluter那边调用的方法名。call.argument 可以取得传过来的参数。当方法执行完,要有返回值返回到flutter的话就用 result.success(obj) 。注意的是,必须要再主线程中调用success。因为flutter是单线程的,调用原生也是等待原生中的主线程代码执行完直接返回的,如果你再子线程中执行逻辑再success,那么flutter就接收不到你的返回值了。
接下来就要再Plugin中编写注册通道的代码了。代码中默认会生成一个plugin类的,
比如我这:
public class ArcfaceandroidPlugin implements FlutterPlugin, MethodCallHandler {
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
MethodChannel channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), ArcfaceCheckImageHandler.CHANNEL);
channel.setMethodCallHandler(new ArcfaceCheckImageHandler(null, flutterPluginBinding.getApplicationContext(), flutterPluginBinding.getBinaryMessenger()));
}
public static void registerWith(Registrar registrar) {
(new MethodChannel(registrar.messenger(), ArcfaceCheckImageHandler.CHANNEL)).
setMethodCallHandler(new ArcfaceCheckImageHandler(registrar.activity(), registrar.context(), registrar.messenger()));
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
}
}
要注意flutter SDK版本不同,注册方式也不同的。1.12之前是直接用静态方法registerWith注册就行了。1.12之后要实现 FlutterPlugin接口 ,然后再 onAttachedToEngine方法中注册。可以参考我另外一篇文章:flutter开发引用安卓原生view
MethodCallHandler 这个接口是代码默认生成实现的,我们就先不管他,暂时用不到。
因为我们不确定使用插件的开发者的sdk是什么版本的,所以我们要适配两个版本的注册方式。
ArcfaceCheckImageHandler 构造方法里面的参数看自己需要写。没用的就没必要写上了。
新建通道 MethodChannel 的时候,第二个参数是要跟flutter 端使用时的参数一样的。这样我们注册的代码就写好了。
当然,原生的写好了,也要再flutter里面写交互:
class ArcFaceDetector{
MethodChannel _channel = MethodChannel('Arcface_Android');
static String RESPONSE_COUNT = 'count';
static String RESPONSE_ERROR = 'error';
static String RESPONSE_CODE = 'code';
Future<Map> findFaces(final String path) async {
final Map<String, dynamic> request = <String, dynamic>{
'path': path, // TODO: support dynamic images as well
};
final Map response = await _channel.invokeMethod('findFaces', request);
return response;
}
///激活引擎
Future<Map> activeEngine() async {
final Map response = await _channel.invokeMethod('activeEngine');
return response;
}
///初始化引擎
Future<Map> initEngine() async {
final Map response = await _channel.invokeMethod('initEngine');
return response;
}
///注销引擎
Future<Map> unInitEngine() async {
final Map response = await _channel.invokeMethod('unInitEngine');
return response;
}
}
这里的返回的 response 就是原生那边的 result.success(obj) 返回的东西了。我这里返回跟接收都是用map。
在项目中引用插件:
这个很简单,只要再pubspec.yaml 文件配置一下就好了
运行一下 packages get,再项目的android 子项目生成的注册器里面就可以看到了:
到这里插件就OK了,我们就可以再想用的地方用 ArcFaceDetector 类来实现人脸检测了。
本文地址:https://blog.csdn.net/qq_32664007/article/details/107550484
下一篇: 移动端ios输入框遇到的一些问题