前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Channel的原理探究

Channel的原理探究

作者头像
拉维
发布2022-03-28 09:08:05
9260
发布2022-03-28 09:08:05
举报
文章被收录于专栏:iOS小生活iOS小生活

在上一篇文章《Flutter引擎——下载、编译和调试》中,我们已经可以调试引擎代码了;而在《Flutter与原生工程的混合开发》中,我们使用到了FlutterMethodChannel。本文就通过Flutter引擎代码的调试来研究一下channel的原理。

一、Channel的创建

首先,我创建了一个FlutterMethodChannel实例对象:

然后我想看一下methodChannelWithName方法的实现,点进去之后:

可以看到,只定位到了方法的声明中,方法的实现定位不到了

那么如何找到该方法的实现呢?

其中最简单的方式就是找到下载到本地的Flutter引擎源代码,然后去查找对应的方法名就可以了,如下:

双击打开该工程,搜索methodChannelWithName即可:

我们今天通过另外一种断点的方式来进行调试。需要注意的是,要通过打断点的方式来调试Flutter引擎源码,就一定要将自己编译的本地Flutter引擎源码挂载到当前的Flutter项目当中,不然是定位不到对应的源码的

首先在对应地方打个断点:

运行之后断到这里,然后在控制台通过如下lldb指令打断点:

代码语言:javascript
复制
br set -n "[FlutterMethodChannel methodChannelWithName:binaryMessenger:]"

然后点击下一步,就可以定位到对应的源码地方了:

接下来我们就一步一步点进去:

代码语言:javascript
复制
+ (instancetype)methodChannelWithName:(NSString*)name
                      binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
  NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
  return [FlutterMethodChannel methodChannelWithName:name binaryMessenger:messenger codec:codec];
}

可以看到,+ (instancetype)methodChannelWithName:(NSString*)name binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger

会调用+ (instancetype)methodChannelWithName:(NSString*)name binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger codec:(NSObject<FlutterMethodCodec>*)codec

在+ (instancetype)methodChannelWithName:(NSString*)name binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger中创建了一个默认的FlutterStandardMethodCodec单例对象。FlutterStandardMethodCodec是一个解码器,下面会做详细介绍。

接下来看一下+ (instancetype)methodChannelWithName:(NSString*)name binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger codec:(NSObject<FlutterMethodCodec>*)codec的源码:

代码语言:javascript
复制
+ (instancetype)methodChannelWithName:(NSString*)name
                      binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
                                codec:(NSObject<FlutterMethodCodec>*)codec {
  return [[[FlutterMethodChannel alloc] initWithName:name binaryMessenger:messenger
                                               codec:codec] autorelease];
}

可以看到,里面调用了- (instancetype)initWithName:(NSString*)name binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger codec:(NSObject<FlutterMethodCodec>*)codec,其源码是:

代码语言:javascript
复制
- (instancetype)initWithName:(NSString*)name
             binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
                       codec:(NSObject<FlutterMethodCodec>*)codec {
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _name = [name retain];
  _messenger = [messenger retain];
  _codec = [codec retain];
  return self;
}

可以看到,channel的创建以及初始化是比较简单的。

接下来我们研究一下channel的监听。

二、channel的监听

我们是通过setMethodCallHandler方法来监听channel事件,如下:

我们通过打断点点进去,找到了setMethodCallHandler的源码:

可以看到,最终会走到setMessageHandlerOnChannel: binaryMessageHandler:函数,接下来继续通过断点走进该函数的实现:

接着点进去:

再点进去:

再点进去:

可以看到,channel作为key,handler作为value,存进了message-handlers这个Map中。实际上,在外界每一个channel都会有一个作为唯一标识的channelName,因此在设置回调的时候就要将这个回调与channel的唯一标识进行一一对应

三、channel的编码

我们在创建channel的时候,会传递三个参数,如下:

代码语言:javascript
复制
+ (instancetype)methodChannelWithName:(NSString*)name
                      binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
                                codec:(NSObject<FlutterMethodCodec>*)codec;

其中name和messenger在前面已经说过了,现在来聊一聊codec。

codec是消息编解码器,它会对你的数据类型进行编解码。比如,Swift中的Dictionary、OC中的NSDictionary以及Java中的Map,对应到Dart中都是Map,在不同的语言中其实现肯定是不一样的,那么他们是如何对应起来的呢,这就需要用到Codec了。

在Flutter中,定义了两种Codec:MessageCodec和MethodCodec。我们接下来以iOS中为例来给大家做介绍。

1,MessageCodec

可以看到,FlutterStandardMethodCodec是一个protocol协议,这个协议里面除了有一个单例获取方法之外,还有一个编码方法(用于将OC类型数据编码成二进制数据),和一个解码方法(用于将二进制数据解码成OC类型数据)

实现FlutterStandardMethodCodec协议的类有如下几个:

(1)FlutterBinaryCodec,用于二进制数据和二进制数据之间的编解码

(2)FlutterJSONMessageCodec,JSON转二进制,二进制转JSON

(3)FlutterStandardMessageCodecFlutter默认的编解码器,用于任意的OC数据类型和二进制之间的编解码

现在我们看一下FlutterStandardMessageCodec的源码:

可以看到,FlutterStandardMessageCodec类型的单例对象最终是通过FlutterStandardReaderWriter类型的一个对象来生成的。那么这里的FlutterStandardReaderWriter是什么呢?它有什么存在的必要性呢?且听我慢慢道来。

接下来再看一下FlutterStandardMethodCodec的源码(至于FlutterStandardMethodCodec是什么,下面👇会做介绍的):

可以看到,FlutterStandardMethodCodec类型的单例对象最终也是通过FlutterStandardReaderWriter类型的一个对象来生成的

而通过FlutterStandardReaderWriter这个名称我们也能理解,这个类里面实际上就是数据的读写操作,也就是说,Flutter将编解码器的核心逻辑封装、抽离到了FlutterStandardReaderWriter层(读,即解码;写,即编码)

(4)FlutterStringCodec,专门用于字符串与二进制数据之间的编解码,编码格式为UTF-8

2,MethodCodec

可以看到,FlutterMethodCodec是一个protocol协议,该协议里面,除了单例的获取方法之外,还有如下方法:

(1)encodeMethodCall,用于将OC的方法调用数据编码成二进制

它编码的对象是FlutterMethodCall,而FlutterMethodCall的定义如下:

可以看到,它里面就俩参数,一个方法名method,还有一个参数arguments,而一个OC方法实际上就是由这两个属性组成的

(2)decodeMethodCall,用于将二进制解码成OC的方法

(3)encodeSuccessEnvelope,在EventChannel中将成功的结果编码成二进制

(4)encodeErrorEnvelope,在EventChannel中将失败的结果编码成二进制

(5)decodeEnvelope,在EventChannel中,将二进制数据解码成OC类型的结果

可以看到,FlutterMethodCodec是对方法调用的编解码解析,适用于MethodChannel和EventChannel。其中,(1)和(2)用于MethodChannel中,(3)、(4)和(5)用于EventChannel中。

实现FlutterMethodCodec协议的类有如下两个:

(1)FlutterJSONMethodCodec

通过JSON格式和二进制转换数据

(2)FlutterStandardMethodCodec

标准格式是通过MethodCall转二进制或者二进制转MethodCall来使用。

以上。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档