本篇,我们接着对flutter插件中MethodChannel的使用进行研究。。。
开始~~
二.MethodChannel的使用
1.官方案例介绍
1.1.运行官方案例后发生了什么
接着上次的流程来说,当我们尝试在安卓studio上把项目运行起来后,屏幕上显示如下所示:
即通过原生安卓的方法获取到了安卓的版本号,为安卓10,展示在了flutter项目中。
进一步,按照我们上篇的分析步骤分析如下代码为examle/main.dart中的部分代码如下
@override
**void** initState() {
**super**.initState();
initPlatformState();
}
*// Platform messages are asynchronous, so we initialize in an async method.*
Future<**void**> initPlatformState() **async** {
String platformVersion;
*// Platform messages may fail, so we use a try/catch PlatformException.*
*// We also handle the message potentially returning null.*
**try** {
platformVersion =
**await** FlutterPluginDemo2.*platformVersion* ?? **'Unknown platform version'**;
} **on** PlatformException {
platformVersion = **'Failed to get platform version.'**;
}
*// If the widget was removed from the tree while the asynchronous platform*
*// message was in flight, we want to discard the reply rather than calling*
*// setState to update our non-existent appearance.*
**if** (!**mounted**) **return**;
setState(() {
**_platformVersion** = platformVersion;
});
}
即通过调用FlutterPluginDemo2.platformVersion 方法获取原生版本号,那么在FlutterPluginDemo2类中又是如何实现的呢,如下所示为lib/flutter_plugin_demo2.dart中的代码
**class** FlutterPluginDemo2 {
**static const** MethodChannel *_channel* = MethodChannel(**'flutter_plugin_demo2'**);
**static** Future<String?> **get** *platformVersion* **async** {
**final** String? version = **await** *_channel*.invokeMethod(**'getPlatformVersion'**);
**return** version;
}
}
它的调用原理是如何呢?
可以看到通过建立一个MethodChannel通道,给这个通道设置一个key值为flutter_plugin_demo2,之后再给要调用的方法设置一个key只为getPlatformVersion。
如此在插件端,如以安卓为例如下的
android/src/main/java/com/example/flutter_plugin_demo2 路径下的FlutterPluginDemo2Plugin.java类 中如下代码片段中
@Override
**public void** onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
**channel** = **new** MethodChannel(flutterPluginBinding.getBinaryMessenger(), **"flutter_plugin_demo2"**);
**channel**.setMethodCallHandler(**this**);
}
@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();
}
}
发现了没,这里也有一个flutter_plugin_demo2,也有一个 getPlatformVersion的key,如此我们就清晰了Method Channel的机制,可以这样理解为
通过flutter端设置一个固定的字符串key同安卓原生端的key保持一致,可以使flutter插件和原生建立起基础通信,而后根据调用方法时同样传递一个key值(如官方示例中的getPlatformVersion)和原生的onMethodCall方法中的call.method对应的值保持一致即可成功调用到安卓端的接口,而后通过
result.success 把对应获取到的原生信息回传给flutter端,从而让flutter拿来进行展示和进一步数据处理工作
1.2.尝试按照官方案例写一个自己的插件(以安卓为例)
首先打开原生工程代码的方法如下所示:
对于安卓端打开方法为:
对于iOS端打开方法如下:
需要注意的是,在iOS中若需要先进入example/ios 目录下执行 flutter run 命令进行Pods的构建才会出现如上的iOS端插件构建代码,否则,是无法进入iOS端原生代码的。
运行项目后展示内容为自己写的一个当用户点击flutter调用安卓原生按钮后,安卓回调数据为 Android: 获取安卓数据成功的示例,即可简称为调——设——回三部曲,
第1步—在flutter代码中调用
在flutter示例代码example/lib/main.dart中代码如下所示:
Future<**void**> updateAndroidInfoData() **async** {
String originalStr;
**try** {
originalStr =
**await** FlutterPluginDemo2.*originalAllData* ?? **"Unknow Not Back"**;
} **on** PlatformException {
originalStr = **"Failed Not Back"**;
}
**if** (!**mounted**) **return**;
setState(() {
**_originalStr** = originalStr;
});
}
执行该方法后
第2步—在flutter插件代码中设置key
在lib/flutter_plugin_demo2.dart中加入调用安卓的代码如下
**static** Future<String?> **get** *originalAllData* **async** {
**final** String? originalStr = **await** *_channel*.invokeMethod(**'originalAllData'**);
**return** originalStr;
}
设置调用的key为 originalAllData,
第3步—在原生(如下为安卓)代码中回传原生数据给flutter
3.同时在FlutterPluginDemo2Plugin.java类中增加call.method.equals("originalAllData”)内容如下,
**else if** (call.method.equals(**"originalAllData"**)) {
result.success(**"Android: "** + **"获取安卓数据成功"**);
}
如此,经历此三步曲后,就可以实现一个最简单的flutter调用原生安卓,安卓同步回传数据给flutter的基础通信架构的功能实现。
2.传值方法汇总
接下来,我们来聊聊关于如何借助MethodChannel来实现把值传给原生,原生经过加工处理后返回给flutter,从而实现flutter调用原生,原生加工后回调给flutter的操作。
来吧,展示~~
2.1.简单传值——flutter调用原生
聊传值之前,先来说说原生接收值的原理,即为flutter和原生直接是通过一个MethodCall的call对象传值的原理,即当flutter中按照官方文档的要求传值给原生后,原生是通过call.arguments来获取到传递的值,从而对值进行加工后返回的操作。
如下所示为flutter端传递一个动态的数字给原生端,原生端实现的是一个超级简易的计算器,即如果是iOS平台,给flutter端传递的数字 翻10倍后返回展示,如果是安卓平台,则把传递的数字返回它的平方。
接下来贴代码进行说明:
1.flutter端的代码示例
在example/lib/more_Params_page.dart(即flutter端使用插件的地方)文件中执行以下方法后,把对应的type,即用户输入的内容传递给中间插件FlutterPluginDemo2类。
Future<**void**> sendParamsToOriginal() **async** {
String originalStr;
**try** {
originalStr = **await** FlutterPluginDemo2.*sendParamsToOriginal*(**type**!,**"传给原生"**) ?? **"0"**;
} **on** PlatformException {
originalStr = **"0"**;
}
**if** (!**mounted**) **return**;
setState(() {
**_paramStr** = originalStr;
});
}
2.中间插件的代码示例
如下所示为
**static** Future<String?> *sendParamsToOriginal*(int key,String value) **async** {
Map params = {
**"key"**:key,
**"value"**:value,
};
**final** String? count = **await** *_channel*.invokeMethod(**'sendParamsToOriginal'**,params);
**return** count;
}
lib/flutter_plugin_demo2.dart中提前写好的插件端调用原生端的代码示例,并传递flutter端的代码至插件端,插件端包装完成后向下继续传递原生。
3.原生端的代码示例
3.1.安卓端
同上所示,安卓端在FlutterPluginDemo2Plugin.java类中的onMethodCall方法中设置同中间插件一致的key,如demo所示的sendParamsToOriginal,根据
MethodCall对象的原理方式获取到flutter端传递过来的参数为call.argument,之后取出传递的值,然后平方相乘后返回给插件,之最上层的flutter端进行展示。
**else if** (call.method.equals(**"sendParamsToOriginal"**)) {
**int** key = call.argument(**"key"**);
result.success(**"Android端 - 计算乘积为 "** + key * key);
}
3.2.iOS端
同理,iOS端代码示例在FlutterPluginDemo2Plugin.m类中的handleMethodCall
方法中部分代码如下所示
**else if** ([**@"sendParamsToOriginal"** isEqualToString:call.method]) {
NSDictionary *params = call.arguments;
NSLog(**@"params = "**,params);
**int** key = [params[**@"key"**] intValue];
result([**@"iOS端 - 计算翻10倍后为:"** stringByAppendingString: [NSString stringWithFormat:**@"%d"**,key * 10]]);
}
最后,由于flutter和原生端交互时难免涉及到数据类型的转换问题,特别是int类型,这里一并展示转换如下所示:
另外本篇的demo连接一并附上如下:Flutter插件demo
综上,关于MethodChannel的基础使用,本篇从官方案例获取系统版本号的分析,到模仿官方案例加入自己调用不同原生返回内容,以及通过简单传递参数给原生加工后返回给flutter的案例来整体对MethodChannel在插件编写中的使用进行了全面的描述;
但尴尬的问题是,本篇中实现的仅仅是flutter端和原生端保持同步状态,实际开发中如声音音量的变化是不可能由flutter端调用安卓然后安卓给回应的,而更可能是flutter端在监听原生,原生端音量发生变化后通知到flutter端,然后去做对应的业务处理,那么就留到下一篇聊这个问题的解决方案。
本篇完~~