Flutter 混合开发系列 包含如下:
与原生通信-BasicMessageChannel
添加 Flutter 到 Android Activity
添加 Flutter 到 Android Fragment
每个工作日分享一篇,欢迎关注、点赞及转发。
平台通信的3中方式
Flutter 与 Native 端通信有如下3个方法:
MethodChannel :Flutter 与 Native 端相互调用,调用后可以返回结果,可以 Native 端主动调用,也可以Flutter主动调用,属于双向通信。此方式为最常用的方式, Native 端调用需要在主线程中执行。
BasicMessageChannel :用于使用指定的编解码器对消息进行编码和解码,属于双向通信,可以 Native 端主动调用,也可以Flutter主动调用。
EventChannel :用于数据流(event streams)的通信, Native 端主动发送数据给 Flutter,通常用于状态的监听,比如网络变化、传感器数据等。
Flutter 端
Flutter 端创建 MethodChannel 通道,用于与原生端通信:
var channel = BasicMessageChannel('com.flutter.guide.BasicMessageChannel' ,StandardMessageCodec());
com.flutter.guide.BasicMessageChannel 是 BasicMessageChannel 的名称,原生端要与之对应。
发送消息:
var result = await channel.send({'name' : 'laomeng' , 'age' : 18 });
完整代码:
class BasicMessageChannelDemo extends StatefulWidget { @override _BasicMessageChannelDemoState createState() => _BasicMessageChannelDemoState(); }class _BasicMessageChannelDemoState extends State <BasicMessageChannelDemo > { var channel = BasicMessageChannel('com.flutter.guide.BasicMessageChannel' ,StandardMessageCodec()); var _data; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Column( children: [ SizedBox( height: 50 , ), RaisedButton( child: Text('发送数据到原生' ), onPressed: () async { var result = await channel.send({'name' : 'laomeng' , 'age' : 18 }); var name = result['name' ]; var age = result['age' ]; setState(() { _data = '$name ,$age ' ; }); }, ), Text('原生返回数据:$_data ' ), ], ), ); } }
Android 端
android 下创建 BasicMessageChannelDemo :
class BasicMessageChannelDemo (messenger: BinaryMessenger) : BasicMessageChannel.MessageHandler<Any> { private var channel: BasicMessageChannel<Any> init { channel = BasicMessageChannel(messenger, "com.flutter.guide.BasicMessageChannel" , StandardMessageCodec()) channel.setMessageHandler(this ) } override fun onMessage (message: Any ?, reply: BasicMessageChannel .Reply <Any >) { val name = (message as Map<String, Any>)["name" ] val age = (message as Map<String, Any>)["age" ] var map = mapOf("name" to "hello,$name " , "age" to "$age " ) reply.reply(map) } }
onMessage 方法在 Flutter 端调用 send 方法后调用,解析方法如下:
override fun onMessage (message: Any ?, reply: BasicMessageChannel .Reply <Any >) { val name = (message as Map<String, Any>)["name" ] val age = (message as Map<String, Any>)["age" ] var map = mapOf("name" to "hello,$name " , "age" to "$age " ) reply.reply(map) }
message 是传入的参数,由于 Flutter 端传入的是 Map,所以上面的解析按照 Map 解析。
reply.reply() 是返回给 Flutter 的结果。
Flutter 端解析:
var result = await channel.send({'name' : 'laomeng' , 'age' : 18 });var name = result['name' ];var age = result['age' ];
两端的解析要相互对应。
在 MainActivity 启动:
class MainActivity : FlutterActivity () { override fun configureFlutterEngine (flutterEngine: FlutterEngine ) { super .configureFlutterEngine(flutterEngine) BasicMessageChannelDemo(flutterEngine.dartExecutor.binaryMessenger) flutterEngine.plugins.add(MyPlugin()) } }
iOS 端
ios 下创建 MethodChannelDemo ,按如下方式:
import Flutterimport UIKitpublic class BasicMessageChannelDemo { var channel:FlutterBasicMessageChannel init (messenger: FlutterBinaryMessenger ) { channel = FlutterBasicMessageChannel (name: "com.flutter.guide.BasicMessageChannel" , binaryMessenger: messenger) channel.setMessageHandler { (message, reply) in if let dict = message as ? Dictionary <String , Any > { let name:String = dict["name" ] as ? String ?? "" let age:Int = dict["age" ] as ? Int ?? -1 reply(["name" :"hello,\(name)" ,"age" :age]) } } } }
在 AppDelegate 启动:
import UIKitimport Flutter@UIApplicationMain @objc class AppDelegate : FlutterAppDelegate { override func application ( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any ]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as ! FlutterViewController MethodChannelDemo (messenger: controller.binaryMessenger) BasicMessageChannelDemo (messenger: controller.binaryMessenger) GeneratedPluginRegistrant .register(with: self ) return super .application(application, didFinishLaunchingWithOptions: launchOptions) } }
原生端主动发送消息给Flutter
Flutter 端接收数据
@override void initState() { super .initState(); channel.setMessageHandler((message) { setState(() { _nativeData = message['count' ]; }); }); }
Android 发送数据
原生端启动定时器,每隔一秒向 Flutter 发送数据,Android 端代码:
class BasicMessageChannelDemo (var activity : Activity , messenger : BinaryMessenger ) : BasicMessageChannel .MessageHandler <Any > { private var channel: BasicMessageChannel<Any> private var count = 0 init { channel = BasicMessageChannel(messenger, "com.flutter.guide.BasicMessageChannel" , StandardMessageCodec()) channel.setMessageHandler(this ) startTimer() } fun startTimer() { var timer = Timer().schedule(timerTask { activity.runOnUiThread { var map = mapOf("count" to count++) channel.send(map,object :BasicMessageChannel.Reply<Any>{ override fun reply(reply: Any?) { } }) } }, 0 , 1000 ) } override fun onMessage(message: Any?, reply: BasicMessageChannel.Reply<Any>) { val name = (message as Map <String , Any>)["name" ] val age = (message as Map <String , Any>)["age" ] var map = mapOf("name" to "hello,$name " , "age" to "$age " ) reply.reply(map) } }
注意:Android 端发送数据要在主现场 中调用,即:
activity.runOnUiThread { var map = mapOf("count" to count++) channel.invokeMethod("timer" , map) }
启动修改如下:
class MainActivity : FlutterActivity () { override fun configureFlutterEngine (flutterEngine: FlutterEngine ) { super .configureFlutterEngine(flutterEngine) BasicMessageChannelDemo(this ,flutterEngine.dartExecutor.binaryMessenger) flutterEngine.plugins.add(MyPlugin()) } }
iOS 发送数据
iOS 端启动定时器代码如下:
import Flutterimport UIKit public class BasicMessageChannelDemo { var channel:FlutterBasicMessageChannel var count = 0 init(messenger: FlutterBinaryMessenger) { channel = FlutterBasicMessageChannel(name: "com.flutter.guide.BasicMessageChannel" , binaryMessenger: messenger) channel.setMessageHandler { (message, reply) in if let dict = message as ? Dictionary<String , Any> { let name:String = dict["name" ] as ? String ?? "" let age:Int = dict["age" ] as ? Int ?? -1 reply(["name" :"hello,\(name)" ,"age" :age]) } } startTimer() } func startTimer() { var timer = Timer.scheduledTimer(timeInterval:1 , target: self, selector:#selector(self.tickDown),userInfo:nil,repeats: true ) } @objc func tickDown(){ count += 1 var args = ["count" :count] channel.sendMessage(args) { (reply) in } } }