flutter 中的 WidgetsFlutterBinding 集成了 GestureBinding、ServicesBinding、SchedulerBinding、PaintingBinding、SemanticsBinding、RendererBinding、WidgetsBinding 等 7 種 Binding,它們都有本身在功能上的劃分,其中,ServicesBinding 主要負責的是 flutter 與 native 之間傳遞信息相關。java
在 ServicesBinding 的 initInstances 函數中主要有兩個操做,將 window.onPlatformMessage 與 defaultBinaryMessenger.handlePlatformMessage 關聯起來,再讀取 license 相關的信息,從使用上來講,license 主要是爲了支撐 about 頁面的展現,除此以外好像沒有其餘的用處。android
而 defaultBinaryMessenger 就是 flutter 與 native 之間進行消息傳遞的關鍵,它負責在兩者之間提供接收、發送數據的接口。首先,從接口上看,它有提供 send、setMessageHandler 這兩個函數,分別用於發送數據、處理數據,flutter 上層的 BasicMessageChannel、MethodChannel、EventChannel 等都是基於它實現的。從 flutter 層來看,它的消息傳遞機制包括三層:ios
如下分層瞭解:c++
這部分以 BinaryMessenger 爲主體,看一下它的各個函數是如何實現的,實現主要分爲兩部分:發送消息和接收消息。發送消息包括兩部分,首先,flutter 將一個數據經過 engine 層傳遞到 native 層,native 處理完了以後會有一個結果返回的過程,表現出來就是回調,這也正是 BinaryMessenger 的 send 函數返回結果是一個 Future 類型的緣由。而把上面這個過程反過來,改成 native 向 flutter 發送消息,flutter 迴應,那麼迴應的這部分就對應着接收消息的實現,處理結果經過 callback 回調給 native 。因此 flutter 中的發送、接收消息能夠看做是一個常規消息傳遞的一半,再結合 native 的發送、接收消息,就構成了兩個發送、接收的流程。markdown
發送過程從 send 開始,返回值是 Future,在 _sendPlatformMessage 中使用 Completer 將 Future 轉成了回調函數:app
Future<ByteData> _sendPlatformMessage(String channel, ByteData message) { final Completer<ByteData> completer = Completer<ByteData>(); // ui.window is accessed directly instead of using ServicesBinding.instance.window // because this method might be invoked before any binding is initialized. // This issue was reported in #27541. It is not ideal to statically access // ui.window because the Window may be dependency injected elsewhere with // a different instance. However, static access at this location seems to be // the least bad option. ui.window.sendPlatformMessage(channel, message, (ByteData reply) { try { completer.complete(reply); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('during a platform message response callback'), )); } }); return completer.future; } 複製代碼
再調用 ui.window.sendPlatformMessage 準備進入 engine 層,與之對應的函數爲 SendPlatformMessage:async
Dart_Handle SendPlatformMessage(Dart_Handle window, const std::string& name, Dart_Handle callback, Dart_Handle data_handle) { UIDartState* dart_state = UIDartState::Current(); if (!dart_state->window()) { return tonic::ToDart( "Platform messages can only be sent from the main isolate"); } fml::RefPtr<PlatformMessageResponse> response; if (!Dart_IsNull(callback)) { response = fml::MakeRefCounted<PlatformMessageResponseDart>( tonic::DartPersistentValue(dart_state, callback), dart_state->GetTaskRunners().GetUITaskRunner()); } if (Dart_IsNull(data_handle)) { dart_state->window()->client()->HandlePlatformMessage( fml::MakeRefCounted<PlatformMessage>(name, response)); } else { tonic::DartByteData data(data_handle); const uint8_t* buffer = static_cast<const uint8_t*>(data.data()); dart_state->window()->client()->HandlePlatformMessage( fml::MakeRefCounted<PlatformMessage>( name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()), response)); } return Dart_Null(); } 複製代碼
在這裏先是將 callback 封裝成了 PlatformMessageResponseDart,方便以後的回調,而後再將 name 和 PlatformMessageResponseDart 一塊兒封裝成 PlatformMessage,做爲單個消息發送。後經過 RuntimeController 轉遞給 Engine,在這裏,Engine 對 asset 請求消息進行了攔截,HandleAssetPlatformMessage 對其負責。asset 請求通常用於 flutter 中獲取 asset 文件夾的資源,這個由 engine 層直接處理,不須要經過 native 層。ide
其餘的消息會再轉遞給 Shell,Shell 中又對 skia 消息進行攔截,能夠設置 skia 的參數,目前只支持設置 SetResourceCacheMaxBytes,能夠調用 flutter 中的 SystemChannels.skia 設置。函數
再剩下的消息就是須要 native 層處理的了,以 android 爲例,ui
void PlatformViewAndroid::HandlePlatformMessage( fml::RefPtr<flutter::PlatformMessage> message) { JNIEnv* env = fml::jni::AttachCurrentThread(); fml::jni::ScopedJavaLocalRef<jobject> view = java_object_.get(env); if (view.is_null()) return; int response_id = 0; if (auto response = message->response()) { response_id = next_response_id_++; pending_responses_[response_id] = response; } auto java_channel = fml::jni::StringToJavaString(env, message->channel()); if (message->hasData()) { fml::jni::ScopedJavaLocalRef<jbyteArray> message_array( env, env->NewByteArray(message->data().size())); env->SetByteArrayRegion( message_array.obj(), 0, message->data().size(), reinterpret_cast<const jbyte*>(message->data().data())); message = nullptr; // This call can re-enter in InvokePlatformMessageXxxResponseCallback. FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(), message_array.obj(), response_id); } else { message = nullptr; // This call can re-enter in InvokePlatformMessageXxxResponseCallback. FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(), nullptr, response_id); } } 複製代碼
這裏會將 PlatformMessage 拆解,將 PlatformMessageResponseDart 保存在 pending_responses_ 中,將它的 id 傳遞到 native 中,供結果回調時使用,最後由 FlutterViewHandlePlatformMessage 經過 jni 調用 android 中的方法,對應 FlutterJNI#handlePlatformMessage。
public void handleMessageFromDart( @NonNull final String channel, @Nullable byte[] message, final int replyId) { Log.v(TAG, "Received message from Dart over channel '" + channel + "'"); BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel); if (handler != null) { try { Log.v(TAG, "Deferring to registered handler to process message."); final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message)); handler.onMessage(buffer, new Reply(flutterJNI, replyId)); } catch (Exception ex) { Log.e(TAG, "Uncaught exception in binary message listener", ex); flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } } else { Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message."); flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } } 複製代碼
android 中也有一個相似於 defaultBinaryMessenger 的對象 platformMessageHandler,handleMessageFromDart 方法接收消息,並在其中從 messageHandlers 中取出對應 channel 的 handler(經過 setMessageHandler 設置),調用其 onMessage 方法進行處理,replyId 也就是以前生成的 responseId,它被封裝成了 Reply。handler 是 BinaryMessageHandler 對象,在 android 中也有三種 Channel,BasicMessageChannel、MethodChannel 和 EventChannel(具體不一樣類的處理過程,能夠參照下面 flutter 中的介紹),其功用與 flutter 中對應類一致。
處理完以後則是調用 Reply 的 reply 方法,將結果回傳給 flutter 。
public void reply(@Nullable ByteBuffer reply) { if (done.getAndSet(true)) { throw new IllegalStateException("Reply already submitted"); } if (reply == null) { flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } else { flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position()); } } 複製代碼
最上面是一個檢驗,一次來自 flutter 的消息,只能回傳一個數據。而後根據結果是否爲空選擇調用 invokePlatformMessageEmptyResponseCallback 仍是 invokePlatformMessageResponseCallback,兩者只是參數的區別。
接着 invokePlatformMessageResponseCallback 會經過 jni 調用 InvokePlatformMessageResponseCallback 函數,而後轉到 PlatformViewAndroid::InvokePlatformMessageResponseCallback,以前在 flutter 發送消息時轉成 responseId 的 PlatformMessageResponse 這裏會被找回來,調用其 Complete 函數進行回調。
void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) { if (callback_.is_empty()) return; FML_DCHECK(!is_complete_); is_complete_ = true; ui_task_runner_->PostTask(fml::MakeCopyable( [callback = std::move(callback_), data = std::move(data)]() mutable { std::shared_ptr<tonic::DartState> dart_state = callback.dart_state().lock(); if (!dart_state) return; tonic::DartState::Scope scope(dart_state); Dart_Handle byte_buffer = WrapByteData(std::move(data)); tonic::DartInvoke(callback.Release(), {byte_buffer}); })); } 複製代碼
主要就是經過 DartInvoke 調用 flutter 中的 callback 函數,將結果 byte_buffer 傳遞回去,這個 callback,就是 _sendPlatformMessage 中聲明的函數,complete 函數的入參。由此,Future 即可以獲得結果,BinaryMessenger.send 函數返回的 Future 即可以獲得結果,一次完整的消息發送過程結束。
接收流程本質上就是發送流程的逆過程,可是細節上會有不一樣,接收流程由 native 中的 send 函數開始,以 android 爲例,就是 DartMessenger#send 方法。
在 android 中的 send 方法中,callback 就被轉換成了 resposeId,callback 被保存在 pendingReplies 中,而後調用 flutterJNI.dispatchPlatformMessage,經過 jni 調用 DispatchPlatformMessage 函數,後面就是通過 jni 函數再調用 PlatformViewAndroid::DispatchPlatformMessage,在這個函數中,它也是對 callback 進行了進一步的封裝成了 PlatformMessageResponseAndroid,可是這裏的 callback 是在 android 中轉換以後的 responseId。同時把 name 和 PlatformMessageResponseAndroid 一塊兒封裝成 PlatformMessage,這個與前面從 flutter 中發送消息的過程是相似的。
完了以後再通過 PlatformView、Shell 傳遞到達 engine 中,
void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) { if (message->channel() == kLifecycleChannel) { if (HandleLifecyclePlatformMessage(message.get())) return; } else if (message->channel() == kLocalizationChannel) { if (HandleLocalizationPlatformMessage(message.get())) return; } else if (message->channel() == kSettingsChannel) { HandleSettingsPlatformMessage(message.get()); return; } if (runtime_controller_->IsRootIsolateRunning() && runtime_controller_->DispatchPlatformMessage(std::move(message))) { return; } // If there's no runtime_, we may still need to set the initial route. if (message->channel() == kNavigationChannel) { HandleNavigationPlatformMessage(std::move(message)); return; } FML_DLOG(WARNING) << "Dropping platform message on channel: " << message->channel(); } 複製代碼
在這裏 engine 會嘗試攔截部分的消息,好比使用 HandleLifecyclePlatformMessage 先處理一下生命週期相關的消息,根據它的返回值決定是否會攔截,不過從函數的目前實現來看,是不會攔截的,這裏的更多的意義應該在於這些消息在 engine 和 flutter 中都有被使用到,好比生命週期事件,會影響到 engine 中 activity_running_ 和 flutter 中 _framesEnabled 的值,從功用上看,兩者實際上是一致的,只不過位於不一樣層,而且兩者之間貌似目前只能經過這裏來統一狀態。
後面還會攔截 localization 和 setting 消息,而後纔是調用 DispatchPlatformMessage 繼續向 flutter 層傳遞消息,若是當前還處於初始化階段,runtime_ 未初始化完成時,會直接由 engine 處理 navigation 事件(目前只接收 setInitialRoute),將 initialRoute 保存起來,這個值會在 flutter 啓動時做爲初始的 route 來建立對應的 Widget 。
正常的傳遞,還要通過 RuntimeController 到 window,在 window 中再將 PlatformMessageResponseAndroid 存到 pending_responses_ 中,提供 responseId,再拆解 PlatformMessage,經過 DartInvokeField 調用 dart 中的 _dispatchPlatformMessage 進入到 flutter 裏。
void _dispatchPlatformMessage(String name, ByteData data, int responseId) { if (window.onPlatformMessage != null) { _invoke3<String, ByteData, PlatformMessageResponseCallback>( window.onPlatformMessage, window._onPlatformMessageZone, name, data, (ByteData responseData) { window._respondToPlatformMessage(responseId, responseData); }, ); } else { window._respondToPlatformMessage(responseId, null); } } 複製代碼
如上,這裏聲明瞭一個 callback 函數,做爲入參調用 window.onPlatformMessage,也就是在 ServicesBinding 中給出的 defaultBinaryMessenger.handlePlatformMessage。
Future<void> handlePlatformMessage( String channel, ByteData data, ui.PlatformMessageResponseCallback callback, ) async { ByteData response; try { final MessageHandler handler = _handlers[channel]; if (handler != null) response = await handler(data); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('during a platform message callback'), )); } finally { callback(response); } } 複製代碼
接收到消息以後,BinaryMessager 須要選擇合適的 MessageHandler 處理消息,MessageHandler 則是經過 setMessageHandler 進行註冊的,有三種不一樣的 MessageHandler,分別對應着 BasicMessageChannel、MethodChannel 和 EventChannel ,就是是下面分類傳輸的內容,總之,通過 MessageHandler 處理以後會獲得 ByteData 類型的處理結果,最終由 callback 將結果回傳給 native 。
callback 中調用的就是 window._respondToPlatformMessage,對應 engine 中的函數 RespondToPlatformMessage。這裏會根據 response 是否爲空決定調用 CompletePlatformMessageEmptyResponse 仍是 CompletePlatformMessageResponse。
在 CompletePlatformMessageResponse 中,會根據 responseId 再找回 PlatformMessageResponseAndroid,調用其 Complete 將數據傳遞給 android。
void PlatformMessageResponseAndroid::Complete( std::unique_ptr<fml::Mapping> data) { platform_task_runner_->PostTask( fml::MakeCopyable([response = response_id_, // weak_java_object = weak_java_object_, // data = std::move(data) // ]() { // We are on the platform thread. Attempt to get the strong reference to // the Java object. auto* env = fml::jni::AttachCurrentThread(); auto java_object = weak_java_object.get(env); if (java_object.is_null()) { // The Java object was collected before this message response got to // it. Drop the response on the floor. return; } // Convert the vector to a Java byte array. fml::jni::ScopedJavaLocalRef<jbyteArray> data_array( env, env->NewByteArray(data->GetSize())); env->SetByteArrayRegion( data_array.obj(), 0, data->GetSize(), reinterpret_cast<const jbyte*>(data->GetMapping())); // Make the response call into Java. FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), response, data_array.obj()); })); } 複製代碼
這裏的 FlutterViewHandlePlatformMessageResponse 就是 jni 的函數,由 jni 將數據傳遞給 FlutterJNI 的 handlePlatformMessageResponse。
在 handlePlatformMessageResponse 的實現中,會根據 replyId 從 pendingReplies 中找到 callback,也就是 send 方法中傳進的,callback 是由上層實現的。
以上就是基礎傳輸過程當中,兩個方向的處理步驟,在這個流程中主要關注的是消息的傳遞,基本不關心消息的類型及處理(不過在 Engine、Shell 類中仍是有對消息的攔截處理)。
分類傳輸主要關心的就是數據的類型,在 flutter(包括 android 中也存在與之對應的)中存在三種類型的消息,就是 BasicMessageChannel、MethodChanel 和 EventChannel,每一 Channel 的構造都至少須要兩個參數,與之綁定的消息類型(消息的 name)和編碼方式(MessageCodec/MethodCodec)。
BasicMessageChannel 用於雙向的單次消息傳遞,包括髮送消息、接收消息兩個功能。發送消息使用的爲 send 函數,返回值是 Future,
Future<T> send(T message) async { return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message))); } 複製代碼
如上,BasicMessageChannel 主要的封裝就是在調用 binaryMessenger.send 先後對 message 進行編解碼,從這裏也能夠看出,send 函數的參數與返回值是同一種類型的(雖然可使用 dynamic 抹除 T 的做用)。
而 setMessageHandler 則是用於向 binaryMessenger 註冊一個消息處理函數,
void setMessageHandler(Future<T> handler(T message)) { if (handler == null) { binaryMessenger.setMessageHandler(name, null); } else { binaryMessenger.setMessageHandler(name, (ByteData message) async { return codec.encodeMessage(await handler(codec.decodeMessage(message))); }); } } 複製代碼
handler 是具體的處理邏輯,BasicMessageChannel 所作的也仍是在處理先後將 message 編解碼。
數據轉換流程
從以上能夠看出,一次 BasicMessageChannel 的 send 過程當中,message 的類型轉換有以下過程:
T(in flutter) -> ByteData(in flutter) -> DartByteData(in engine) -> buffer(in engine) -> vector<uint8_t>(in engine) -> byte[](in jni) -> ByteBuffer(in java) -> T(in java) -> process -> ByteBuffer(in java) -> vector<uint8_t>(in engine) -> DataMapping(in engine) -> ByteData(in engine) -> T(in flutter)
MethodCannel 用於雙向的方法調用,包括調用對端方法、響應對端調用,流程與 BasicMessageChannel 基本相似,只是數據轉換上略有不一樣,invokeMethod 用於調用對端方法,setMethodCallHandler 用於註冊一個方法的處理函數。
Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async { assert(method != null); final ByteData result = await binaryMessenger.send( name, codec.encodeMethodCall(MethodCall(method, arguments)), ); if (result == null) { throw MissingPluginException('No implementation found for method $method on channel $name'); } final T typedResult = codec.decodeEnvelope(result); return typedResult; } 複製代碼
invokeMethod 有兩個參數,方法名和方法入參,在 MethodCannel 中這兩個參數會被封裝成 MethodCall 對象,而後利用 MethodCodec 將 MethodCall 編碼成 ByteData 傳遞到 binaryMessenger,並獲得 ByteData 類型的返回值,後面再利用 MethodCodec 將其解碼成 T 類型數據,由此能夠看到,MethodCannel 的 invokeMethod 函數的入參與返回值是不一樣類型的,MethodCodec 相對於 MessageCode 多了兩個函數,分別用於編解碼 MethodCall 和編解碼方法調用的返回值。
而 setMethodCallHandler 用於註冊調用方法供 native 調用,
void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) { binaryMessenger.setMessageHandler( name, handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler), ); } Future<ByteData> _handleAsMethodCall(ByteData message, Future<dynamic> handler(MethodCall call)) async { final MethodCall call = codec.decodeMethodCall(message); try { return codec.encodeSuccessEnvelope(await handler(call)); } on PlatformException catch (e) { return codec.encodeErrorEnvelope( code: e.code, message: e.message, details: e.details, ); } on MissingPluginException { return null; } catch (e) { return codec.encodeErrorEnvelope(code: 'error', message: e.toString(), details: null); } } 複製代碼
它會將 handler 封裝到 callback 函數中,在 _handleAsMethodCall 中進行協調,也就是先把 message 轉成 MethodCall 對象以後,再交給 handler 處理,處理完的結果再由 codec 轉成 ByteData 並返回,接着 binaryMessenger 再拿着這個數據回傳到 native 中。
數據轉換流程
flutter 調用 native 函數:
(method, message) -> MethodCall(in flutter) -> ByteData(in flutter) -> ...(一系列基礎傳輸流程) -> ByteBuffer(in java) -> MethodCall(in java) -> process -> Object(in java) -> ByteBuffer(in java) -> ...(一系列基礎傳輸流程) -> ByteData(in flutter) -> T
navtive 調用 flutter 函數:
(method, message) -> MethodCall(in java) -> ByteBuffer(in java) -> ...(一系列基礎傳輸流程) -> ByteData(in flutter) -> MethodCall(in flutter) -> process -> dynamic(in flutter) -> ByteData(in flutter) -> ...(一系列基礎傳輸流程) -> byte[](in java) -> ByteBuffer(in java) -> Object(in java)
另外,MethodChannel 還有一個子類,OptionalMethodChannel,支持返回 null 結果,這在 MethodChannel 中是不容許的。
EventChannel 用於接收一系列消息,這些消息被包裝到 Stream 中,receiveBroadcastStream 返回一個 Stream 對象,能夠在 Stream 上添加監聽者,而後開始發送 listen 消息到 native 層後,native 中對應的 EventChannel 就開始處理消息,在處理的過程當中能夠發送多條消息,這些消息的在傳到 flutter 中後都會被加入到 Stream 中,而後通知全部的監聽者。
在 listen 開始以前,native 中的 EventChannel 沒法主動開始工做,當 flutter 中 Stream 的第一個監聽者成功添加時,纔會向 native 發送 listen 消息,此時,兩者之間創建鏈接,開始工做。
在 listen 的過程當中間,兩者並不能進行交流,native 層收到 listen 消息就開始不斷髮送消息,flutter 中也只能經過 Stream 不斷接收消息。
兩者均可以主動結束鏈接,在 native 中能夠調用 EventSink.endOfStream 結束鏈接,在 flutter 中移除 Stream 的全部監聽者也能夠結束鏈接。若是須要再次創建鏈接,就須要向 Stream 中添加監聽者。
由上述能夠得出,在 EventChannel 中,native 與 flutter 之間不平等,且兩者向對方發送消息時都不須要接收返回的結果,而是直接經過新的 send 途徑向對方發送消息,這是 EventChannel 與以上兩種方式最大的不一樣。
下面具體介紹 EventChannel 的工做原理,EventChannel 在初始化時須要提供 name 和 MethodCodec,而後調用 receiveBroadcastStream 返回一個 Stream 對象,後續上層主要是經過在 Stream 中添加監聽來完成對 native 層消息的接收,同時添加/刪除監聽的操做,能夠開始/結束接收消息。
Stream<dynamic> receiveBroadcastStream([ dynamic arguments ]) { final MethodChannel methodChannel = MethodChannel(name, codec); StreamController<dynamic> controller; controller = StreamController<dynamic>.broadcast(onListen: () async { defaultBinaryMessenger.setMessageHandler(name, (ByteData reply) async { if (reply == null) { controller.close(); } else { try { controller.add(codec.decodeEnvelope(reply)); } on PlatformException catch (e) { controller.addError(e); } } return null; }); try { await methodChannel.invokeMethod<void>('listen', arguments); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('while activating platform stream on channel $name'), )); } }, onCancel: () async { defaultBinaryMessenger.setMessageHandler(name, null); try { await methodChannel.invokeMethod<void>('cancel', arguments); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('while de-activating platform stream on channel $name'), )); } }); return controller.stream; } 複製代碼
EventChannel 的主要邏輯都在上面這個函數中了,調用以後會先生成一個 MethodChannel 用於向 native 發送消息,而後就是建立了一個 StreamController,在它的 onListen 函數中註冊了一個消息接收,在接收到消息以後會將其轉存到 StreamController 中,StreamController 負責將消息發送到它的監聽者們,註冊以後就是向 native 發送一個 listen 消息,開始接收。在 onCancel 函數中取消消息接收,同時發送一個 cancel 消息給 native ,讓 native 中的 EventChannel 作一些結尾工做等。
再看看 native (以 android 爲例)中 EventChannel 的工做原理,EventChannel 經過調用 setStreamHandler 方法,StreamHandler 由上層提供,負責具體的處理邏輯,它有 onListen 和 onCancel 兩個方法,前者提供了 arguments(參數)和 events(用於發送消息、報錯和結束鏈接),後者只提供了 argments 參數。
在 setStreamHandler 中,EventChannel 將 StreamHandler 封裝到 IncomingStreamRequestHandler 中,IncomingStreamRequestHandler 中的 onMessage 就是 native 接收到消息以後的回調方法,接收到 onListen 消息會調用 onListen 函數,在 onListen 中,除去一些維護正常狀態的代碼,就是調用 StreamHandler 的 listen 函數。native 中的 EventChannel 也能夠經過調用 EventSink.endOfStream 結束鏈接,它會向 flutter 中發送一個空消息,在 flutter 中接收到空消息時便會調用 StreamController.close 結束接收消息。
對於上層調用,flutter 中主要集中在 SystemChannels 中,好比 navigation、lifecycle 等。
navigation 是一個 MethodChannel,在 WidgetsBinding 中會給它設置監聽,調用 SystemChannels.navigation.setMethodCallHandler 傳遞進去 _handleNavigationInvocation 函數,
Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) { switch (methodCall.method) { case 'popRoute': return handlePopRoute(); case 'pushRoute': return handlePushRoute(methodCall.arguments); } return Future<dynamic>.value(); } 複製代碼
如上,這裏會根據 MethodCall 的方法名調用不一樣調用 pop/push 函數完成頁面切換。
lifcycle 是一個 BasicMessageChannel,在 SchedulerBinding 中設置監聽,傳進的 handler 爲 _handleLifecycleMessage,
Future<String> _handleLifecycleMessage(String message) async { handleAppLifecycleStateChanged(_parseAppLifecycleMessage(message)); return null; } void handleAppLifecycleStateChanged(AppLifecycleState state) { assert(state != null); _lifecycleState = state; switch (state) { case AppLifecycleState.resumed: case AppLifecycleState.inactive: _setFramesEnabledState(true); break; case AppLifecycleState.paused: case AppLifecycleState.suspending: _setFramesEnabledState(false); break; } } 複製代碼
如上,會根據 native 傳來的 activity 的狀態,決定是否容許更新界面。
以上就是 flutter 與 native 之間進行消息傳遞的過程、實現原理以及一些使用方法,經過消息傳遞機制,flutter 可以十分方便的調用 native 的能力,這一點的意義主要在於如下兩點: