上一篇文章主要分析了dart調(diào)用原生代碼的實(shí)現(xiàn)原理,本文將重點(diǎn)講原生代碼是如何調(diào)用和回調(diào)dart的。
感性認(rèn)識(shí)
當(dāng)使用AndroidStudio調(diào)試模式調(diào)試dart代碼的時(shí)候,當(dāng)一個(gè)dart代碼被調(diào)用前,通常會(huì)有類(lèi)似的堆棧

dart層面,是通過(guò)setMethodCallHandler來(lái)實(shí)現(xiàn)監(jiān)聽(tīng)的,當(dāng)原生代碼發(fā)生調(diào)用,會(huì)觸發(fā)handler被執(zhí)行,然后進(jìn)入到Plugin的dart代碼進(jìn)入分發(fā)邏輯,dart代碼被執(zhí)行。
JPushPlugin.m
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
getRidResults = @[].mutableCopy;
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"jpush"
binaryMessenger:[registrar messenger]];
JPushPlugin* instance = [[JPushPlugin alloc] init];
instance.channel = channel;
[registrar addApplicationDelegate:instance];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)networkDidReceiveMessage:(NSNotification *)notification {
[_channel invokeMethod:@"onReceiveMessage" arguments: [notification userInfo]];
}
在原生層面,原生調(diào)用dart代碼都是通過(guò)FlutterMethodChannel的invokeMethod進(jìn)行的,由于invokeMethod并沒(méi)有以源碼的形式集成進(jìn)Flutter SDK,所以在原生代碼上,這里就已經(jīng)是調(diào)試的盡頭了。
原理分析
invokeMethod的實(shí)現(xiàn)在FlutterChannels.mm中
- (void)invokeMethod:(NSString*)method arguments:(id)arguments {
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:method
arguments:arguments];
NSData* message = [_codec encodeMethodCall:methodCall];
[_messenger sendOnChannel:_name message:message];
}
- (void)invokeMethod:(NSString*)method arguments:(id)arguments result:(FlutterResult)callback {
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:method
arguments:arguments];
NSData* message = [_codec encodeMethodCall:methodCall];
FlutterBinaryReply reply = ^(NSData* data) {
if (callback) {
callback((data == nil) ? FlutterMethodNotImplemented : [_codec decodeEnvelope:data]);
}
};
[_messenger sendOnChannel:_name message:message binaryReply:reply];
}
這里不管原生的方法是否需要reply,都會(huì)對(duì)調(diào)用的方法名和參數(shù)進(jìn)行一個(gè)封裝,封裝成FlutterMethodCall類(lèi)型的對(duì)象,再對(duì)methodCall對(duì)象進(jìn)行編碼,轉(zhuǎn)換成二進(jìn)制數(shù)據(jù)message,這里有必要說(shuō)一下這個(gè)_codec
FlutterChannels.mm
+ (instancetype)messageChannelWithName:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
NSObject<FlutterMessageCodec>* codec = [FlutterStandardMessageCodec sharedInstance];
return [FlutterBasicMessageChannel messageChannelWithName:name
binaryMessenger:messenger
codec:codec];
}
通常在初始化的時(shí)候,如果沒(méi)有傳codec就使用FlutterStandardMessageCodec作為默認(rèn)的codec,我們看原生代碼
JPushPlugin.m
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"jpush"
binaryMessenger:[registrar messenger]];
在創(chuàng)建channel的時(shí)候確實(shí)大部分也是不傳codec的,在FlutterStandardCodec.mm中encodeMethodCall方法是這樣定義的
- (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
NSMutableData* data = [NSMutableData dataWithCapacity:32];
FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
[writer writeValue:call.method];
[writer writeValue:call.arguments];
return data;
}
初始化data為4個(gè)字節(jié),然后將method和arguments寫(xiě)入, 這里不展開(kāi)講FlutterStandardWriter的工作機(jī)制, 只需知道,原生調(diào)用dart時(shí),會(huì)將方法名和參數(shù)轉(zhuǎn)換成二進(jìn)制數(shù)據(jù)。[_messenger sendOnChannel:_name message:message binaryReply:reply] 這里的_messenger是FlutterBinaryMessengerRelay,這里具體的分析可以參考上一篇文章
- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
if (self.parent) {
[self.parent sendOnChannel:channel message:message binaryReply:nil];
} else {
FML_LOG(WARNING) << "Communicating on a dead channel.";
}
}
- (void)sendOnChannel:(NSString*)channel
message:(NSData*)message
binaryReply:(FlutterBinaryReply)callback {
if (self.parent) {
[self.parent sendOnChannel:channel message:message binaryReply:callback];
} else {
FML_LOG(WARNING) << "Communicating on a dead channel.";
}
}
所以我們很容易就找到了sendOnChannel,還是上一篇文章的分析,得知parent就是FlutterEngine,也找到了實(shí)現(xiàn)的[代碼]:
- (void)sendOnChannel:(NSString*)channel
message:(NSData*)message
binaryReply:(FlutterBinaryReply)callback {
NSParameterAssert(channel);
NSAssert(_shell && _shell->IsSetup(),
@"Sending a message before the FlutterEngine has been run.");
fml::RefPtr<flutter::PlatformMessageResponseDarwin> response =
(callback == nil) ? nullptr
: fml::MakeRefCounted<flutter::PlatformMessageResponseDarwin>(
^(NSData* reply) {
callback(reply);
},
_shell->GetTaskRunners().GetPlatformTaskRunner());
fml::RefPtr<flutter::PlatformMessage> platformMessage =
(message == nil) ? fml::MakeRefCounted<flutter::PlatformMessage>(channel.UTF8String, response)
: fml::MakeRefCounted<flutter::PlatformMessage>(
channel.UTF8String, flutter::GetVectorFromNSData(message), response);
_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage);
}
如果reply存在就構(gòu)造一個(gè)PlatformMessageResponseDarwin類(lèi)型的response
platform_message_response_darwin.h
class PlatformMessageResponseDarwin : public flutter::PlatformMessageResponse {
public:
void Complete(std::unique_ptr<fml::Mapping> data) override;
void CompleteEmpty() override;
private:
explicit PlatformMessageResponseDarwin(PlatformMessageResponseCallback callback,
fml::RefPtr<fml::TaskRunner> platform_task_runner);
~PlatformMessageResponseDarwin() override;
fml::ScopedBlock<PlatformMessageResponseCallback> callback_;
fml::RefPtr<fml::TaskRunner> platform_task_runner_;
FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDarwin);
};
}
platform_message_response_darwin.mm
namespace flutter {
PlatformMessageResponseDarwin::PlatformMessageResponseDarwin(
PlatformMessageResponseCallback callback,
fml::RefPtr<fml::TaskRunner> platform_task_runner)
: callback_(callback, fml::OwnershipPolicy::Retain),
platform_task_runner_(std::move(platform_task_runner)) {}
PlatformMessageResponseDarwin::~PlatformMessageResponseDarwin() = default;
void PlatformMessageResponseDarwin::Complete(std::unique_ptr<fml::Mapping> data) {
fml::RefPtr<PlatformMessageResponseDarwin> self(this);
platform_task_runner_->PostTask(fml::MakeCopyable([self, data = std::move(data)]() mutable {
self->callback_.get()(GetNSDataFromMapping(std::move(data)));
}));
}
void PlatformMessageResponseDarwin::CompleteEmpty() {
fml::RefPtr<PlatformMessageResponseDarwin> self(this);
platform_task_runner_->PostTask(
fml::MakeCopyable([self]() mutable { self->callback_.get()(nil); }));
}
}
上面是設(shè)置方法的回調(diào),_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage)進(jìn)行消息的再次轉(zhuǎn)發(fā),這里用到了_shell,那究竟_shell是在哪里初始化的呢,在FlutterEngine中搜索發(fā)現(xiàn)是在- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI方法中,而這個(gè)方法的調(diào)用是在下面的代碼
@implementation FlutterViewController {
std::unique_ptr<fml::WeakPtrFactory<FlutterViewController>> _weakFactory;
fml::scoped_nsobject<FlutterEngine> _engine;
// We keep a separate reference to this and create it ahead of time because we want to be able to
// setup a shell along with its platform view before the view has to appear.
fml::scoped_nsobject<FlutterView> _flutterView;
fml::scoped_nsobject<UIView> _splashScreenView;
fml::ScopedBlock<void (^)(void)> _flutterViewRenderedCallback;
UIInterfaceOrientationMask _orientationPreferences;
UIStatusBarStyle _statusBarStyle;
flutter::ViewportMetrics _viewportMetrics;
BOOL _initialized;
BOOL _viewOpaque;
BOOL _engineNeedsLaunch;
NSMutableSet<NSNumber*>* _ongoingTouches;
// This scroll view is a workaround to accomodate iOS 13 and higher. There isn't a way to get
// touches on the status bar to trigger scrolling to the top of a scroll view. We place a
// UIScrollView with height zero and a content offset so we can get those events. See also:
// https://github.com/flutter/flutter/issues/35050
fml::scoped_nsobject<UIScrollView> _scrollView;
}
@synthesize displayingFlutterUI = _displayingFlutterUI;
#pragma mark - Manage and override all designated initializers
- (instancetype)initWithEngine:(FlutterEngine*)engine
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle {
NSAssert(engine != nil, @"Engine is required");
self = [super initWithNibName:nibName bundle:nibBundle];
if (self) {
_viewOpaque = YES;
if (engine.viewController) {
FML_LOG(ERROR) << "The supplied FlutterEngine " << [[engine description] UTF8String]
<< " is already used with FlutterViewController instance "
<< [[engine.viewController description] UTF8String]
<< ". One instance of the FlutterEngine can only be attached to one "
"FlutterViewController at a time. Set FlutterEngine.viewController "
"to nil before attaching it to another FlutterViewController.";
}
_engine.reset([engine retain]);
_engineNeedsLaunch = NO;
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
_ongoingTouches = [[NSMutableSet alloc] init];
[self performCommonViewControllerInitialization];
[engine setViewController:self];
}
return self;
}
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle {
self = [super initWithNibName:nibName bundle:nibBundle];
if (self) {
_viewOpaque = YES;
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
_engine.reset([[FlutterEngine alloc] initWithName:@"io.flutter"
project:project
allowHeadlessExecution:NO]);
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
[_engine.get() createShell:nil libraryURI:nil];
_engineNeedsLaunch = YES;
_ongoingTouches = [[NSMutableSet alloc] init];
[self loadDefaultSplashScreenView];
[self performCommonViewControllerInitialization];
}
return self;
}
- (instancetype)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil {
return [self initWithProject:nil nibName:nil bundle:nil];
}
- (instancetype)initWithCoder:(NSCoder*)aDecoder {
return [self initWithProject:nil nibName:nil bundle:nil];
}
- (instancetype)init {
return [self initWithProject:nil nibName:nil bundle:nil];
}
省略若干行
}
@end
創(chuàng)建FlutterApp后,我們會(huì)發(fā)現(xiàn)Main.storyboard類(lèi)型是FlutterViewController,這個(gè)類(lèi)在初始化的時(shí)候會(huì)執(zhí)行initWithNibName進(jìn)而執(zhí)行initWithProject
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle
這個(gè)初始化中會(huì)調(diào)用createShell,至于為什么這里調(diào)用的時(shí)候要用_engine.get()以及為什么這里的_engine要用fml::scoped_nsobject<FlutterEngine>先不糾結(jié)
從shell.h得知,返回的是PlatformView類(lèi)型的指針
fml::WeakPtr<PlatformView> GetPlatformView();
所以在PlatformView類(lèi)中可以找到DispatchPlatformMessage的實(shí)現(xiàn)
void PlatformView::DispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
delegate_.OnPlatformViewDispatchPlatformMessage(std::move(message));
}
根據(jù)delegate_的定義
PlatformView::Delegate& delegate_;
OnPlatformViewDispatchPlatformMessage的實(shí)現(xiàn)是在PlatformView::Delegate或其子類(lèi)中
class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler
Shell類(lèi)就是PlatformView::Delegate的子類(lèi)了,我們也找到了OnPlatformViewDispatchPlatformMessage的真實(shí)實(shí)現(xiàn)
void Shell::OnPlatformViewDispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), message = std::move(message)] {
if (engine) {
engine->DispatchPlatformMessage(std::move(message));
}
});
}
繞了一圈,原來(lái),_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage)就是調(diào)用Shell::OnPlatformViewDispatchPlatformMessage,這里task_runners_.GetUITaskRunner()->PostTask應(yīng)該是把一段代碼加到一個(gè)任務(wù)隊(duì)列里執(zhí)行,可能類(lèi)似dispatch_async的作用,PostTask真實(shí)的實(shí)現(xiàn)原理不再這里深入討論,這里先給出大膽的假設(shè)。engine_->GetWeakPtr()這里使用弱引用估計(jì)也是為了在block中不引起對(duì)engine的強(qiáng)引用吧。實(shí)際還是Engine類(lèi)的實(shí)例調(diào)用DispatchPlatformMessage。
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();
}
上面的一段代碼應(yīng)該是系統(tǒng)定義的一些channel,kLifecycleChannel,kLocalizationChannel,kSettingsChannel具體的定義后面再研究,下面的是有關(guān)runtime_controller_的調(diào)用,源碼詳情
bool RuntimeController::IsRootIsolateRunning() const {
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
if (root_isolate) {
return root_isolate->GetPhase() == DartIsolate::Phase::Running;
}
return false;
}
bool RuntimeController::DispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;
}
return false;
}
這代代碼有關(guān)DartIsolate的,是為了防止引擎沒(méi)有在運(yùn)行? 或者說(shuō)runtime沒(méi)工作?
接下來(lái)的HandleNavigationPlatformMessage應(yīng)該就是針對(duì)這種異常的處理,暫時(shí)不深入研究
bool RuntimeController::DispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;
}
return false;
}
至此調(diào)用window->DispatchPlatformMessage(std::move(message)),應(yīng)該可以說(shuō),我又回來(lái)了,上一篇文章離開(kāi)dart就是進(jìn)入了window.cc
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state) {
FML_DLOG(WARNING)
<< "Dropping platform message for lack of DartState on channel: "
<< message->channel();
return;
}
tonic::DartState::Scope scope(dart_state);
Dart_Handle data_handle =
(message->hasData()) ? ToByteData(message->data()) : Dart_Null();
if (Dart_IsError(data_handle)) {
FML_DLOG(WARNING)
<< "Dropping platform message because of a Dart error on channel: "
<< message->channel();
return;
}
int response_id = 0;
if (auto response = message->response()) {
response_id = next_response_id_++;
pending_responses_[response_id] = response;
}
tonic::LogIfError(
tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage",
{tonic::ToDart(message->channel()), data_handle,
tonic::ToDart(response_id)}));
}
這里將message->data()轉(zhuǎn)化成Dart_Handle,tonic::DartInvokeField進(jìn)入dart_invoke.cc
Dart_Handle DartInvokeField(Dart_Handle target,
const char* name,
std::initializer_list<Dart_Handle> args) {
Dart_Handle field = Dart_NewStringFromCString(name);
return Dart_Invoke(target, field, args.size(),
const_cast<Dart_Handle*>(args.begin()));
}
Dart_Handle DartInvoke(Dart_Handle closure,
std::initializer_list<Dart_Handle> args) {
int argc = args.size();
Dart_Handle* argv = const_cast<Dart_Handle*>(args.begin());
Dart_Handle handle = Dart_InvokeClosure(closure, argc, argv);
LogIfError(handle);
return handle;
}
這里Dart_InvokeClosure完成調(diào)用,這里為什么Dart_InvokeClosure就能完成C++代碼到dart代碼的調(diào)用,據(jù)說(shuō)是有dart_vm,但找了半天也沒(méi)找到dart_vm的源碼,只找到一些代碼片段
//sdk/runtime/include/dart_api.h
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
Dart_InvokeClosure(Dart_Handle closure,
int number_of_arguments,
Dart_Handle* arguments);
//dart/sdk/runtime/vm/dart_api_impl.cc
DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure,
int number_of_arguments,
Dart_Handle* arguments) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
CHECK_CALLBACK_STATE(T);
const Instance& closure_obj = Api::UnwrapInstanceHandle(Z, closure);
if (closure_obj.IsNull() || !closure_obj.IsCallable(NULL)) {
RETURN_TYPE_ERROR(Z, closure, Instance);
}
if (number_of_arguments < 0) {
return Api::NewError(
"%s expects argument 'number_of_arguments' to be non-negative.",
CURRENT_FUNC);
}
// Set up arguments to include the closure as the first argument.
const Array& args = Array::Handle(Z, Array::New(number_of_arguments + 1));
Object& obj = Object::Handle(Z);
args.SetAt(0, closure_obj);
for (int i = 0; i < number_of_arguments; i++) {
obj = Api::UnwrapHandle(arguments[i]);
if (!obj.IsNull() && !obj.IsInstance()) {
RETURN_TYPE_ERROR(Z, arguments[i], Instance);
}
args.SetAt(i + 1, obj);
}
// Now try to invoke the closure.
return Api::NewHandle(T, DartEntry::InvokeClosure(args));
}
最終就會(huì)調(diào)用到
hooks.dart
@pragma('vm:entry-point')
void _dispatchPlatformMessage(String name, ByteData data, int responseId) {
if (name == ChannelBuffers.kControlChannelName) {
try {
channelBuffers.handleMessage(data);
} catch (ex) {
_printDebug('Message to "$name" caused exception $ex');
} finally {
window._respondToPlatformMessage(responseId, null);
}
} else if (window.onPlatformMessage != null) {
_invoke3<String, ByteData, PlatformMessageResponseCallback>(
window.onPlatformMessage,
window._onPlatformMessageZone,
name,
data,
(ByteData responseData) {
window._respondToPlatformMessage(responseId, responseData);
},
);
} else {
channelBuffers.push(name, data, (ByteData responseData) {
window._respondToPlatformMessage(responseId, responseData);
});
}
}
這里會(huì)判斷方法名是否是kControlChannelName,如果是將進(jìn)行一些系統(tǒng)的處理,我們自定義的方法不會(huì)走到這里,來(lái)到下面的_invoke3這里已經(jīng)能夠和本文最上面給出的堆棧吻合上了,下面執(zhí)行_invoke3方法,這里是不能調(diào)試的, 所以只能從源碼上進(jìn)行分析,這里_invoke1 _invoke2 _invoke3是根據(jù)參數(shù)的不同來(lái)定義的,除了window.onPlatformMessage和window._onPlatformMessageZone后面的參數(shù)個(gè)數(shù)就是invoke的編號(hào),_invoke3接收3個(gè)參數(shù),方法名,方法的參數(shù)和回調(diào),原生代碼調(diào)用dart也是可以傳遞回調(diào)的。
void _invoke3<A1, A2, A3>(void callback(A1 a1, A2 a2, A3 a3), Zone zone, A1 arg1, A2 arg2, A3 arg3) {
if (callback == null)
return;
assert(zone != null);
if (identical(zone, Zone.current)) {
callback(arg1, arg2, arg3);
} else {
zone.runGuarded(() {
callback(arg1, arg2, arg3);
});
}
}
首先會(huì)對(duì)invoke的前兩個(gè)默認(rèn)參數(shù)進(jìn)行校驗(yàn),這里也會(huì)涉及到上一篇文章說(shuō)到的Zone,runGuarded就是增加了保護(hù),大神寫(xiě)代碼就是會(huì)比較飄逸
/**
* Executes the given [action] in this zone and catches synchronous
* errors.
*
* This function is equivalent to:
* ```
* try {
* this.run(action);
* } catch (e, s) {
* this.handleUncaughtError(e, s);
* }
* ```
*
* See [run].
*/
void runGuarded(void action());
然后執(zhí)行callback(arg1, arg2, arg3),window.onPlatformMessage實(shí)際是_DefaultBinaryMessenger的對(duì)象的handlePlatformMessage方法,是在WidgetsFlutterBinding.ensureInitialized()初始化綁定的時(shí)候進(jìn)行賦值的:
mixin ServicesBinding on BindingBase {
@override
void initInstances() {
super.initInstances();
_instance = this;
_defaultBinaryMessenger = createBinaryMessenger();
window
..onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
initLicenses();
SystemChannels.system.setMessageHandler(handleSystemMessage);
}
所以執(zhí)行callback(arg1, arg2, arg3)會(huì)調(diào)用handlePlatformMessage方法
@override
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);
} else {
ui.channelBuffers.push(channel, data, callback);
callback = null;
}
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message callback'),
));
} finally {
if (callback != null) {
callback(response);
}
}
}
這里會(huì)根據(jù)channel取出不同的handler,_handler是dart端setMessageHandler存儲(chǔ)到字典中的
class MethodChannelWebViewPlatform implements WebViewPlatformController {
/// Constructs an instance that will listen for webviews broadcasting to the
/// given [id], using the given [WebViewPlatformCallbacksHandler].
MethodChannelWebViewPlatform(int id, this._platformCallbacksHandler)
: assert(_platformCallbacksHandler != null),
_channel = MethodChannel('plugins.flutter.io/webview_$id') {
_channel.setMethodCallHandler(_onMethodCall);
}
組件在dart端初始化的時(shí)候如果設(shè)置了setMethodCallHandler,會(huì)調(diào)用_DefaultBinaryMessenger的setMessageHandler方法,這樣通過(guò)_handleAsMethodCall方法封裝的handler就被存儲(chǔ)在_DefaultBinaryMessenger中的_handlers里了,當(dāng)_handler執(zhí)行的時(shí)候會(huì)調(diào)用_handleAsMethodCall
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);
}
}
這里會(huì)將message轉(zhuǎn)化成MethodCall,執(zhí)行handler(call)就會(huì)回調(diào)_channel.setMethodCallHandler(_onMethodCall)里的_onMethodCall
Future<bool> _onMethodCall(MethodCall call) async {
switch (call.method) {
case 'javascriptChannelMessage':
final String channel = call.arguments['channel'];
final String message = call.arguments['message'];
_platformCallbacksHandler.onJavaScriptChannelMessage(channel, message);
return true;
case 'navigationRequest':
return await _platformCallbacksHandler.onNavigationRequest(
url: call.arguments['url'],
isForMainFrame: call.arguments['isForMainFrame'],
);
case 'onPageFinished':
_platformCallbacksHandler.onPageFinished(call.arguments['url']);
return null;
case 'onPageStarted':
_platformCallbacksHandler.onPageStarted(call.arguments['url']);
return null;
case 'onWebResourceError':
_platformCallbacksHandler.onWebResourceError(
WebResourceError(
errorCode: call.arguments['errorCode'],
description: call.arguments['description'],
domain: call.arguments['domain'],
errorType: call.arguments['errorType'] == null
? null
: WebResourceErrorType.values.firstWhere(
(WebResourceErrorType type) {
return type.toString() ==
'$WebResourceErrorType.${call.arguments['errorType']}';
},
),
),
);
return null;
}
throw MissingPluginException(
'${call.method} was invoked but has no handler',
);
}
這里就是dart層面的分發(fā)了,這樣就完成了原生代碼對(duì)dart代碼的調(diào)用。
總結(jié)
原生代碼調(diào)用Dart接口,經(jīng)歷了兩個(gè)階段:
- 原生層的轉(zhuǎn)發(fā),最終執(zhí)行
Dart_InvokeClosure - Dart VM實(shí)現(xiàn)了原生對(duì)Dart接口的調(diào)用,進(jìn)入
vm:entry-point的_dispatchPlatformMessage此后方法在Dart層進(jìn)行一層層傳遞,最終調(diào)用通過(guò)閉包的層層回溯完成了setMethodCallHandler的回調(diào)。
遺留問(wèn)題
-
FlutterStandardWriter的工作機(jī)制,這里也會(huì)結(jié)合上上一篇文章的WriteBuffer進(jìn)行講解,并深入研究codec的作用,了解通信過(guò)程中數(shù)據(jù)是如何傳遞的。 -
FlutterViewController中為什么使用engine_.get()以及_engine的類(lèi)型為什么是fml::scoped_nsobject<FlutterEngine> -
task_runners_.GetUITaskRunner()->PostTask的實(shí)現(xiàn)原理和作用。 - 系統(tǒng)定義的channel:
kLifecycleChannel,kLocalizationChannel,kSettingsChannel是做什么的,這里也會(huì)結(jié)合上一篇文章的kSkiaChannel進(jìn)行 -
DartIsolate的核心作用是什么? - Dart VM的工作原理是怎樣的?原生代碼為什么可以調(diào)用到Dart代碼,這里也將集合上一篇文章中Dart代碼調(diào)用原生代碼的原理進(jìn)行。
參考文獻(xiàn)
寫(xiě)在最后
Flutter現(xiàn)在還不能說(shuō)很穩(wěn)定,截止發(fā)稿,查閱了一些資料,也對(duì)比了一些源碼,發(fā)現(xiàn)有些引擎層的實(shí)現(xiàn)代碼已經(jīng)發(fā)生了改變,而且現(xiàn)階段也還有些設(shè)計(jì)不夠合理或者嚴(yán)謹(jǐn)?shù)牡胤接写倘?,未?lái)Flutter底層的研究以及性能的優(yōu)化還會(huì)持續(xù)一段時(shí)間。