Android端Flutter插件开发

一、简介

此文章主要记录本人的flutter插件开发过程以及遇到的问题等,如有错误请指正.

二、开发准备(Windows)

1.Android Studio 4.0以上
2.Flutter SDK

三、环境配置

1.安装flutter sdk

下载好之后,解压,找到根目录下的flutter文件下找到flutter_console.bat,双击运行并启动flutter命令行。

2.更新环境变量

要在终端运行 flutter 命令, 你需要添加以下环境变量到系统PATH:

转到 “控制面板>用户帐户>用户帐户>更改我的环境变量”
在“用户变量”下检查是否有名为“Path”的条目:
如果该条目存在, 追加 flutter\bin的全路径,使用 ; 作为分隔符.
如果条目不存在, 创建一个新用户变量 Path ,然后将 flutter\bin的全路径作为它的值.
在“用户变量”下检查是否有名为”PUB_HOSTED_URL”和”FLUTTER_STORAGE_BASE_URL”的条目,如果没有,也添加它们。
重启Windows以应用此更改

3.测试flutter环境

打开命令行输入:flutter doctor

flutter_plugin.png

如图可以看到有两个报错为插件工具没有导入可查看这里解决问题:
https://www.jianshu.com/p/3dc7dbd0712c

四、插件开发

1.使用Android Studio创建flutter插件

参照: https://www.jianshu.com/p/3dc7dbd0712c

2.编译插件桥接类

找到插件桥接类


微信截图_20210125172304.png

打开后可以看到很多红色报错,如下图可以点开新的AS界面进行编译:


微信截图_20201224104312.png
3.方法简介
onAttachedToEngine方法

初始化方法,"flutter_vin_plugin"为定义好的插件桥接类名,后面调用需要一一对应。

@Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_vin_plugin");
        channel.setMethodCallHandler(this);
    }
onMethodCall方法

接受从js层获取参数的方法"isCropImage"等都是传递的参数标识通过MethodCall 对象获取传递过来的数据
startScanVin等为自定义的原生方法,里面可以自定义一些操作

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        resultPlugin = result;
        String isCrop = call.argument("isCropImage");
        ConstantConfig.isImportCrop = !TextUtils.isEmpty(isCrop) && isCrop.equals("1");
        ConstantConfig.isCheckMotorbike = Boolean.getBoolean(call.argument("containMoto") + "");
        initOcrFile();
        if (call.method.equals("scanVin")) { 
            startScanVin();
        } else if (call.method.equals("imageVin")) {  
            startImport();
        } else {
            unInitOcrApi();
            result.notImplemented();
        }
    }
onAttachedToActivity方法

此方法的包含一些原生的activity中的一些监听方法,添加监听后可实现对应的原生方法。
①addRequestPermissionsResultListener: 对应原生中的权限监听方法
②addActivityResultListener:对应原生中activity回调方法等一些有关activity生命周期的方法

@Override
    public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
        this.activity = binding.getActivity();
        binding.addRequestPermissionsResultListener(new PluginRegistry.RequestPermissionsResultListener() {
            @Override
            public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
                switch (requestCode) {
                    case SCAN_PERMISSION_CODE:
                        if (permissions.length != 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {//失败
                            Toast.makeText(activity, "请允许权限在识别", Toast.LENGTH_SHORT).show();
                        } else {//成功
                            //启动启动VIN码扫描识别页面
                            Intent intent = new Intent(activity, ScanVinActivity.class);
                            activity.startActivityForResult(intent, VIN_RECOG_CODE);
                        }
                        break;
                    case IMPORT_PERMISSION_CODE:
                        if (permissions.length != 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {//失败
                            Toast.makeText(activity, "请允许权限在识别", Toast.LENGTH_SHORT).show();
                        } else {//成功
                            //启动启动VIN码导入识别页面
                            Intent intent = new Intent(activity, VinRecogActivity.class);
                            activity.startActivityForResult(intent, VIN_RECOG_CODE);
                        }
                        break;
                }
                return false;
            }
        });
        binding.addActivityResultListener(new PluginRegistry.ActivityResultListener() {
            @Override
            public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
                if (data != null && requestCode == VIN_RECOG_CODE) {
                    //接收所有识别结果,图片
                    String vinResult = data.getStringExtra("vinResult");
                    //接收识别结果的状态码,0表示成功,其他值表示识别失败
                    int recogCode = data.getIntExtra("recogCode", -1);
                    String vinThumbPath = data.getStringExtra("vinThumbPath");
                    String vinAreaPath = data.getStringExtra("vinAreaPath");
                    Map<String, String> map = new HashMap<>();
                    map.put("ocrResult", vinResult);
                    map.put("ocrThumbPath", vinThumbPath);
                    map.put("ocrAreaPath", vinAreaPath);
                    resultPlugin.success(map);
                }
                return false;
            }
        });
    }

到此插件部分已经开发的差不多了

五、引用插件

1.在插件中的demo调用测试

找到插件目录下的lib文件夹下的文件打开如下;


微信截图_20210128104358.png

此文件为插件原生与js端沟通的桥梁所有的方法交互都需要通过此方法
如下图,一共定义几个方法,比如licName等参数是js传递过来的参数,将这些参数放入param中,通过我们上面定义的flutter_vin_plugin的对象_channel执行invokeMethod方法调用原生并声明原生中的方法名scanVin以及传递js端数据集合param,,通过map接受原生中返回的数据即可.


微信截图_20210128105151.png

找到js端主页
微信截图_20210128110329.png

打开后可以定义我们在桥接中定义好的方法名称


微信截图_20210128110637.png

下面在main.dart中定义对应调用的方法:
result为从原生获取的数据_resultOcr为定义好的变量.
    Future<void> scanVin() async {
      Map<String, String> result;
    // 参数说明 ("授权文件名称","是否屏蔽部分校验规则") 0为false 1为true
      result = await FlutterVinPlugin.scanVin("7332DBAFD2FD18301EF6", "0"); // TODO 扫描识别
      setState(() {
        _resultMap = result;
        _resultOcr = _resultMap['ocrResult'];
        _resultThumbPath = _resultMap['ocrThumbPath'];
        _resultAreaPath = _resultMap['ocrAreaPath'];
      });
    }

然后即可在view中点击监听调用:


微信截图_20210128110842.png

main.dart中这里不多做描述了,具体可以查看官方文档学习如何开发。

2.在实际项目中调用测试
①将插件复制进Flutter项目目录中
②Flutter项目中的pubspec.yaml文件,进行如下图配置,path根据自己的插件的相对路径配置
图片1.png
③在你的项目中打开pubspec.yam文件执行插件引用如图:
图片2.png
④在你的项目中打开example下GeneratedPluginRegistrant.Java代码,可以看到这里已经成功引用了FlutterVinPlugin插件如图
图片3.png

六、调试运行

微信截图_20210128113627.png

运行成功


微信截图_20210128113700.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容