Channel: flutter平台層與運行層的雙向通信


環境: flutter sdk v1.5.4-hotfix.1@stable
對應 flutter engine: 52c7a1e849a170be4b2b2fe34142ca2c0a6fea1f

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

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

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

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

發送有時機, 接收無定時

平台端(android)可以顯式的創建一個通道, 通道建立后既可作為發送端又可作為接收端, 作為發送端可以主動的傳送相關數據, 是為有時機, 作為接收端, 只能被動等待數據到來, 是為無定時

數據發送

調用一個通道的send方法,即為發送數據了, 有時發送完數據需要一個反饋, 於是有另一個回調參數Reply<T>, 這個回復是接收端反饋給發送端后發送端作的響應, 可以叫做發送回復.

數據接收

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

通道解碼

理解了通道本質, 通道的解碼MessageCodec就顯而易見了, 也就顯得不那么重要了: 在數據通信過程中針對各種各樣的數據對象進行序列化和反序列化. 我們自己也完全可以定制自己的序列方式(比如gson), 因為無論是c++層java層還是dart層, 只能讀寫字節.

可以總結如下:
通道的本質即數據通信
通道的解碼即對數據進行序列化和反序列化
通道可作為發送端也可作為接收端
通道最終是以二進制字節的形態傳送數據
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機制中最為重要的核心類, 是在平台層負責與運行層通信的最關鍵角色.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM