Flutter进阶-引擎源码调试
指定ios_debug_sim_unopt引擎
1.首先新建一个flutter工程,找到ios目录下在Generated文件中指定调试的引擎
// ios配置文件指定引擎
//FLUTTER_ENGINE=/Users/xxx/engine/src
//LOCAL_ENGINE=ios_debug_sim_unopt
// ios配置文件指定引擎
当然前提是这里已经使用GN构建好了
2.此时运行iOS工程,设置断点
点击屏幕触发断点,跟踪这些断点可以找到-[FlutterViewController touchesBegan:withEvent:]这个方法,找到上面的ios_debug_sim_unopt的目录,打开flutter_engine工程,在FlutterViewController.m文件中找到了这个方法。

这样通过调试debug的引擎可以一步一步来跟踪方法的实现,为我们更好的理解Flutter提供了一种方法。
Flutter Channel底层原理探究
Flutter作为一个灵活的UI框架,无论是iOS平台上的OC或Swift, 还是安卓平台上的Java或Kotlin都可以通过Platform Channel机制来与Flutter进行通讯。需要注意的是Platform Channel不依赖代码而成,而是建立在消息传递的方式上。实际上,它的工作模式和原理非常类似于基于二进制协议开发的网络服务
iOS channel原理
Flutter提供了三种Channel用作Flutter与iOS原生平台之间的数据传递

FlutterMethodChannel(name: "one", binaryMessenger: self.flutterVc as! FlutterBinaryMessenger)
FlutterBasicMessageChannel(name: "messageChannel", binaryMessenger: self.flutterVc.binaryMessenger)
三种channel分别带来不同的作用,但是设计上大同小异,都有以下几个成员变量
name:channel名称,作为每个channel的唯一标志。在flutter应用中,通常会存在多个Platform Channel,这些channel之间就是通过唯一标志name来区分。例如FlutterMethodChannel发起方法调用时,就需要我们为MethodChannel指定对应的标志name- messenger:消息信使(
BinaryMessenger)用作消息的发送和接收的工具,主要负责flutter与原生之间的相互通信,尽管flutter中存在三种不同的Channel,但是对应的沟通工具都是BinaryMessenger

在创建一个channel后,不论是通过设置代理还是通过setHandle回调来进行消息处理,最终都会为该channel绑定一个FlutterBinaryMessengerHandler,并且以channel的name作为key,保存在一个map中。当接收到发送消息之后,会根据消息中携带的channel名称取出对应的FlutterBinaryMessengerHandler,交给BinaryMessenger处理,在ios平台上BinaryMessenger是一个名为FlutterBinaryMessenger协议
以FlutterMethodChannel的addMethodCallDelegate:channel:为例
addMethodCallDelegate:channel: -> setMethodCallHandler:handler -> setMessageHandlerOnChannel:binaryMessageHandler: -> PlatformMessageRouter::SetMessageHandler
void PlatformMessageRouter::SetMessageHandler(const std::string& channel,
FlutterBinaryMessageHandler handler) {
message_handlers_.erase(channel);
if (handler) {
message_handlers_[channel] =
fml::ScopedBlock<FlutterBinaryMessageHandler>{handler, fml::OwnershipPolicy::Retain};
}
}
通过这个方法链也验证了上面说的每一个FlutterBinaryMessengerHandler的key值都是channel的name
- Codec(编解码器):在channel中,messenger携带的数据需要在Dart层和Native层传输,所以就需要一种与平台无关的数据协议,既能支持图片又能支持文件等资源。因此官方采用了二进制字节流作为数据传输协议。二进制字节流:发送方需要把数据编写成二进制数据,接收方再把数据解码成原始数据,而负责编解码操作的就是Codec。在flutter中有两种Codec
FlutterMessageCodec
FlutterMessageCodec:对message进行编解码,用于二进制与基础数据之间的编解码,其中FlutterBasicMessenger采用的就是这个Codec,在flutter中,MessageCodec有多种实现
@protocol FlutterMessageCodec
+ (instancetype)sharedInstance;
// 将指定类型的message编码为二进制数据
- (NSData* _Nullable)encode:(id _Nullable)message;
// 将二进制数据NSData解码成指定类型
- (id _Nullable)decode:(NSData* _Nullable)message;
@end

FlutterStandardMessageCodec:是BasicMessage Channel默认使用的编解码器,底层是用FlutterStandardReaderWriter实现的,用于数据类型和二进制之间的编解码。支持基础数据类型包括(bool/char/string/double/float/int/long/short/array/dictionary)以及二进制数据FlutterBinaryCodec:用于二进制数据与二进制数据之间的编解码,在实现上只是原封不动的将接收到的二进制数据返回FlutterStringCodec:用于字符串与二进制数据之间的编解码,字符串采用utf-8编码格式FlutterJSONMessageCodec:用于数据类型与二进制数据之间的编解码,支持基础数据类型,在iOS端使用NSJSONSerialization作为序列化的工具
FlutterMethodCodec
FlutterMethodCodec用于二进制数据与方法调用FlutterMethodCall和返回结果之间的编解码,主要是用在FlutterMethodChannel和FlutterEventChannel中
@protocol FlutterMethodCodec
+ (instancetype)sharedInstance;
// 将FlutterMethodCall编码为二进制NSData
- (NSData*)encodeMethodCall:(FlutterMethodCall*)methodCall;
// 将二进制NSData解码为FlutterMethodCall
- (FlutterMethodCall*)decodeMethodCall:(NSData*)methodCall;
// 将正常响应结果result编码为二进制
- (NSData*)encodeSuccessEnvelope:(id _Nullable)result;
// 将错误响应提示编码为二进制NSData
- (NSData*)encodeErrorEnvelope:(FlutterError*)error;
// 将二进制数据NSData解码,失败返回 FlutterError
- (id _Nullable)decodeEnvelope:(NSData*)envelope;
@end
FlutterMethodCall代表从Flutter端发起的方法调用,方法调用包括:方法名、参数以及返回结果。因此和FlutterMessageCodec相比,FlutterMethodCodec中多了两个处理调用结果的方法
当前在FlutterMethodCodec有两种实现
FlutterJSONMethodCodec:在将FlutterMethodCall对象进行编码时,会首先将该对象转换成JSON对象
@interface FlutterJSONMethodCodec : NSObject <FlutterMethodCodec>
- (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
return [[FlutterJSONMessageCodec sharedInstance] encode:@{
@"method" : call.method,
@"args" : [self wrapNil:call.arguments],
}];
}
在编码调用结果时,会将其转化为一个数组,调用成功为[result],调用失败为[code, message, details]
- (NSData*)encodeSuccessEnvelope:(id)result {
return [[FlutterJSONMessageCodec sharedInstance] encode:@[ [self wrapNil:result] ]];
}
- (NSData*)encodeErrorEnvelope:(FlutterError*)error {
return [[FlutterJSONMessageCodec sharedInstance] encode:@[
error.code,
[self wrapNil:error.message],
[self wrapNil:error.details],
]];
}
FlutterStandardMethodCodec:是FlutterMethodCodec的默认实现,当其编码在将FlutterMethodCall对象进行编码时,会将Method和args依次使用FlutterStandardReaderWriter进行编码,然后写成二进制数据。
深入编解码器原理
上面我们说过FlutterStandardMessageCode和FlutterStandardMethodCodec都是使用了FlutterStandardReaderWriter进行编码,那么我们来看下FlutterStandardMethodCodec的定义
+ (instancetype)sharedInstance {
static id _sharedInstance = nil;
if (!_sharedInstance) {
FlutterStandardReaderWriter* readerWriter =
[[[FlutterStandardReaderWriter alloc] init] autorelease];
_sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter];
}
return _sharedInstance;
}
重点分析FlutterStandardReaderWriter怎么来编解码的
@implementation FlutterStandardReaderWriter
- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
return [[[FlutterStandardWriter alloc] initWithData:data] autorelease];
}
- (FlutterStandardReader*)readerWithData:(NSData*)data {
return [[[FlutterStandardReader alloc] initWithData:data] autorelease];
}
@end
// 15个枚举值用来标识不同的数据类型,0是null,3表示Int32类型
// 在向NSData写入指定类型的数据时,需要首先写入标志位,然后紧接着写入值
// 在从NSData读取数据时,首先读取类型标志,然后读取具体的值
typedef NS_ENUM(NSInteger, FlutterStandardField) {
FlutterStandardFieldNil,
FlutterStandardFieldTrue,
FlutterStandardFieldFalse,
FlutterStandardFieldInt32,
FlutterStandardFieldInt64,
FlutterStandardFieldIntHex,
FlutterStandardFieldFloat64,
FlutterStandardFieldString,
FlutterStandardFieldUInt8Data,
FlutterStandardFieldInt32Data,
FlutterStandardFieldInt64Data,
FlutterStandardFieldFloat64Data,
FlutterStandardFieldList,
FlutterStandardFieldMap,
FlutterStandardFieldFloat32Data,
};
readerWithData:从NSData中读取value值
writerWithData:用于将value值写入到NSData中
Handler消息处理
Flutter中定义了一套handler用于处理经过Codec解码后的消息,在使用channel时,需要为其设置对应的handler,本质上就是为其注册一个对应的FlutterBinaryMessageHandler,二进制数据被FlutterBinaryMessageHandler进行处理,首先使用Codec进行解码操作,然后再分发给具体的Handler进行处理。与三种Platform Channel相对应,Flutter中也定义了三种Handler
FlutterMessageHandler用于处理字符串或者半结构化消息
typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback);
FlutterMethodCallHandler用于处理方法调用FlutterStreamHandler用于事件流通信,通常是用于平台主动向Flutter发送事件通知
@protocol FlutterStreamHandler
- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
eventSink:(FlutterEventSink)events;
- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments;
@end
onListenWithArguments:eventSink:当Flutter端开始监听平台事件时,会向平台发起一次MethodCall其中方法名为listen,也就是最终会调用FlutterStreamHandler中的这个方法,其中eventSink的参数可用于向Flutter发送事件
onCancelWithArguments:当Flutter端停止监听平台事件时,会向平台发起一次MethodCall其中方法名为cancel,也就是最终会调用FlutterStreamHandler中的这个方法,在该方法中通常需要销毁一些无用的资源
转载自:https://juejin.cn/post/7080762530926166052