Channel: flutter平臺層與運行層的雙向通訊

環境: flutter sdk v1.5.4-hotfix.1@stablejava

對應 flutter engine: 52c7a1e849a170be4b2b2fe34142ca2c0a6fea1fandroid

存在這樣的情形: flutter應用的視圖控件響應用戶的輸入(好比KeyEvent), 須要將平臺的按鍵數據傳遞到flutter的dart環境並響應, 同時應用可能由於某個操做須要調用平臺的接口讓手機震動. 可是flutter的App視圖運行dart代碼,平臺(Android)運行Java代碼, 同時dart層沒法識別java層定義的對象類, 這就須要將數據在不一樣的運行環境中傳遞, flutter框架中的channel機制其實就是實現這個目的的.ios

一些文章和部分代碼可能會讓人感到困擾, 爲何已經有send接口了還要添加一個setMessageHander接口, 同時send已經有回調reply了, 怎麼MessageHandler除了數據還有帶一個reply. c++

理解的關鍵其實就是這個channel, 顧名思義, 就是進行數據傳送的通道, 在平臺層(java)與運行層(dart)進行數據通訊. 一旦涉及通訊就涉及對象傳遞, 而在不一樣運行時(runtime)環境進行對象傳遞就必然涉及對象序列化了. 因此不用被名稱迷惑, 所謂的MessageCodec其實就是專門做對象序列化的實例, 而通道既然能發送數據也必須可以接收數據, 如此的雙向通訊, 僅此而已.git

一個通道關聯3個對象: 名稱, 操做與序列化, 操做即具體作收發消息的工做, 即Messenger. 而消息按類型又分爲普通對象, 操做方法, 數據流, 對應着3種基本通道: BasicMessageChannel<T>, MethodChannel, EventChannelgithub

發送有時機, 接收無定時

平臺端(android)能夠顯式的建立一個通道, 通道創建後既可做爲發送端又可做爲接收端, 做爲發送端能夠主動的傳送相關數據, 是爲有時機, 做爲接收端, 只能被動等待數據到來, 是爲無定時緩存

數據發送

調用一個通道的send方法,即爲發送數據了, 有時發送完數據須要一個反饋, 因而有另外一個回調參數Reply<T>, 這個回覆是接收端反饋給發送端後發送端做的響應, 能夠叫作發送回覆.框架

數據接收

每種通道都設置了一個setMessageHandler的方法, MessageHandler<T>其實就是通道的數據接收器, 更容易理解的名字應該是MessageReceiver, 專門等待發送端發送的數據; 表示通道創建後做爲接收方接收數據後進行的處理, 數據處理完以後可能須要再反饋給發送端, 因此MessageHandler<T>.onMessage(T message, Reply<T> reply)中的Reply<T>是接收端反饋給發送端的回覆, 能夠叫作接收回復spa

通道解碼

理解了通道本質, 通道的解碼MessageCodec就顯而易見了, 也就顯得不那麼重要了: 在數據通訊過程當中針對各類各樣的數據對象進行序列化和反序列化. 咱們本身也徹底能夠定製本身的序列方式(好比gson), 由於不管是c++層java層仍是dart層, 只能讀寫字節.code

能夠總結以下:
通道的本質即數據通訊
通道的解碼即對數據進行序列化和反序列化
通道可做爲發送端也可做爲接收端
通道最終是以二進制字節的形態傳送數據
c++消彌平臺的差別(android,ios), 同時提供統一的接口和方式供dart使用

數據發送示例

普通對象傳遞-以Android端傳遞按鍵事件至dart端爲例
按鍵數據被包裝成一個對象實例,通道對象類型是BinaryMessenger<Object>調用序列以下:

FlutterView.onKeyDown
  AndroidKeyProcessor.onKeyDown
    KeyEventChannel.keyDown
     BasicMessageChannel.send
       BinaryMessenger.send -> DartExecutor.send
         DartMessenger.send
           FlutterJNI.dispatchPlatformMessage

最終調用了BinaryMessenger的send方法, 其實現體是DartExecutor, DartExecutor是平臺層與運行層交互的點, 它實現了平臺向dart調用, dart向平臺的響應.

調用dart方法-以Android端傳遞導航事件至dart端爲例
activity響應打開頁面的方法onNewIntent被flutter定義了一個導航方法,通道對象類型是MethodChannel, 調用序列以下:

FlutterActivityDelegate.onNewIntent
  FlutterActivityDelegate.loadIntent
    FlutterView.setInitialRoute
      NavigationChannel.setInitialRoute
        MethodChannel.invokeMethod
          new MethodCall
          JSONMethodCodec.encodeMethodCall
          BinaryMessenger.send -> DartExecutor.send
            DartMessenger.send
              FlutterJNI.dispatchPlatformMessage

能夠看到方法的名稱與參數被包裝成了MethodCall, 結構體被序列化成了字節以後傳遞給dart, 最終仍是調用了DartMessenger的send方法

此外還有EventChannel,可是在代碼中沒有實例化(2019.06.24 flutter-engine:52c7a1e8)就先不分析了,本質與原理仍是同樣的。

響應發送回覆

能夠看到DartMessengerpendingReplies:Map<>緩存了BinaryMessenger.BinaryReply, 待dart代碼執行完發送端操做後響應handlePlatformMessageResponse時取出, 完成發送反饋, 在MethodChannel中即爲方法返回值.

數據接收示例

接收dart層通知
目前代碼中只有AccessibilityChannel有用到BasicMessageChannel.MessageHandler, 這是爲了設置android視圖ViewAccessibility屬性, 日常開發不怎麼用到, 但毫無疑問,最終調用的仍是平臺層的相關代碼

接收dart層調用-以Android端調用平臺類PlatformChannel爲例
PlatformChannel負責dart層向平臺層調用的統一操做, 其建立過程以下

FlutterView.FltterView()
  new PlatformChannel
    new MethodChannel
    MethodChannel.setMethodCallHandler
      BinaryMessenger.setMessageHandler -> DartExecutor.setMessageHandler
        DartMessenger.setMessageHandler
  new PlatformPlugin
    PlatformChannel.setPlatformMessageHandler

DartMessengermessageHandlers根據通道名稱緩存了BinaryMessenger.BinaryMessageHandler, 平臺層做爲接收方不定時等待dart層發送數據, 方法調用流程以下:

DartMessenger.handleMessageFromDart
  BinaryMessenger.BinaryMessageHandler.onMessage -> MethodChannel.IncomingMethodCallHandler.onMessage
    MethodCallHandler.onMethodCall -> PlatformChannel.parsingMethodCallHandler.onMethodCall
      PlatformMessageHandler.vibrateHapticFeedback -> PlatformPlugin.mPlatformMessageHandler.vibrateHapticFeedback
        PlatformPlugin.vibrateHapticFeedback
          View.performHapticFeedback

由上可見DartMessenger是channel機制中最爲重要的核心類, 是在平臺層負責與運行層通訊的最關鍵角色.

相關文章
相關標籤/搜索