本篇,我们接着对flutter插件中MethodChannel的使用进行研究。。。

 

开始~~

目录:

二.MethodChannel的使用

1.官方案例介绍

1.1.运行官方案例后发生了什么

1.2.尝试按照官方案例写一个自己的插件

2.传值方法汇总

2.1.简单传值——flutter调用原生

二.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

同时在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端,然后去做对应的业务处理,那么就留到下一篇聊这个问题的解决方案。

flutter插件基础之基本介绍和工程目录介绍(一)

本篇完~~

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