欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

编写自定义flutter插件(安卓篇)

程序员文章站 2022-07-05 21:13:45
最近在搞flutter插件化。感觉插件化开发还是很有必要,其实无论是否真的有用到跟原生的交互,只要你把某写功能模块分成一个个插件,后期无论是拓展还是复用都更加方便。只要引入一个个插件就可以了。看一下怎么来创建flutter插件吧。选择新建flutter plugin项目。这里如果要跟安卓原生交互的话。kotlin不熟悉的就不要勾选这个勾了。因为勾了默认mainActivity就会用kotlin 生成了。项目建好后就比较简单了。如果是要跟原生交互的话,就直接在android 子项目中开发就行了。明...

最近在搞flutter插件化。感觉插件化开发还是很有必要,其实无论是否真的有用到跟原生的交互,只要你把某写功能模块分成一个个插件,后期无论是拓展还是复用都更加方便。只要引入一个个插件就可以了。

看一下怎么来创建flutter插件吧。选择新建flutter plugin项目。
编写自定义flutter插件(安卓篇)
这里如果要跟安卓原生交互的话。kotlin不熟悉的就不要勾选这个勾了。因为勾了默认mainActivity就会用kotlin 生成了。
编写自定义flutter插件(安卓篇)
项目建好后就比较简单了。如果是要跟原生交互的话,就直接在android 子项目中开发就行了。
我就是再原来的项目下建了一个pulgins的目录来放插件的:
编写自定义flutter插件(安卓篇)
我这个项目主要是要集成虹软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 文件配置一下就好了
编写自定义flutter插件(安卓篇)
运行一下 packages get,再项目的android 子项目生成的注册器里面就可以看到了:
编写自定义flutter插件(安卓篇)

到这里插件就OK了,我们就可以再想用的地方用 ArcFaceDetector 类来实现人脸检测了。

本文地址:https://blog.csdn.net/qq_32664007/article/details/107550484