一、簡介
Platform Channel 是 Flutter 端與 Platform 端制定的通信機制,由官方提供用於 Dart 和平臺之間的相互通信。
分爲以下 3 種
(1)BaseMessageChannel :用於傳遞字符串和半結構化的信息(在大內存數據塊傳遞的情況下使用)
(2)MethodChannel:用於傳遞方法調用(Method Invocation)
(3)EventChannel: 用於數據流(Event Streams)的通信
二、消息傳遞與編碼器
Flutter 的消息傳遞工具是 BinaryMessager ,通過它與 Platform 建立起通信關係,消息以二進制的格式進行傳遞。
如圖所示 BinaryMessager 的傳遞需要經過 BinaryMessageHandler,BinaryMessagerHandler 是以 Channel Name 作爲鍵值生成出來再被註冊到 BinaryMessager 上的,BinaryMessageHandler 和 BinaryMessager 是一一對應的,二進制格式的消息通過消息編碼器(Codec)解碼爲可識別的信息,並傳遞給 Handler 進行處理。Handler 處理完後,會把結果編碼爲二進制格式,再通過回調函數返回結果併發送回 Flutter 端。
1.編碼器分類
(1)MessageCodec:BinaryCodec、StringCodec、JSONMessageCodec、StandardMessageCodec
(2)MethodCodec:JSONMethodCodec、StandardMessageCodec
經過消息編碼器處理後,消息就可以被 Handler 進行處理了。
2.消息編碼過程
Android 端的返回值是 java.lang.Integer 類型的,而 iOS 端返回值則是一個 NSNumber 類型的(通過 NSNumber numberWithInt:獲取)。而到了 Flutter 端時,這個返回值自動“變成 ”了 Dart 語言的 Int 類型。
standard platform channels 使用 standard messsage codec 對 message 和 response 進行序列化和反序列化,message與 response 可以是 booleans, numbers, Strings, byte buffers,List, Maps 等等,而序列化後得到的則是二進制格式的數據。
Flutter 默認的消息編碼器是 StandardMessageCodec ,支持的數據類型如下:
三、MethodChannel
MethodChannel 是 Flutter 與 Platform 之間傳遞信息的一種,其傳遞過程是:BinaryMessager > BinaryMessagerHandler > MethodChannel。
如上圖:Native 端(iOS 和 Android)爲宿主端(host),Flutter 則是客戶端(client),Flutter 調用 Native 方法時,需要傳遞的信息是通過平臺通道傳遞到宿主端的,Native 收到調用的信息後方可執行指定的操作。如有返回的數據,則 Native 會將數據再通過平臺通道一併傳遞給 Flutter,其中數據傳遞是異步的,這樣就能確保消息傳遞時用戶界面不會被阻塞。
1.Flutter 層(Dart 層)
Flutter 端使用 MethodChannel 的 invokeMethod 方法發起一次方法調用時,開始了消息傳遞流程。invokeMethod 方法會將其入參 message 和 arguments 封裝成一個 MethodCall 對象,並使用 MethodCodec 將其編碼爲二進制格式數據,再通過 BinaryMessages 將消息發出。(注意,此處提到的類名與方法名均爲 Dart 層的實現)
上述過程最終會調用到 ui.Window 的 _sendPlatformMessage 方法,該方法是一個Native 方法,其實現在 Native 層,這與 Java 的 JNI 技術非常類似。我們向 Native 層發送了三個參數:
• name,String 類型,代表 Channel 名稱
• data,ByteData 類型,即之前封裝的二進制數據
• callback,Function 類型,用於結果回調
2.Native 層
到 Native 層後,window.cc 的 SendPlatformMessage 方法接受了來自 Dart 層的三個參數,並對它們做了一定的處理:Dart 層的回調 callback 封裝爲 Native 層的 PlatformMessageResponseDart 類型的 response;dart 層的二進制數據 data 轉化爲 std::vector<uint8t> 類型數據 data;根據 response, data 以及 Channel 名稱 name 創建一個 PlatformMessage 對象,並通過dartstate->window()->client()->HandlePlatformMessage 方法處理 PlatformMessage 對象。
dart_state->window()->client()是一個 WindowClient,而其具體的實現爲 RuntimeController,RuntimeController 會將消息交給其代理 RuntimeDelegate 處理。
RuntimeDelegate 的實現爲 Engine,Engine 在處理 Message 時,會判斷該消息是否是爲了獲取資源(channel 等於"flutter/assets"),如果是,則走獲取資源邏輯,否則調用 Engine::Delegate 的 OnEngineHandlePlatformMessage 方法。
Engine::Delegate 的具體實現爲 Shell,其 OnEngineHandlePlatformMessage 接收到消息後,會向 PlatformTaskRunner 添加一個 Task,該 Task 會調用 PlatformView 的 HandlePlatformMessage 方法。值得注意的是,Task 中的代碼執行在 Platform Task Runner 中,而之前的代碼均執行在 UI Task Runner 中。
四、消息處理
PlatformView 的 HandlePlatformMessage 方法在不同平臺有不同的實現,但是其基本原理是相同的。
1.PlatformView
AndroidPlatformViewAndroid 是 Platformview 的子類,也是其在 Android 端的具體實現。當 PlatformViewAndroid 接收到 PlatformMessage 類型的消息時,如果消息中有 response(類型爲 PlatformMessageResponseDart),則生成一個自增長的 responseid,並以 responseid 爲key,response 爲 value 存入字典 pendingresponses 中。接着,將 channel 和 data 均轉化爲 Java 可識別的數據,通過 JNI 向 Java 層發起調用,將 response_id、channel 和 data 傳遞過去。
Java 層中,被調用的代碼爲 FlutterNativeView (BinaryMessager 的具體實現)的 handlePlatformMessage ,該方法會根據 channel 找到對應的 BinaryMessageHandler 並將消息傳遞給它處理。
BinaryMessageHandler 處理完成後,FlutterNativeView 會通過 JNI 調用 native 的方法,將 responsedata 和 responseid 傳遞到 native 層。
Native 層,PlatformViewAndroid 的 InvokePlatformMessageResponseCallback 接收到了 respondid 和 responsedata。其先將 responsedata 轉化爲二進制結果,並根據 responseid,從 pandingresponses 中找到對應的 PlatformMessageResponseDart 對象,調用其 Complete 方法將二進制結果返回。
2.PlatformViewIOS
PlatformViewIOS 是 PlatformView 的子類,也是其在 iOS 端的具體實現,當 PlatformViewIOS 接收到 message 時會交給 PlatformMessageRouter 處理。
PlatformMessageRouter通過 PlatformMessage 中的 channel 找到對應的 FlutterBinaryMessageHandler,並將二進制消息其處理,消息處理完成後,直接調用 PlatformMessage 對象中的 PlatformMessageResponseDart 對象的 Complete 方法將二進制結果返回。
3.結果回傳
PlatformMessageResponseDart 的 Complete 方法向 UI Task Runner 添加了一個新的 Task,這個 Task 的作用是將二進制結果從 native 的二進制數據類型轉化爲 Dart 的二進制數據類型 response,並調用 Dart 的 callback 將 response 傳遞到 Dart 層。
Dart 層接收到二進制數據後,使用 MethodCodec 將數據解碼,並返回給業務層。至此,一次從 Flutter 發起的方法調用就完整結束了。
五、具體使用
1.Flutter 端調用 Android 方法
2.Android 端代碼
(1)繼承 MethodCallHandler 並設置 Handler ,MethodChannel 需要保存在對象一會調用回調時需要使用,onMethodCall 爲 Flutter 層回調的方法這邊用 RCIMFlutterWrapper 承接處理。
(2)RCIMFlutterWrapper 類中處理, MethodCall 的 Method,對應 Flutter 層調用 invokeMethod 方法的傳入的第一個參數,兩端需完全對應一致。
(3)直接通過 result 對象回調回去,這樣就能將結果回調。
3.關於 Android 回調 Flutter 的使用
(1)Flutter 端回調監聽,設置監聽 Key 兩端對應。
(2)Android 端代碼回調,mChannel.invokeMethod 方法將數據回調給 Flutter 層。