Flutter 与原生通信的三种方式
Flutter 与原生之间的通信依赖灵活的消息传递方式
应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)应用(原生应用)
宿主监听平台通道,并接收该消息。然后它会调用该平台的 API,并将响应发送回客户端,即应用程序的 Flutter 部分
Flutter 与原生存在三种交互方式
MethodChannel:用于传递方法调用(method invocation)通常用来调用 native 中某个方法
BasicMessageChannel:用于传递字符串和半结构化的信息,这个用的比较少
EventChannel:用于数据流(event streams)的通信。有监听功能,比如电量变化之后直接推送数据给flutter端
三种 Channel 之间互相独立,各有用途,但它们在设计上却非常相近。每种 Channel 均有三个重要成员变量:
name: String类型,代表 Channel 的名字,也是其唯一标识符
messager:BinaryMessenger 类型,代表消息信使,是消息的发送与接收的工具
codec: MessageCodec 类型或 MethodCodec 类型,代表消息的编解码器
具体使用
首先分别创建 Native 工程和 Flutter Module。我这里是以 iOS 端和 Flutter 通信为例,创建完 iOS 工程后,需要通过 CocoaPods 管理 Flutter Module。
然后在 iOS 工程里面创建 Podfile ,然后引入 Flutter Module ,具体代码如下:
platform :ios,'11.0' inhibit_all_warnings! #flutter module 文件路径 flutter_application_path = '../flutter_module' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'Native_iOS' do install_all_flutter_pods(flutter_application_path) end复制代码
注意:
flutter_application_path 这个是 Flutter 工程的路径,我是原生项目和 Flutter在一个目录下
最后在终端
pod install
一下,看是否能正常引入 Flutter Module。这样就可以在iOS工程里面导入#import <Flutter/Flutter.h>
一、MethodChannel的使用
这里写的代码实现了以下功能
1.实现了点击原生页面的按钮跳转到 Flutter 页面,在 Flutter 点击返回
按钮能正常返回原生页面
2.实现在Flutter页面点击当前电量
,从原生界面传值到 Flutter 页面
原生端代码
@property (nonatomic, strong)FlutterEngine *flutterEngine; @property (nonatomic, strong)FlutterViewController *flutterVC; @property (nonatomic, strong)FlutterMethodChannel *methodChannel; - (void)viewDidLoad { [super viewDidLoad]; //隐藏了原生的导航栏 self.navigationController.navigationBarHidden = YES; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 80, 80)]; btn.backgroundColor = [UIColor redColor]; [btn addTarget:self action: @selector(onBtnClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; self.flutterVC = [[FlutterViewController alloc] initWithEngine:self.flutterEngine nibName:nil bundle:nil]; //创建channel self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"methodChannel" binaryMessenger:self.flutterVC.binaryMessenger]; } - (void)onBtnClick { //告诉Flutter对应的页面 //Method--方法名称,arguments--参数 [self.methodChannel invokeMethod:@"EnterFlutter" arguments:@""]; //push进入Flutter页面 [self.navigationController pushViewController:self.flutterVC animated:YES]; __weak __typeof(self) weakSelf = self; //监听Flutter发来的事件 [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { //响应从Flutter页面发送来的方法 if ([call.method isEqualToString:@"exit"]) { [weakSelf.flutterVC.navigationController popViewControllerAnimated:YES]; } else if ([call.method isEqualToString:@"getBatteryLevel"]) { //传值回Flutter页面 [weakSelf.methodChannel invokeMethod:@"BatteryLevel" arguments:@"60%"]; } }]; } //创建引擎,真正在项目中,引擎可以定义为一个单例。这样处理防止在原生里面存在多引擎,是非常占有内存的 - (FlutterEngine *)flutterEngine { if (!_flutterEngine) { FlutterEngine * engine = [[FlutterEngine alloc] initWithName:@"flutterEngin"]; if (engine.run) { _flutterEngine = engine; } } return _flutterEngine; }复制代码
Flutter 端代码
class _MyHomePageState extends State<MyHomePage> { String batteryLevel = '0%'; //定义通道 final MethodChannel _methodhannel = const MethodChannel('com.pages.your/native_get'); @override void initState() { super.initState(); //Flutter端监听发送过来的数据 _methodhannel.setMethodCallHandler((call) { if (call.method == 'EnterFlutter') { print(call.arguments); } else if (call.method == 'BatteryLevel') { batteryLevel = call.arguments; } setState(() {}); return Future(() {}); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( children: [ ElevatedButton( onPressed: () { //发送消息给原生 _methodhannel.invokeListMethod('exit'); }, child: Text('返回'), ), ElevatedButton( onPressed: () { //发送消息给原生 _oneChannel.invokeListMethod('getBatteryLevel'); }, child: Text('当前电量${batteryLevel}'), ), ], ), ), ); } }复制代码
二、BasicMessageChannel的使用
它是可以双端通信的,Flutter 端可以给 iOS 发送消息,iOS 也可以给 Flutter 发送消息。这段代码实现了在 Flutter 中的 TextField 输入文字,在 iOS 端能及时输出。
原生端代码
需要在上面代码的基础上增加 MessageChannel ,并接收消息和发送消息
@property (nonatomic, strong) FlutterBasicMessageChannel *messageChannel; self.messageChannel = [FlutterBasicMessageChannel messageChannelWithName:@"messgaeChannel" binaryMessenger:self.flutterVC.binaryMessenger]; [self.messageChannel setMessageHandler:^(id _Nullable message, FlutterReply _Nonnull callback) { NSLog(@"收到Flutter的:%@",message); }];复制代码
Flutter 端代码
//需要创建和iOS端相同名称的通道 final messageChannel = const BasicMessageChannel("messgaeChannel", StandardMessageCodec());复制代码
监听消息
messageChannel.setMessageHandler((message) { print('收到来自iOS的$message'); return Future(() {}); });复制代码
发送消息
messageChannel.send(str);复制代码
三、EventChannel的使用
只能是原生发送消息给 Flutter 端,例如监听手机电量变化,网络变化,传感器等。
我这里在原生端实现了一个定时器,每隔一秒发送一个消息给 Flutter 端,模仿这个功能。
原生端代码
记得所在的类要实现这个协议 FlutterStreamHandler
//定义属性 //通道 @property (nonatomic, strong) FlutterEventChannel *eventChannel; //事件回调 @property (nonatomic, copy) FlutterEventSink events; //用于计数 @property (nonatomic, assign) NSInteger count; //初始化通道 self.eventChannel = [FlutterEventChannel eventChannelWithName:@"eventChannel" binaryMessenger:self.flutterVC.binaryMessenger]; [self.eventChannel setStreamHandler:self]; //调用创建定时器 [self createTimer]; //创建定时器 - (void)createTimer { NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector: @selector(timeStart) userInfo:nil repeats:YES]; } //发送消息 - (void)timeStart{ self.count += 1; NSDictionary *dic = [NSDictionary dictionaryWithObject:@(self.count) forKey:@"count"]; if (self.events != nil) { self.events(dic); } } //代表通道已经建好,原生端可以发送数据了 - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)eventSink { self.events = eventSink; return nil; } //代表Flutter端不再接收 - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments { self.events = nil; return nil; }复制代码
Flutter 端代码
伪原创工具 SEO网站优化 https://www.237it.com/
//创建通道 final EventChannel eventChannel = const EventChannel('eventChannel'); //开始监听数据 eventChannel.receiveBroadcastStream().listen((event) { print(event.toString()); });复制代码
以上就是iOS原生和Flutter通信的三种方式,消息传递是异步的,这确保了用户界面在消息传递时不会被挂起。
作者:周糖果
链接:https://juejin.cn/post/7035211019618091045