指定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有多种实现 ```objectivec @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
中 ```objectivec @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中多了两个处理调用结果的方法<br />当前在
FlutterMethodCodec`有两种实现FlutterJSONMethodCodec
:在将FlutterMethodCall
对象进行编码时,会首先将该对象转换成JSON对象@interface FlutterJSONMethodCodec : NSObject <FlutterMethodCodec>
```objectivec
- (NSData)encodeMethodCall:(FlutterMethodCall)call {
return [[FlutterJSONMessageCodec sharedInstance] encode:@{
@”method” : call.method,
@”args” : [self wrapNil:call.arguments],
}];
}
在编码调用结果时,会将其转化为一个数组,调用成功为`[result]`,调用失败为`[code, message, details] `
objectivec (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
的定义 ```objectivec
- (instancetype)sharedInstance {
static id _sharedInstance = nil;
if (!_sharedInstance) {
FlutterStandardReaderWriter* readerWriter =
_sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter]; } return _sharedInstance; }[[[FlutterStandardReaderWriter alloc] init] autorelease];
重点分析`FlutterStandardReaderWriter`怎么来编解码的
objectivec @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值<br />`writerWithData:`用于将value值写入到NSData中
<a name="HV6xP"></a>
### `Handler`消息处理
Flutter中定义了一套handler用于处理经过`Codec`解码后的消息,在使用channel时,需要为其设置对应的handler,本质上就是为其注册一个对应的`FlutterBinaryMessageHandler`,二进制数据被`FlutterBinaryMessageHandler`进行处理,首先使用`Codec`进行解码操作,然后再分发给具体的Handler进行处理。与三种`Platform Channel`相对应,`Flutter`中也定义了三种`Handler`
- `FlutterMessageHandler`用于处理字符串或者半结构化消息
```objectivec
typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback);
FlutterMethodCallHandler
用于处理方法调用FlutterStreamHandler
用于事件流通信,通常是用于平台主动向Flutter发送事件通知 ```objectivec @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发送事件<br />
onCancelWithArguments:当Flutter端停止监听平台事件时,会向平台发起一次
MethodCall其中方法名为cancel,也就是最终会调用
FlutterStreamHandler`中的这个方法,在该方法中通常需要销毁一些无用的资源