指定ios_debug_sim_unopt引擎

1.首先新建一个flutter工程,找到ios目录下在Generated文件中指定调试的引擎

  1. // ios配置文件指定引擎
  2. //FLUTTER_ENGINE=/Users/xxx/engine/src
  3. //LOCAL_ENGINE=ios_debug_sim_unopt
  4. // ios配置文件指定引擎

当然前提是这里已经使用GN构建好了
image.png
2.此时运行iOS工程,设置断点
image.png
点击屏幕触发断点,跟踪这些断点可以找到-[FlutterViewController touchesBegan:withEvent:]这个方法,找到上面的ios_debug_sim_unopt的目录,打开flutter_engine工程,在FlutterViewController.m文件中找到了这个方法。
image.png
image.png
这样通过调试debug的引擎可以一步一步来跟踪方法的实现,为我们更好的理解Flutter提供了一种方法。

Flutter Channel底层原理探究

Flutter作为一个灵活的UI框架,无论是iOS平台上的OC或Swift, 还是安卓平台上的Java或Kotlin都可以通过Platform Channel机制来与Flutter进行通讯。需要注意的是Platform Channel不依赖代码而成,而是建立在消息传递的方式上。实际上,它的工作模式和原理非常类似于基于二进制协议开发的网络服务

iOS channel原理

Flutter提供了三种Channel用作Flutter与iOS原生平台之间的数据传递
image.png

  1. FlutterMethodChannel(name: "one", binaryMessenger: self.flutterVc as! FlutterBinaryMessenger)
  2. 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

image.png
在创建一个channel后,不论是通过设置代理还是通过setHandle回调来进行消息处理,最终都会为该channel绑定一个FlutterBinaryMessengerHandler,并且以channel的name作为key,保存在一个map中。当接收到发送消息之后,会根据消息中携带的channel名称取出对应的FlutterBinaryMessengerHandler,交给BinaryMessenger处理,在ios平台上BinaryMessenger是一个名为FlutterBinaryMessenger协议

FlutterMethodChanneladdMethodCallDelegate:channel:为例
addMethodCallDelegate:channel: -> setMethodCallHandler:handler -> setMessageHandlerOnChannel:binaryMessageHandler: -> PlatformMessageRouter::SetMessageHandler

  1. void PlatformMessageRouter::SetMessageHandler(const std::string& channel,
  2. FlutterBinaryMessageHandler handler) {
  3. message_handlers_.erase(channel);
  4. if (handler) {
  5. message_handlers_[channel] =
  6. fml::ScopedBlock<FlutterBinaryMessageHandler>{handler, fml::OwnershipPolicy::Retain};
  7. }
  8. }

通过这个方法链也验证了上面说的每一个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 ``` image.png

  • FlutterStandardMessageCodec:是BasicMessage Channel默认使用的编解码器,底层是用FlutterStandardReaderWriter实现的,用于数据类型和二进制之间的编解码。支持基础数据类型包括(bool/char/string/double/float/int/long/short/array/dictionary)以及二进制数据

  • FlutterBinaryCodec:用于二进制数据与二进制数据之间的编解码,在实现上只是原封不动的将接收到的二进制数据返回
  • FlutterStringCodec:用于字符串与二进制数据之间的编解码,字符串采用utf-8编码格式
  • FlutterJSONMessageCodec:用于数据类型与二进制数据之间的编解码,支持基础数据类型,在iOS端使用NSJSONSerialization作为序列化的工具

    FlutterMethodCodec

  • FlutterMethodCodec用于二进制数据与方法调用FlutterMethodCall和返回结果之间的编解码,主要是用在FlutterMethodChannelFlutterEventChannel中 ```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对象

    1. @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对象进行编码时,会将Methodargs依次使用FlutterStandardReaderWriter进行编码,然后写成二进制数据。

    深入编解码器原理

    上面我们说过FlutterStandardMessageCodeFlutterStandardMethodCodec都是使用了FlutterStandardReaderWriter进行编码,那么我们来看下FlutterStandardMethodCodec的定义 ```objectivec

  • (instancetype)sharedInstance { static id _sharedInstance = nil; if (!_sharedInstance) { FlutterStandardReaderWriter* readerWriter =
    1. [[[FlutterStandardReaderWriter alloc] init] autorelease];
    _sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter]; } return _sharedInstance; } 重点分析`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, };

  1. `readerWithData:`NSData中读取value值<br />`writerWithData:`用于将value值写入到NSData
  2. <a name="HV6xP"></a>
  3. ### `Handler`消息处理
  4. Flutter中定义了一套handler用于处理经过`Codec`解码后的消息,在使用channel时,需要为其设置对应的handler,本质上就是为其注册一个对应的`FlutterBinaryMessageHandler`,二进制数据被`FlutterBinaryMessageHandler`进行处理,首先使用`Codec`进行解码操作,然后再分发给具体的Handler进行处理。与三种`Platform Channel`相对应,`Flutter`中也定义了三种`Handler`
  5. - `FlutterMessageHandler`用于处理字符串或者半结构化消息
  6. ```objectivec
  7. typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback);
  • FlutterMethodCallHandler用于处理方法调用
  • FlutterStreamHandler用于事件流通信,通常是用于平台主动向Flutter发送事件通知 ```objectivec @protocol FlutterStreamHandler
  • (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments
    1. eventSink:(FlutterEventSink)events;
  • (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments; @end `` onListenWithArguments:eventSink:当Flutter端开始监听平台事件时,会向平台发起一次MethodCall其中方法名为listen,也就是最终会调用FlutterStreamHandler中的这个方法,其中eventSink的参数可用于向Flutter发送事件<br />onCancelWithArguments:当Flutter端停止监听平台事件时,会向平台发起一次MethodCall其中方法名为cancel,也就是最终会调用FlutterStreamHandler`中的这个方法,在该方法中通常需要销毁一些无用的资源