Flutter 混合开发系列 蕴含如下:

  • 嵌入原生View-Android
  • 嵌入原生View-iOS
  • 与原生通信-MethodChannel
  • 与原生通信-BasicMessageChannel
  • 与原生通信-EventChannel
  • 增加 Flutter 到 Android Activity
  • 增加 Flutter 到 Android Fragment
  • 增加 Flutter 到 iOS

每个工作日分享一篇,欢送关注、点赞及转发。

平台通信的3中形式

Flutter 与 Native 端通信有如下3个办法:

  • MethodChannel:Flutter 与 Native 端互相调用,调用后能够返回后果,能够 Native 端被动调用,也能够Flutter被动调用,属于双向通信。此形式为最罕用的形式, Native 端调用须要在主线程中执行。
  • BasicMessageChannel:用于应用指定的编解码器对音讯进行编码和解码,属于双向通信,能够 Native 端被动调用,也能够Flutter被动调用。
  • EventChannel:用于数据流(event streams)的通信, Native 端被动发送数据给 Flutter,通常用于状态的监听,比方网络变动、传感器数据等。

通信架构图

此图为官网的架构图

Flutter 与 Native 端通信是异步的。

通信与平台线程

Native 端被动发送数据给 Flutter时,Native 端代码须要在主线程中执行,Android 端从子线程跳转到主线程形式:

Kotlin 代码:

Handler(Looper.getMainLooper()).post {  }

Java 代码:

new Handler(Looper.getMainLooper()).post(new Runnable() {  @Override  public void run() {      }});

如果能够获取到以后 Activity,也能够应用如下形式:

activity.runOnUiThread {   }

iOS 端从子线程跳转到主线程形式:

Objective-C 代码:

dispatch_async(dispatch_get_main_queue(), ^{  });

Swift 代码:

DispatchQueue.main.async {  }

MethodChannel

Flutter 端

Flutter 端创立 MethodChannel 通道,用于与原生端通信:

var channel = MethodChannel('com.flutter.guide.MethodChannel');

com.flutter.guide.MethodChannel 是 MethodChannel 的名称,原生端要与之对应。

发送音讯:

var result = await channel.invokeMethod('sendData',{'name': 'laomeng', 'age': 18})
  • 第一个参数示意method,办法名称,原生端会解析此参数。
  • 第二个参数示意参数,类型任意,多个参数通常应用Map
  • 返回 Future,原生端返回的数据。

残缺代码:

class MethodChannelDemo extends StatefulWidget {  @override  _MethodChannelDemoState createState() => _MethodChannelDemoState();}class _MethodChannelDemoState extends State<MethodChannelDemo> {  var channel = MethodChannel('com.flutter.guide.MethodChannel');  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                  .invokeMethod('sendData', {'name': 'laomeng', 'age': 18});              var name = result['name'];              var age = result['age'];              setState(() {                _data = '$name,$age';              });            },          ),          Text('原生返回数据:$_data')        ],      ),    );  }}

Android 端

android 下创立 MethodChannelDemo

package com.flutter.guideimport io.flutter.plugin.common.BinaryMessengerimport io.flutter.plugin.common.MethodCallimport io.flutter.plugin.common.MethodChannel/** * des: */class MethodChannelDemo(messenger: BinaryMessenger): MethodChannel.MethodCallHandler {    private var channel: MethodChannel    init {        channel = MethodChannel(messenger, "com.flutter.guide.MethodChannel")        channel.setMethodCallHandler(this)    }    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {            }}

onMethodCall 办法在 Flutter 端调用 invokeMethod 办法回调,解析办法如下:

override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {    if (call.method == "sendData") {        val name = call.argument("name") as String?        val age = call.argument("age") as Int?        var map = mapOf("name" to "hello,$name",                "age" to "$age"        )        result.success(map)    }}
  • call.method 字符串就是 invokeMethod 办法传入的 method
  • call.argument 是 invokeMethod 传入的参数,因为 Flutter 端传入的是 Map,所以下面的解析依照 Map 解析。
  • result.success() 是返回给 Flutter 的后果。

Flutter 端解析:

var result = await channel    .invokeMethod('sendData', {'name': 'laomeng', 'age': 18});var name = result['name'];var age = result['age'];
两端的解析要互相对应。

MainActivity 启动:

class MainActivity : FlutterActivity() {        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {        super.configureFlutterEngine(flutterEngine)        MethodChannelDemo(flutterEngine.dartExecutor.binaryMessenger)    }}

iOS 端

ios 下创立 MethodChannelDemo,按如下形式:

import Flutterimport UIKitpublic class MethodChannelDemo {        init(messenger: FlutterBinaryMessenger) {        let channel = FlutterMethodChannel(name: "com.flutter.guide.MethodChannel", binaryMessenger: messenger)        channel.setMethodCallHandler { (call:FlutterMethodCall, result:@escaping FlutterResult) in            if (call.method == "sendData") {                if let dict = call.arguments as? Dictionary<String, Any> {                    let name:String = dict["name"] as? String ?? ""                    let age:Int = dict["age"] as? Int ?? -1                    result(["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)    GeneratedPluginRegistrant.register(with: self)        return super.application(application, didFinishLaunchingWithOptions: launchOptions)  }}

原生端被动发送音讯给Flutter

Flutter 端接收数据
@overridevoid initState() {  super.initState();  channel.setMethodCallHandler((call) {    setState(() {      _nativeData = call.arguments['count'];    });  });}
Android 发送数据

原生端启动定时器,每隔一秒向 Flutter 发送数据,Android 端代码:

class MethodChannelDemo(var activity: Activity, messenger: BinaryMessenger) : MethodChannel.MethodCallHandler {    private var channel: MethodChannel    private var count = 0    init {        channel = MethodChannel(messenger, "com.flutter.guide.MethodChannel")        channel.setMethodCallHandler(this)        startTimer()    }    fun startTimer() {        var timer = Timer().schedule(timerTask {            activity.runOnUiThread {                var map = mapOf("count" to count++)                channel.invokeMethod("timer", map)            }        }, 0, 1000)    }    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {        if (call.method == "sendData") {            val name = call.argument("name") as String?            val age = call.argument("age") as Int?            var map = mapOf("name" to "hello,$name",                    "age" to "$age"            )            result.success(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)        MethodChannelDemo(this,flutterEngine.dartExecutor.binaryMessenger)        flutterEngine.plugins.add(MyPlugin())    }}

iOS 发送数据

iOS 端启动定时器代码如下:

import Flutterimport UIKitpublic class MethodChannelDemo {    var count =  0    var channel:FlutterMethodChannel    init(messenger: FlutterBinaryMessenger) {        channel = FlutterMethodChannel(name: "com.flutter.guide.MethodChannel", binaryMessenger: messenger)        channel.setMethodCallHandler { (call:FlutterMethodCall, result:@escaping FlutterResult) in            if (call.method == "sendData") {                if let dict = call.arguments as? Dictionary<String, Any> {                    let name:String = dict["name"] as? String ?? ""                    let age:Int = dict["age"] as? Int ?? -1                    result(["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.invokeMethod("timer", arguments:args)    }}

交换

老孟Flutter博客(330个控件用法+实战入门系列文章):http://laomengit.com

欢送退出Flutter交换群(微信:laomengit)、关注公众号【老孟Flutter】: