在一步步实现一个Flutter plugin插件这篇文章我们介绍了如何实现一个plugin,但是这里通过MethodChannel只实现了Flutter向Platform的通信,并未实现从Platform向Flutter的通信,今天我们就来介绍如何通过BasicMessageChannel实现Platform向Flutter方向的通信。
创建Plugin
关于在命令行中或者Android Studio中如何新建一个Plugin项目,我们在一步步实现一个Flutter plugin插件这片文章中已经有详细介绍,这里不再赘述
Flutter端代码
首先创建一个BasicMessageChannel对象
第一个参数为channel名,需与Platform中的BasicMessageChannel对象传的channel名一致
第二个参数为codec,表示消息编解码器,Flutter中已经默认为我们实现了如下几种,基本够用,也支持自定义,我们这里用StringCodec,支持简单的内容为String的消息通信。codec的类型也必须和Platform中的BasicMessageChannel对象传的codec类型一致
- BinaryCodec
BinaryCodec是最为简单的一种Codec,因为其返回值类型和入参的类型相同,均为二进制格式(Android中为ByteBuffer,iOS中为NSData)。实际上,BinaryCodec在编解码过程中什么都没做,只是原封不动将二进制数据消息返回而已。或许你会因此觉得BinaryCodec没有意义,但是在某些情况下它非常有用,比如使用BinaryCodec可以使传递内存数据块时在编解码阶段免于内存拷贝。 - StringCodec
StringCodec用于字符串与二进制数据之间的编解码,其编码格式为UTF-8。 - JSONMessageCodec
JSONMessageCodec用于基础数据与二进制数据之间的编解码,其支持基础数据类型以及列表、字典。其在iOS端使用了NSJSONSerialization作为序列化的工具,而在Android端则使用了其自定义的JSONUtil与StringCodec作为序列化工具。 - StandardMessageCodec
StandardMessageCodec是BasicMessageChannel的默认编解码器,其支持基础数据类型、二进制数据、列表、字典
static const BasicMessageChannel _messageChannel = const BasicMessageChannel('plugin_version', StringCodec());
然后通过setMessageHandler方法设置一个消息处理器,用于处理从platform传过来的消息
_messageChannel.setMessageHandler(_handleMessage);
Future<String> _handleMessage(message) async {
print('收到native的消息${message}');
}
Android端代码
与Flutter端的代码类似,首先创建一个BasicMessageChannel对象
第二个参数为channel名,需与Flutter中的BasicMessageChannel对象传的channel名一致
第三个参数为codec,表示消息编解码器,也必须和Flutter中的BasicMessageChannel对象传的codec类型一致,codec类型在上文中已具体介绍,这里不再赘述
private static BasicMessageChannel messageChannel;
public static void registerWith(PluginRegistry.Registrar registrar) {
messageChannel = new BasicMessageChannel(registrar.messenger(),"plugin_version", StringCodec.INSTANCE);
}
然后调用send方法向Flutter发送消息
messageChannel.send("message from platform");
iOS端代码
说实话,iOS开发臣妾不懂啊
实现方法跟Android类似,可以参考官方文档
完整实现代码
结合一步步实现一个Flutter plugin插件这篇文章中的Flutter端向Platform端的通信,贴上完整的Flutter和Platform双向通信的完整实现代码
flutter端代码
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter/material.dart';
class PluginVersion {
static const MethodChannel _methodChannel = const MethodChannel('plugin_version');
static const BasicMessageChannel _messageChannel = const BasicMessageChannel('plugin_version', StringCodec());
PluginVersion() {
_messageChannel.setMessageHandler(_handleMessage);
}
Future<String> _handleMessage(message) async {
print('收到native的消息${message}');
Fluttertoast.showToast(
msg: message.toString(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Colors.black,
textColor: Colors.white);
}
Future<String> get platformVersion async {
final String version = await _methodChannel.invokeMethod('getPlatformVersion');
return version;
}
}
Android端代码
package com.himmy.plugin_version;
import android.os.Build;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.StringCodec;
public class PluginVersionPlugin implements MethodChannel.MethodCallHandler {
private static BasicMessageChannel messageChannel;
public static void registerWith(PluginRegistry.Registrar registrar) {
MethodChannel channel = new MethodChannel(registrar.messenger(), "plugin_version");
channel.setMethodCallHandler(new PluginVersionPlugin());
messageChannel = new BasicMessageChannel(registrar.messenger(), "plugin_version", StringCodec.INSTANCE);
}
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if ("getPlatformVersion".equals(methodCall.method)) {
result.success("Android " + Build.VERSION.RELEASE);
messageChannel.send("message from platform");
} else {
result.notImplemented();
}
}
}
插件使用
在创建的Flutter Plugin项目中默认有一个测试项目example,替换lib/main.dart中的内容为如下内容
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:plugin_version/plugin_version.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
PluginVersion pluginVersion = PluginVersion();
@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.
try {
platformVersion = await pluginVersion.platformVersion;
} 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;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
floatingActionButton: FloatingActionButton(
onPressed: initPlatformState,
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
}
}
参考
flutter与native通信