iOS原生嵌入Flutter

打印 上一主题 下一主题

主题 778|帖子 778|积分 2334

1.嵌入Flutter

先创建ios工程

我们先创建NativeDemo ios工程然后,导入cocopad通过配置pod文件来引入Flutter 框架。

  
  1. flutter_app_path = '../flutter_module'
  2. load File.join(flutter_app_path,'.iOS','Flutter','podhelper.rb')
  3. platform :ios, '11.0'
  4. post_install do |installer|
  5.   flutter_post_install(installer)
  6. end
  7. target 'NativeDemo' do
  8.   install_all_flutter_pods(flutter_app_path)
  9.   use_frameworks!
  10. end
复制代码
创建flutter_module工程,用于原生引入调用:

在来看ios原生怎样嵌入Flutter页面:
  1. #import <Flutter/Flutter.h>
  2. @property(nonatomic, strong) FlutterEngine * flutterEngine;
  3. @property(nonatomic, strong) FlutterViewController* flutterVc;
  4. @property(nonatomic, strong) FlutterBasicMessageChannel* msgChannel;
  5. - (IBAction)pushFlutter:(id)sender {
  6.    //告诉Flutter显示one_page
  7.     FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.flutterVc];
  8.     [methodChannel invokeMethod:@"one" arguments:nil];
  9.     //弹出Flutter页面
  10.     [self presentViewController:self.flutterVc animated:YES completion:nil];
  11.     //监听Flutter页面的回调
  12.     [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
  13.         //如果是要退出
  14.         if([call.method isEqualToString:@"exit"]){
  15.             [self.flutterVc dismissViewControllerAnimated:YES completion:nil];
  16.         }
  17.     }];
  18. }
  19. - (IBAction)pushFlutterTwo:(id)sender {
  20.     //告诉Flutter显示one_page
  21.      FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"two_page" binaryMessenger:self.flutterVc];
  22.     [methodChannel invokeMethod:@"two" arguments:nil];
  23.      //弹出Flutter页面
  24.      [self presentViewController:self.flutterVc animated:YES completion:nil];
  25.      //监听Flutter页面的回调
  26.      [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
  27.          //如果是要退出
  28.          if([call.method isEqualToString:@"exit"]){
  29.              [self.flutterVc dismissViewControllerAnimated:YES completion:nil];
  30.          }
  31.      }];
  32. }
  33. - (void)viewDidLoad {
  34.     [super viewDidLoad];
  35.     self.flutterVc = [[FlutterViewController alloc] initWithEngine:self.flutterEngine nibName:nil bundle:nil];
  36.     self.msgChannel = [FlutterBasicMessageChannel  messageChannelWithName:@"messageChannel" binaryMessenger:self.flutterVc];
  37.     [self.msgChannel setMessageHandler:^(id  _Nullable message, FlutterReply  _Nonnull callback) {
  38.         NSLog(@"收到Flutter的%@",message);
  39.     }];
  40. }
  41. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  42. {
  43.     static int a = 0;
  44.     [self.msgChannel sendMessage:[NSString stringWithFormat:@"%d",a++]];
  45. }
