持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情
- 本文主要介绍 flutter与原生端的通信方式之一的MethodChannel,通过和原生客户端的交互方式。
MethodChannel:Flutter 与Native端相互调用,调用后可以返回结果,可以 Native 端主动调用,也可以Flutter主动调用,属于双向通信。此方式为最常用的方式, Native 端调用需要在主线程中执行。
下图是官方的架构图
消息和响应是异步传递的,以确保用户界面保持响应。
注意: 尽管 Flutter 与 Dart 异步发送消息,但无论何时调用通道方法,都必须在平台的主线程上调用该方法。 有关更多信息,请参阅线程部分。
在客户端,MethodChannel启用发送与方法调用相对应的消息。在平台方面, MethodChannelAndroid ( MethodChannelAndroid) 和 FlutterMethodChanneliOS ( MethodChanneliOS) 允许接收方法调用并返回结果。这些类允许您使用非常少的“样板”代码开发平台插件。
1. 平台线程
上面说了Flutter 与 Dart 异步发送消息,但无论何时调用通道方法,都必须在平台的主线程上调用该方法。因此我们看下Android 端从子线程跳转到主线程方式
- Kotlin 代码:
Handler(Looper.getMainLooper()).post {
}
- Java 代码:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
}
});
- 获取Activity activity.runOnUiThread {
} iOS 端从子线程跳转到主线程方式:
- OC代码
// 1.NSThread
[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
- (void)updateUI {
}
// 2.NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
// 3.GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
- Swfit代码
// gcd
DispatchQueue.main.async {
}
//其他类似
2. MethodChannel
2.1 Flutter
在flutter端我们创建一个MethodChannel通道进行通信,其中com.flutter.test.MethodChannel就是MethodChannel的名称,与之交互的客户端要对应。
static const channel = MethodChannel('com.flutter.test.MethodChannel');
发送消息
var reslut = await platform.invokeMethod('userInfo', {'name': 'Jack', 'city': "New York"});
- 第一个参数表示method,方法名称,原生端会解析此参数。
- 第二个参数表示参数,类型任意,多个参数通常使用Map。
- 返回 Future,原生端返回的数据。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MethodChannelDemo extends StatefulWidget {
@override
_MethodChannelDemoState createState() => _MethodChannelDemoState();
}
class _MethodChannelDemoState extends State<MethodChannelDemo> {
var channel = const MethodChannel('com.flutter.test.MethodChannel');
var _data;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
SizedBox(
height: 150,
),
RaisedButton(
child: const Text('发送数据到原生'),
onPressed: () async {
var result = await channel.invokeMethod('sendData', {'name': 'Jack', 'age': 18});
var name = result['name'];
var age = result['age'];
setState(() {
_data = '$name,$age';
});
},
),
Text('原生返回数据:$_data')
],
),
);
}
}
2.2 ios
我们在iOS客户端创建一个MethodChannelDemo对象
import UIKit
import Flutter
class MethodChannelDemo: NSObject {
init(messenger: FlutterBinaryMessenger) {
let channel = FlutterMethodChannel(name: "com.flutter.test.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 ?? 0
result(["name":"hello,\(name)","age":age-1])
}
}
}
}
}
之后在AppDelegate之中注册
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)
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
运行结果
点击后,我们对age 处理减1.
我们继续看下客户端给flutter端发送消息除了result这种被动的,看下如何主动进行发送,点击的时候发生定时器进行发送数据
class MethodChannelDemo {
var count = 0
var channel:FlutterMethodChannel
var timer :Timer!
init(messenger: FlutterBinaryMessenger) {
channel = FlutterMethodChannel(name: "com.flutter.test.MethodChannel", binaryMessenger: messenger)
channel.setMethodCallHandler { [self] (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 ?? 0
result(["name":"hello,\(name)","age":age-1])
}
startTimer()
}
}
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval:1, target: self, selector:#selector(self.tickDown),userInfo:nil,repeats: true)
}
@objc func tickDown(){
count += 1
let args = ["count":count]
channel.invokeMethod("timer", arguments:args)
}
}
我们在flutter中接收数据,刷新状态
var _nativeData;
@override
void initState() {
super.initState();
channel.setMethodCallHandler((call) async {
setState(() {
_nativeData = call.arguments['count'];
});
});
}
点击发送数据
android的流程也是类似的,可以看下,这里就不展示了。
3.小结
MethodChannel流程就是通过注册进行回调交互,了解下流程就好,具体的可以看下官方文档。后面也是推荐插件进行处理和原生客户端的通信。