Channel的原理探究

2022-03-28 09:08:05 浏览数 (1)

在上一篇文章《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是什么,下面

0 人点赞