1.嵌入Flutter
先创建ios工程
我们先创建NativeDemo ios工程然后,导入cocopad通过配置pod文件来引入Flutter 框架。
- flutter_app_path = '../flutter_module'
- load File.join(flutter_app_path,'.iOS','Flutter','podhelper.rb')
- platform :ios, '11.0'
- post_install do |installer|
- flutter_post_install(installer)
- end
- target 'NativeDemo' do
- install_all_flutter_pods(flutter_app_path)
- use_frameworks!
- end
复制代码 创建flutter_module工程,用于原生引入调用:
在来看ios原生怎样嵌入Flutter页面:
- #import <Flutter/Flutter.h>
- @property(nonatomic, strong) FlutterEngine * flutterEngine;
- @property(nonatomic, strong) FlutterViewController* flutterVc;
- @property(nonatomic, strong) FlutterBasicMessageChannel* msgChannel;
- - (IBAction)pushFlutter:(id)sender {
- //告诉Flutter显示one_page
- FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.flutterVc];
- [methodChannel invokeMethod:@"one" arguments:nil];
- //弹出Flutter页面
- [self presentViewController:self.flutterVc animated:YES completion:nil];
- //监听Flutter页面的回调
- [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
- //如果是要退出
- if([call.method isEqualToString:@"exit"]){
- [self.flutterVc dismissViewControllerAnimated:YES completion:nil];
- }
- }];
- }
- - (IBAction)pushFlutterTwo:(id)sender {
- //告诉Flutter显示one_page
- FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"two_page" binaryMessenger:self.flutterVc];
- [methodChannel invokeMethod:@"two" arguments:nil];
- //弹出Flutter页面
- [self presentViewController:self.flutterVc animated:YES completion:nil];
- //监听Flutter页面的回调
- [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
- //如果是要退出
- if([call.method isEqualToString:@"exit"]){
- [self.flutterVc dismissViewControllerAnimated:YES completion:nil];
- }
- }];
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.flutterVc = [[FlutterViewController alloc] initWithEngine:self.flutterEngine nibName:nil bundle:nil];
- self.msgChannel = [FlutterBasicMessageChannel messageChannelWithName:@"messageChannel" binaryMessenger:self.flutterVc];
- [self.msgChannel setMessageHandler:^(id _Nullable message, FlutterReply _Nonnull callback) {
- NSLog(@"收到Flutter的%@",message);
- }];
- }
- -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- {
- static int a = 0;
- [self.msgChannel sendMessage:[NSString stringWithFormat:@"%d",a++]];
- }
复制代码 然后我们在看flutter_module工程代码:
- void initState() {
- _messageChannel.setMessageHandler((message) {
- print('收到来自iOS的$message');
- return Future(() {});
- });
- super.initState();
- _oneChannel.setMethodCallHandler((call) {
- pageIndex = call.method;
- print(call.method);
- setState(() {});
- return Future(() {});
- });
- _twoChannel.setMethodCallHandler((call) {
- pageIndex = call.method;
- print(call.method);
- setState(() {});
- return Future(() {});
- });
- }
- // This widget is the root of your application.
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Flutter Demo',
- theme: ThemeData(
- primarySwatch: Colors.blue,
- ),
- home: _rootPage(pageIndex),
- );
- }
- _rootPage(String pageIndex) {
- switch (pageIndex) {
- case 'one':
- return Scaffold(
- appBar: AppBar(
- title: Text(pageIndex),
- ),
- body: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- ElevatedButton(
- onPressed: () {
- _oneChannel.invokeMapMethod('exit');
- },
- child: Text(pageIndex),
- ),
- TextField(
- onChanged: (String str) {
- _messageChannel.send(str);
- },
- )
- ],
- ),
- );
- case 'two':
- return Scaffold(
- appBar: AppBar(
- title: Text(pageIndex),
- ),
- body: Center(
- child: ElevatedButton(
- onPressed: () {
- _twoChannel.invokeMapMethod('exit');
- },
- child: Text(pageIndex),
- ),
- ),
- );
- default:
- return Scaffold(
- appBar: AppBar(
- title: const Text('default'),
- ),
- body: Center(
- child: ElevatedButton(
- onPressed: () {
- _twoChannel.invokeMapMethod('exit');
- },
- child: Text(pageIndex),
- ),
- ),
- );
- }
- }
- }
复制代码 运行效果:
下面是理论先容:
2.Flutter Channel
Flutter 作为一个灵活的UI框架。无论是ios平台上的Objective-C或Swift,还是Android平台上的Java或Kotlin都可以通过Platform Channel 机制来与Flutter进行通讯。必要注意的是Platform Channel 不依赖代码生成,而是建立在消息通报方式上。实际上,它的工作模式和原理非常类似基于二进制协议开发的网络服务。
iOS Channel 原理
Flutter 提供了三种Channel用作Flutter与iOS原生平台之间的数据通报:
1.FlutterBasicMessageChannel:用作字符串和半结构化的数据通报。
- **结构化数据:**: 包括预定义的数据类型、格式和结构的数据,常见的比如关系型数据库中数据表里的数据。
- **半结构化数据:**: 具有可识别的模式并可以解析的文本数据文件,比如XML数据文件。
- **非结构化数据:**: 没有固定结构的数据,通常保存为不同类型的文件,比如文本文档、图片、视频等。
复制代码 2.FlutterMethodChannel:用来调用方法(method invocation),包括从 Flutter向原生平台发起方法调用,也支持从原生平台Flutter发起方法调用。
3.FlutterEventChannel:用来支持数据流(streams)通信。
三种 Channel 分别带来差别的作用。但是在筹划上大同小异。都有以下三个成员变量:
- name:Channel 名称 作为每一个Channel的唯一标记。
在我们的Flutter 应用中,通常会存在多个 Platform Channel。 那么这些 Channel 之间就是通过唯一标记name 来区分。 例如,使用 FlutterMethodChannel发起方法调用时,就必要我们为MethodChannel指定对应name。
- messenger:消息信使(BinaryMessenger)
用作消息的发送和接收的工具,重要负责Flutter与原生之间的相互通讯。
普通来讲, messenger就是咱们现在的外卖小哥。messenger负责把数据从 Flutter 送到iOS平台,大概从iOS传输数据到Flutter。只管Flutter中存在三种差别用途的Channel, 但是对应的沟通工具都是 BinaryMessenger 。
在创建一个 Channel 后,不论是通过设置署理 (Delegate),还是通过 setXXXHandler:来进行消息处理。终极会为该 Channel 绑定一个 FlutterBinaryMessageHandler。 并以 Channel的name作为key , 生存在一个 Map 结构中。 当接受到发送消息后,会根据消息中携带的 Channel 名称取出对应 FlutterBinaryMessageHandler, 并交由BinaryMessenger处理。
注意:在 iOS平台BinaryMessenger 是一个名为 FlutterBinaryMessenger 的协议。
3 .Codec (编解码器)
在 Channel 中,messenger 携带的数据必要在 Dart 层, Native (iOS/Android平台)层中传输,所以就必要一种与平台无关的数据协议。既能支持图片,又能支持文件等资源。因此官方终极采用了二进制字节流作为数据传输协议。
二进制字节流: 发送方法必要把数据编码成二进制数据,接收方再把数据解码成原始数据。而负责编解码操作的就是 Codec。
在 Flutter 中有两种 Codec:
MessageCodec:对message进行编解码 MessageCodec 用于二进制数据与底子数据之间的编解码,此中 FlutterBasicMessageChannel 中采用的就是该Codec。
- //用于实现二进制数据NSData和不同类型数据之间的转换
- @protocol FlutterMessageCodec
- +(instancetype)sharedInstance;
- //将指定的类型message编码为二进制数据
- - (NSData *_nullable)encode:(id _nullable)message;
- //将二进制数据NSData解码成指定类型
- -(id _nullable)decode:(NSData* _nullabel)message;
- @end
复制代码 在 Flutter 中,MessageCodec有多种实现:
- FlutterStandardMessageCodec:是FlutterBasicMessageChannel 中默认使用的编解码器。(底层是用FlutterStandardReaderWriter 实现的)。用于数据类型和二进制数据之间的编解码。支持底子数据类型包(bool、char、double、float、int、long、short、String、Array、Dictionary)以及二进制数据。
- FlutterBinaryCodec:用于二进制数据和二进制数据之间的编解码,在实现上只是原封不动的将接收到的二进制数据返回。
- FlutterStringCodec:用于字符串与二进制数据之间的编解码,对于字符串采用 UTF-8编码格式。
- FlutterJSONMessageCodec:用于数据类型与二进制数据之间的编解码,支持底子数据类型(bool、char、double、float、int、long、short、String、Array、Dictionary)。在iOS端使用 NSJSONSerialization作为序列化工具。
FlutterMethodCodec:对 FlutterMethodCall编解码
FlutterMethodCodec 用于二进制数据与方法调用(FlutterMethodCall)和返回效果之间的编解码。重要用在FlutterMethodChannel 和 FlutterEventChannel中。
- @protocol FlutterMethodCodec
- +(instancetype)sharedInstance;
- //将FlutterMethodCall编码为二进制NSData
- -(NSData *)encodeMethodCall:(FlutterMethodCall*)methodCall;
- //将二进制NSData methodCall解码为FlutterMethodCall
- - (FlutterMethodCall *)decodeMethodCall:(NSData*)methodCall;
- //将正常响应结果result编码为二进制
- -(NSData*)encodeSuccess Envelope:(id _nullable)result;
- //将错误响应提示编码为二进制NSData
- -(NSData*)encodeErrorEnvelope:(FlutterError*)error;
- //将二进制数据NSData解码,失败返回FlutterError
- -(id _nullable)decodeEnvelope:(NSData*)envelope;
复制代码
FlutterMethodCall 代表从 Flutter端发起的方法调用。方法调用包括:方法名、方法参数以及方法返回效果。因此和FlutterMessageCodec 相比,FlutterMethodCodec 中多了两个处理调用效果的方法:
- 方法调用成功:使用 encodeSuccessEnvelope:编码result。
- 方法调用失败:使用encodeErrorEnvelope:编码FlutterError。
decodeEnvelope:方法则用与解码iOS平台代码调用Dart中方法的效果。好比通过FlutterMethodChannel调用Flutter中的方法,且得到其返回效果。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |