1 channel原理

1. Flutter提供了三种Channel

用作Flutter与原生的数据传递

  • FlutterBasicMessageChannel:用作字符串和半结构换的数据传递

    结构化的数据:包含预定义的数据类型、格式和结构的数据,eg:关系型数据库中数据表里的数据 半结构化数据:具有可识别的模式并可以解析的文本数据文件,eg:xml数据文件 非结构化数据:没有固定结构的数据,通常保存为不同类型的文件,eg:文本文档,图片,视频等

  • FlutterMethodChannel:用来调用方法(method invocation),包括从Flutter向原生平台发起方法调用,也支持从原生平台向Flutter发起方法调用。

  • FlutterEventChannel: 用来支持数据流(streams)通信。”

2. 三种Channel都有以下三个成员变量

1. name:Channel名称

作为每个Channel的唯一标志。

在我们的Flutter应用中,通常会存在多个Platform Channel。那么这些Channel之间就是通过唯一标志name来区分。例如,使用FlutterMethodChannel发起方法调用时,就需要我们为MethodChannel指定对应的标示name。

2. messenger:消息信使(BinaryMessenger)

用作消息的发送和接收的工具,主要负责Flutter与原生之间的相互通讯。

通俗来讲,messenger就是咱们现在的外卖小哥。messenger负责把数据从Flutter送到iOS平台,或者从iOS传输数据到Flutter。尽管Flutter中存在三种不同用途的Channel,但是对应的沟通工具都是BinaryMessenger。

在创建一个Channel后,不论是通过设置代理(Delegate),还是通过setXXXXHandler:来进行消息处理。最终会为该Channel绑定一个FlutterBinaryMessageHandler。并以Channel的name作为key,保存在一个Map结构中。当接受到发送消息后,会根据消息中携带的Channel名称取出对应FlutterBinaryMessageHandler,并交由BinaryMessenger处理。

注意:在iOS平台BinaryMessenger是一个名为FlutterBinaryMessenger的协议。

以FlutterMethodChannel的addMethodCallDelegate:channel:为例:
该方法的底层代码,位于engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm:

  1. - (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
  2. channel:(FlutterMethodChannel*)channel {
  3. // 实际上也是通过setMethodCallHandler:实现的
  4. [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
  5. [delegate handleMethodCall:call result:result];
  6. }];
  7. }

然后来看setMethodCallHandler:,代码位于engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannels.mm:

  1. - (void)setMethodCallHandler:(FlutterMethodCallHandler)handler {
  2. // 可以看到底层最终调用的都是同一个方法,此时的_messenger代表的是FlutterViewController
  3. if (!handler) {
  4. [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
  5. return;
  6. }

[_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];
接下来来看FlutterViewController里的setMessageHandlerOnChannel:binaryMessageHandler:,代码位于engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm:

  1. - (void)setMessageHandlerOnChannel:(NSString*)channel
  2. binaryMessageHandler:(FlutterBinaryMessageHandler)handler {
  3. NSAssert(channel, @"The channel must not be null");
  4. // 调到FlutterEngine里面的setMessageHandlerOnChannel
  5. [_engine.get().binaryMessenger setMessageHandlerOnChannel:channel binaryMessageHandler:handler];
  6. }

进入到FlutterEngine的setMessageHandlerOnChannel:binaryMessageHandler:,代码位于engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm:

  1. - (void)setMessageHandlerOnChannel:(NSString*)channel
  2. binaryMessageHandler:(FlutterBinaryMessageHandler)handler {
  3. NSParameterAssert(channel);
  4. NSAssert(_shell && _shell->IsSetup(),
  5. @"Setting a message handler before the FlutterEngine has been run.");
  6. // 通过flutter::PlatformViewIOS获取PlatformMessageRouter
  7. self.iosPlatformView->GetPlatformMessageRouter().SetMessageHandler(channel.UTF8String, handler);
  8. }

PlatformMessageRouter,代码位于engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h

  1. // map结构
  2. std::unordered_map<std::string, fml::ScopedBlock<FlutterBinaryMessageHandler>>
  3. message_handlers_;
  1. void PlatformMessageRouter::SetMessageHandler(const std::string& channel,
  2. FlutterBinaryMessageHandler handler) {
  3. message_handlers_.erase(channel);
  4. if (handler) {
  5. // key-value形式
  6. message_handlers_[channel] =
  7. fml::ScopedBlock<FlutterBinaryMessageHandler>{handler, fml::OwnershipPolicy::Retain};
  8. }
  9. }

3. Codec(编解码器)

在Channel中,messenger携带的数据需要在Dart层,Native(iOS/Android平台)层中传输,所以就需要一种与平台无关的数据协议。既能支持图片,又能支持文件等资源。因此官方最终采用了二进制字节流作为数据传输协议。
二进制字节流:发送方需要把数据编码成二进制数据,接收方再把数据解码成原始数据。而负责编解码操作的就是Codec。

FlutterMethodCodec:对FlutterMethodCall编解码

FlutterMethodCodec用于二进制数据与方法调用(FlutterMethodCall)和返回结果之间的编解码。主要用在FlutterMethodChannel和FlutterEventChannel中。

image.png
创建channel
image.png
image.png

监听channel
image.png
image.png
FlutterBinaryMessager协议定义
image.png
FlutterBinaryMessager协议实现未找到,项目调试

3 项目调试引擎

  1. 新建项目
  2. 配置引擎

image.png

  1. 遵循协议FlutterBinaryMessager

image.png

  1. 创建channel

image.png

  1. 断点调试进入函数体,找到-setMessageHandlerOnChannel:binaryMessageHandler:的实现

image.png
_engine.get().binaryMessager 是消息信使,创建channel时传递的binaryMessager
channel是创建channel时的name
handle是内部包含了外部handler的回调call

  1. 进入_engine.get().binaryMessager的-setMessageHandlerOnChannel:binaryMessageHandler:中

image.png

  1. 进入self.parent的-setMessageHandlerOnChannel:binaryMessageHandler:中

image.png
将channel作为key,handler作为value存储起来
image.png

2 codec编解器

在Flutter中有两种Codec:FlutterMessageCodec和FlutterMethodCodec

MessageCodec对message进行编解码

FlutterMessageCodec

用于二进制数据与基础数据之间的编解码,其中FlutterBasicMessageChannel中采用的就是该Codec。

  1. // 用于实现二进制数据NSData和不同类型数据之间的转换
  2. @protocol FlutterMessageCodec
  3. /**
  4. * Returns a shared instance of this `FlutterMessageCodec`.
  5. */
  6. + (instancetype)sharedInstance;
  7. // 将指定的类型message编码为二进制数据
  8. - (NSData* _Nullable)encode:(id _Nullable)message;
  9. // 将二进制数据NSData解码成指定类型
  10. - (id _Nullable)decode:(NSData* _Nullable)message;
  11. @end

四种FlutterMessageCodec:

  • FlutterJSONMessageCodec:用于数据类型与二进制数据之间的编解码,支持基础数据类型(bool、char、double、float、int、long、short、String、Array、Dictionary)。在iOS端使用NSJSONSerialization作为序列化的工具。
  • FlutterBinaryCodec 二进制数据之间的编解码
  • FlutterStringCodec 字符串与二进制数据之间的编解码,对于字符串采用UTF-8编码格式。
  • FlutterStandardMessageCodec 默认编解码器,任意类型和二进制数据之间的编解码,原理是使用FlutterStandardReaderWriter实现的。用于数据类型和二进制数据之间的编解码。支持基础数据类型包(bool、char、double、float、int、long、short、String、Array、Dictionary)以及二进制数据。

FlutterBinaryCodec:用于二进制数据和二进制数据之间的编解码,在实现上只是原封不动的将接收到的二进制数据返回。

在FlutterStandardMethodCodec中最重要的两个方法是writeValue:和readValueOfType:。前者用于将value值写入到NSData中,后者从NSData中读取value值。在iOS中,将当前手机电量传递给Flutter的过程中。假设电量值为100。那么该值转换成二进制数据流程为:
首先向NSData中写入表示int32类型的标志值FlutterStandardFieldInt32。
因为int32占4个byte。将value值继续写入到NSData中。
当Flutter接受到该二进制数据后:

先读取第一个byte值。根据此值得知后面需要读取一个int32类型的数据。
随后读取后面4个byte。并将其转为dart类型中int类型。

image.png

FlutterStandardReaderWriter

image.png
读写数据:

  1. @implementation FlutterStandardWriter {
  2. NSMutableData* _data;
  3. }
  4. .......
  5. - (void)writeAlignment:(UInt8)alignment {
  6. UInt8 mod = _data.length % alignment;
  7. if (mod) {
  8. for (int i = 0; i < (alignment - mod); i++) {
  9. [self writeByte:0];
  10. }
  11. }
  12. }
  13. “.......
  14. /**
  15. 下面14个枚举值用来标志不同类型的数据,比如0表示NULL,3表示Int32类型。
  16. 在向NSData写入指定类型的数据时,需要首先写入类型标志。然后紧跟着写入具体的值。
  17. 在从NSData读取数据时,首先读取类型标志,然后读取具体的数值。
  18. */
  19. typedef NS_ENUM(NSInteger, FlutterStandardField) {
  20. FlutterStandardFieldNil,
  21. FlutterStandardFieldTrue,
  22. FlutterStandardFieldFalse,
  23. FlutterStandardFieldInt32,
  24. FlutterStandardFieldInt64,
  25. FlutterStandardFieldIntHex,
  26. FlutterStandardFieldFloat64,
  27. FlutterStandardFieldString,
  28. // The following must match the corresponding order from `FlutterStandardDataType`.
  29. FlutterStandardFieldUInt8Data,
  30. FlutterStandardFieldInt32Data,
  31. FlutterStandardFieldInt64Data,
  32. FlutterStandardFieldFloat64Data,
  33. FlutterStandardFieldList,
  34. FlutterStandardFieldMap,
  35. };
  36. // 根据数据类型,先向data中写入类型标志值
  37. - (void)writeValue:(id)value {
  38. if (value == nil || value == [NSNull null]) {
  39. [self writeByte:FlutterStandardFieldNil];
  40. } else if ([value isKindOfClass:[NSNumber class]]) {
  41. CFNumberRef number = (CFNumberRef)value;
  42. BOOL success = NO;
  43. if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
  44. BOOL b = CFBooleanGetValue((CFBooleanRef)number);
  45. [self writeByte:(b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse)];
  46. success = YES;
  47. } else if (CFNumberIsFloatType(number)) {
  48. Float64 f;
  49. success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
  50. if (success) {
  51. // 1. 写入类型标志值
  52. [self writeByte:FlutterStandardFieldFloat64];
  53. // 2. 指定对齐方式,用0补足
  54. [self writeAlignment:8];
  55. // 3. f转为byte,写入到NSData中
  56. [self writeBytes:(UInt8*)&f length:8];
  57. }
  58. } else if (CFNumberGetByteSize(number) <= 4) {
  59. SInt32 n;
  60. success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
  61. if (success) {
  62. [self writeByte:FlutterStandardFieldInt32];
  63. [self writeBytes:(UInt8*)&n length:4];
  64. }
  65. } else if (CFNumberGetByteSize(number) <= 8) {
  66. SInt64 n;
  67. success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
  68. if (success) {
  69. [self writeByte:FlutterStandardFieldInt64];
  70. [self writeBytes:(UInt8*)&n length:8];
  71. }
  72. }
  73. if (!success) {
  74. NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
  75. NSAssert(NO, @"Unsupported value for standard codec");
  76. }
  77. } else if ([value isKindOfClass:[NSString class]]) {
  78. NSString* string = value;
  79. [self writeByte:FlutterStandardFieldString];
  80. [self writeUTF8:string];
  81. } else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
  82. FlutterStandardTypedData* typedData = value;
  83. [self writeByte:FlutterStandardFieldForDataType(typedData.type)];
  84. [self writeSize:typedData.elementCount];
  85. [self writeAlignment:typedData.elementSize];
  86. [self writeData:typedData.data];
  87. } else if ([value isKindOfClass:[NSData class]]) {
  88. [self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]];
  89. } else if ([value isKindOfClass:[NSArray class]]) {
  90. NSArray* array = value;
  91. [self writeByte:FlutterStandardFieldList];
  92. [self writeSize:array.count];
  93. for (id object in array) {
  94. [self writeValue:object];
  95. }
  96. } else if ([value isKindOfClass:[NSDictionary class]]) {
  97. NSDictionary* dict = value;
  98. [self writeByte:FlutterStandardFieldMap];
  99. [self writeSize:dict.count];
  100. for (id key in dict) {
  101. [self writeValue:key];
  102. [self writeValue:[dict objectForKey:key]];
  103. }
  104. } else {
  105. NSLog(@"Unsupported value: %@ of type %@", value, [value class]);
  106. NSAssert(NO, @"Unsupported value for standard codec");
  107. }
  108. }
  109. @end
  110. @implementation FlutterStandardReader {
  111. NSData* _data;
  112. NSRange _range;
  113. }
  114. - (instancetype)initWithData:(NSData*)data {
  115. self = [super init];
  116. NSAssert(self, @"Super init cannot be nil");
  117. _data = [data retain];
  118. _range = NSMakeRange(0, 0);
  119. return self;
  120. }
  121. - (void)dealloc {
  122. [_data release];
  123. [super dealloc];
  124. }
  125. .......
  126. // `writeValue:`方法反向过程,原理一致
  127. - (nullable id)readValueOfType:(UInt8)type {
  128. // 根据标志位,取出数据类型
  129. FlutterStandardField field = (FlutterStandardField)type;
  130. switch (field) {
  131. case FlutterStandardFieldNil:
  132. return nil;
  133. case FlutterStandardFieldTrue:
  134. return @YES;
  135. case FlutterStandardFieldFalse:
  136. return @NO;
  137. case FlutterStandardFieldInt32: {
  138. SInt32 value;
  139. // 根据数据类型和长度,从NSData中读出数据,包装成NSNumber
  140. [self readBytes:&value length:4];
  141. return @(value);
  142. }
  143. case FlutterStandardFieldInt64: {
  144. SInt64 value;
  145. [self readBytes:&value length:8];
  146. return @(value);
  147. }
  148. case FlutterStandardFieldFloat64: {
  149. Float64 value;
  150. [self readAlignment:8];
  151. [self readBytes:&value length:8];
  152. return [NSNumber numberWithDouble:value];
  153. }
  154. case FlutterStandardFieldIntHex:
  155. case FlutterStandardFieldString:
  156. return [self readUTF8];
  157. case FlutterStandardFieldUInt8Data:
  158. case FlutterStandardFieldInt32Data:
  159. case FlutterStandardFieldInt64Data:
  160. case FlutterStandardFieldFloat64Data:
  161. return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
  162. case FlutterStandardFieldList: {
  163. UInt32 length = [self readSize];
  164. NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
  165. for (UInt32 i = 0; i < length; i++) {
  166. id value = [self readValue];
  167. [array addObject:(value == nil ? [NSNull null] : value)];
  168. }
  169. return array;
  170. }
  171. case FlutterStandardFieldMap: {
  172. UInt32 size = [self readSize];
  173. NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size];
  174. for (UInt32 i = 0; i < size; i++) {
  175. id key = [self readValue];
  176. id val = [self readValue];
  177. [dict setObject:(val == nil ? [NSNull null] : val)
  178. forKey:(key == nil ? [NSNull null] : key)];
  179. }
  180. return dict;
  181. }
  182. default:
  183. NSAssert(NO, @"Corrupted standard message");
  184. }
  185. }
  186. @end
  187. @implementation FlutterStandardReaderWriter
  188. - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
  189. return [[[FlutterStandardWriter alloc] initWithData:data] autorelease];
  190. }
  191. - (FlutterStandardReader*)readerWithData:(NSData*)data {
  192. return [[[FlutterStandardReader alloc] initWithData:data] autorelease];
  193. }
  194. @end

FlutterMethodCodec

  1. FLUTTER_EXPORT
  2. @protocol FlutterMethodCodec
  3. /**
  4. * Provides access to a shared instance this codec.
  5. *
  6. * @return The shared instance.
  7. */
  8. + (instancetype)sharedInstance;
  9. // 将FlutterMethodCall编码为二进制NSData
  10. - (NSData*)encodeMethodCall:(FlutterMethodCall*)methodCall;
  11. // 将二进制NSData methodCall解码为FlutterMethodCall
  12. - (FlutterMethodCall*)decodeMethodCall:(NSData*)methodCall;
  13. // 将正常响应结果result编码为二进制
  14. - (NSData*)encodeSuccessEnvelope:(id _Nullable)result;
  15. // 将错误响应提示编码为二进制NSData
  16. - (NSData*)encodeErrorEnvelope:(FlutterError*)error;
  17. // 将二进制数据NSData解码,失败返回`FlutterError`
  18. - (id _Nullable)decodeEnvelope:(NSData*)envelope;
  19. @end

两种FlutterMethodCodec:

  • FlutterStandardMethodCodec 原理同FlutterStandardMessageCodec一样,是使用FlutterStandardReaderWriter实现的 ```objectivec @implementation FlutterStandardMethodCodec { FlutterStandardReaderWriter* _readerWriter; }
  • (instancetype)sharedInstance { static id _sharedInstance = nil; if (!_sharedInstance) { //初始化readerWriter,用来编码和解码 FlutterStandardReaderWriter* readerWriter =
    1. [[[FlutterStandardReaderWriter alloc] init] autorelease];
    _sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter]; } return _sharedInstance; }
  • (NSData)encodeMethodCall:(FlutterMethodCall)call { …….. // 将call写入二进制字节流中 FlutterStandardWriter* writer = [_readerWriter writerWithData:data]; [writer writeValue:call.method]; [writer writeValue:call.arguments]; …….. }

  • (NSData)encodeSuccessEnvelope:(id)result { …….. FlutterStandardWriter writer = [_readerWriter writerWithData:data]; [writer writeByte:0]; [writer writeValue:result]; …….. }

  • (NSData)encodeErrorEnvelope:(FlutterError)error { …….. FlutterStandardWriter* writer = [_readerWriter writerWithData:data]; [writer writeByte:1]; [writer writeValue:error.code]; [writer writeValue:error.message]; [writer writeValue:error.details]; …….. }

  • (FlutterMethodCall)decodeMethodCall:(NSData)message { // 从二进制字节流message中读取数据,转成FlutterMethodCall FlutterStandardReader* reader = [_readerWriter readerWithData:message]; …….. }

  • (id)decodeEnvelope:(NSData)envelope { FlutterStandardReader reader = [_readerWriter readerWithData:envelope]; …….. }

@end

  1. - FlutterJSONMethodCodec
  2. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1994311/1626145249821-5806970f-1d9f-4a6b-8925-b6b0c3d99312.png#clientId=u47ed944a-0844-4&from=paste&height=521&id=ue747efaa&margin=%5Bobject%20Object%5D&name=image.png&originHeight=520&originWidth=747&originalType=binary&ratio=1&size=318446&status=done&style=none&taskId=u66dc612f-5df2-4387-ba67-8e1713fd540&width=748.4918518066406)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1994311/1626145321411-28f1ea92-79e6-426b-a88b-b9196d274abd.png#clientId=u47ed944a-0844-4&from=paste&height=416&id=u113817c7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=411&originWidth=739&originalType=binary&ratio=1&size=325268&status=done&style=none&taskId=ub8ade585-3ad6-474a-8271-7dc98211208&width=748.4972839355469)
  3. <a name="xCXbB"></a>
  4. #### FlutterMethodCall
  5. 代表从Flutter端发起的方法调用。方法调用包括:方法名、方法参数以及方法返回结果。因此和FlutterMessageCodec相比,FlutterMethodCodec中多了两个处理调用结果的方法:<br />方法调用成功:使用encodeSuccessEnvelope:编码result。<br />方法调用失败:使用encodeErrorEnvelope:()编码FlutterError。<br />decodeEnvelope:方法则用于解码iOS平台代码调用Dart中方法的结。比如通过FlutterMethodChannel调用Flutter中的方法,且获得其返回结果。
  6. 当前在FlutterMethodCodec有两种实现:
  7. FlutterJSONMethodCodecFlutterJSONMethodCodec编解码器依赖于FlutterJSONMethodCodec。在将FlutterMethodCall对象进行编码时,会首先将该对象转成JSON对象:
  8. ```objectivec
  9. {
  10. "method":method,
  11. "args":args
  12. }

代码位于engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm:

  1. - (NSData*)encodeMethodCall:(FlutterMethodCall*)call { return [[FlutterJSONMessageCodec sharedInstance] encode:@{
  2. @"method" : call.method,
  3. @"args" : [self wrapNil:call.arguments],
  4. }];
  5. }

其在编码调用结果时,会将其转化为一个数组,调用成功为[result],调用失败为[code, message, details]。

  1. - (NSData*)encodeSuccessEnvelope:(id)result {
  2. // 数组
  3. return [[FlutterJSONMessageCodec sharedInstance] encode:@[ [self wrapNil:result] ]];
  4. }
  5. - (NSData*)encodeErrorEnvelope:(FlutterError*)error {
  6. // 数组
  7. return [[FlutterJSONMessageCodec sharedInstance] encode:@[
  8. error.code,
  9. [self wrapNil:error.message],
  10. [self wrapNil:error.details],
  11. ]];
  12. }

当前想要调用某个Channel的setVolum(12)。其对应的MethodCall被被转成:

  1. {
  2. "method":"setVolum",
  3. "args":{
  4. "volum":5
  5. }
  6. }

接下来使用FlutterJSONMessageCodec将其编码为二进制数据。

FlutterStandardMethodCodec:它是FlutterMethodCodec的默认实现。当其编码在将FlutterMethodCall对象进行编码时,会将method和args依次使用FlutterStandardReaderWriter进行编码,然后写成二进制数据。

注意:Flutter新版本的StandardMethodCodec不再依赖StandardMessageCodec对method和args进行编码。而是使用公共类FlutterStandardReaderWriter进行编码。

3 Handler消息处理

Flutter中定义了一套Handler用于处理经过Codec解码后消息。在使用Channel时,需要为其设置对应的Handler。本质上就是为其注册一个对应FlutterBinaryMessageHandler,二进制数据被FlutterBinaryMessageHandler进行处理。首先使用Codec进行解码操作,然后再分发给具体Handler进行处理。与三种Platform Channel相对应,Flutter中也定义了三种Handler:

FlutterMessageHandler

用于处理字符串或者半结构化消息,定义在FlutterBasicMessageChannel中。

// 处理来自Flutter中的消息,有两个参数:id类型的消息以及用于异步返回的FlutterReply
typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback);

FlutterMethodCallHandler

用于处理方法调用,定义在MethodChannel中。
代码位于engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannels.mm:

  1. // result用来异步提交调用结果。
  2. typedef void (^FlutterMethodCallHandler)(FlutterMethodCall* call, FlutterResult result)
  3. - (void)setMethodCallHandler:(FlutterMethodCallHandler)handler {
  4. if (!handler) {
  5. [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
  6. return;
  7. }
  8. // Make sure the block captures the codec, not self.
  9. NSObject<FlutterMethodCodec>* codec = _codec;
  10. FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
  11. FlutterMethodCall* call = [codec decodeMethodCall:message];
  12. handler(call, ^(id result) {
  13. // 如果返回的是FlutterMethodNotImplemented表明此次调用未找到方法。
  14. if (result == FlutterMethodNotImplemented)
  15. callback(nil);
  16. // 如果返回的是FlutterError表明调用失败。
  17. else if ([result isKindOfClass:[FlutterError class]])
  18. callback([codec encodeErrorEnvelope:(FlutterError*)result]);
  19. else
  20. callback([codec encodeSuccessEnvelope:result]);
  21. });
  22. };
  23. [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];}

FlutterStreamHandler

用于事件流(Stream)通信,定义在EventChannel中。StreamHandler用于事件流的通信,通常是用于平台主动向Flutter发送事件通知。在iOS中是一个FlutterStreamHandler协议。

  1. @protocol FlutterStreamHandler
  2. - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
  3. eventSink:(FlutterEventSink)events;
  4. - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments;
  5. @end

在FlutterStreamHandler存在两个方法:
代码位于:

  1. static void SetStreamHandlerMessageHandlerOnChannel(NSObject<FlutterStreamHandler>* handler,
  2. NSString* name,
  3. NSObject<FlutterBinaryMessenger>* messenger,
  4. NSObject<FlutterMethodCodec>* codec) {
  5. __block FlutterEventSink currentSink = nil;
  6. FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
  7. FlutterMethodCall* call = [codec decodeMethodCall:message];
  8. if ([call.method isEqual:@"listen"]) {
  9. ......
  10. FlutterError* error = [handler onListenWithArguments:call.arguments eventSink:currentSink];
  11. ......
  12. } else if ([call.method isEqual:@"cancel"]) {
  13. ......
  14. FlutterError* error = [handler onCancelWithArguments:call.arguments];
  15. ......
  16. }
  17. [messenger setMessageHandlerOnChannel:name binaryMessageHandler:messageHandler];
  18. }
  • onListenWithArguments:。当Flutter端开始监听平台事件时,会向平台发起一次MethodCall,其中方法名为listen,也就是最终会调用FlutterStreamHandler中的onListenWithArguments:方法。该方法中接受两个参数,其中eventSink的参数可用于向Flutter发送事件(实际上还是通过BinaryMessager)。

  • onCancelWithArguments:。当Flutter开始停止监听平台事件时,会再向平台发起一次MethodCall,其中方法名为cancel,最终会调用[…]