复制代码
然后我们在看flutter_module工程代码:
  1. void initState() {
  2.     _messageChannel.setMessageHandler((message) {
  3.       print('收到来自iOS的$message');
  4.       return Future(() {});
  5.     });
  6.     super.initState();
  7.     _oneChannel.setMethodCallHandler((call) {
  8.       pageIndex = call.method;
  9.       print(call.method);
  10.       setState(() {});
  11.       return Future(() {});
  12.     });
  13.     _twoChannel.setMethodCallHandler((call) {
  14.       pageIndex = call.method;
  15.       print(call.method);
  16.       setState(() {});
  17.       return Future(() {});
  18.     });
  19.   }
  20.   // This widget is the root of your application.
  21.   @override
  22.   Widget build(BuildContext context) {
  23.     return MaterialApp(
  24.       title: 'Flutter Demo',
  25.       theme: ThemeData(
  26.         primarySwatch: Colors.blue,
  27.       ),
  28.       home: _rootPage(pageIndex),
  29.     );
  30.   }
  31.   _rootPage(String pageIndex) {
  32.     switch (pageIndex) {
  33.       case 'one':
  34.         return Scaffold(
  35.           appBar: AppBar(
  36.             title: Text(pageIndex),
  37.           ),
  38.           body: Column(
  39.             mainAxisAlignment: MainAxisAlignment.center,
  40.             children: [
  41.               ElevatedButton(
  42.                 onPressed: () {
  43.                   _oneChannel.invokeMapMethod('exit');
  44.                 },
  45.                 child: Text(pageIndex),
  46.               ),
  47.               TextField(
  48.                 onChanged: (String str) {
  49.                   _messageChannel.send(str);
  50.                 },
  51.               )
  52.             ],
  53.           ),
  54.         );
  55.       case 'two':
  56.         return Scaffold(
  57.           appBar: AppBar(
  58.             title: Text(pageIndex),
  59.           ),
  60.           body: Center(
  61.             child: ElevatedButton(
  62.               onPressed: () {
  63.                 _twoChannel.invokeMapMethod('exit');
  64.               },
  65.               child: Text(pageIndex),
  66.             ),
  67.           ),
  68.         );
  69.       default:
  70.         return Scaffold(
  71.           appBar: AppBar(
  72.             title: const Text('default'),
  73.           ),
  74.           body: Center(
  75.             child: ElevatedButton(
  76.               onPressed: () {
  77.                 _twoChannel.invokeMapMethod('exit');
  78.               },
  79.               child: Text(pageIndex),
  80.             ),
  81.           ),
  82.         );
  83.     }
  84.   }
  85. }
复制代码
运行效果:
下面是理论先容:
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:用作字符串和半结构化的数据通报。
  
  1. **结构化数据:**: 包括预定义的数据类型、格式和结构的数据,常见的比如关系型数据库中数据表里的数据。
  2. **半结构化数据:**: 具有可识别的模式并可以解析的文本数据文件,比如XML数据文件。
  3. **非结构化数据:**: 没有固定结构的数据,通常保存为不同类型的文件,比如文本文档、图片、视频等。
复制代码
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。
  1. //用于实现二进制数据NSData和不同类型数据之间的转换
  2. @protocol FlutterMessageCodec
  3. +(instancetype)sharedInstance;
  4. //将指定的类型message编码为二进制数据
  5. - (NSData *_nullable)encode:(id _nullable)message;
  6. //将二进制数据NSData解码成指定类型
  7. -(id _nullable)decode:(NSData* _nullabel)message;
  8. @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中。
  1. @protocol FlutterMethodCodec
  2. +(instancetype)sharedInstance;
  3. //将FlutterMethodCall编码为二进制NSData
  4. -(NSData *)encodeMethodCall:(FlutterMethodCall*)methodCall;
  5. //将二进制NSData methodCall解码为FlutterMethodCall
  6. - (FlutterMethodCall *)decodeMethodCall:(NSData*)methodCall;
  7. //将正常响应结果result编码为二进制
  8. -(NSData*)encodeSuccess Envelope:(id _nullable)result;
  9. //将错误响应提示编码为二进制NSData
  10. -(NSData*)encodeErrorEnvelope:(FlutterError*)error;
  11. //将二进制数据NSData解码,失败返回FlutterError
  12. -(id _nullable)decodeEnvelope:(NSData*)envelope;
复制代码

FlutterMethodCall 代表从 Flutter端发起的方法调用。方法调用包括:方法名、方法参数以及方法返回效果。因此和FlutterMessageCodec 相比,FlutterMethodCodec 中多了两个处理调用效果的方法:


  • 方法调用成功:使用 encodeSuccessEnvelope:编码result。
  • 方法调用失败:使用encodeErrorEnvelope:编码FlutterError。
decodeEnvelope:方法则用与解码iOS平台代码调用Dart中方法的效果。好比通过FlutterMethodChannel调用Flutter中的方法,且得到其返回效果。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

何小豆儿在此

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表