上一篇文章主要分析了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ì)有類似的堆棧
dart層面域庇,是通過setMethodCallHandler
來實(shí)現(xiàn)監(jiān)聽的字币,當(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代碼都是通過FlutterMethodChannel
的invokeMethod
進(jìn)行的票渠,由于invokeMethod
并沒有以源碼的形式集成進(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
類型的對(duì)象杜窄,再對(duì)methodCall
對(duì)象進(jìn)行編碼,轉(zhuǎn)換成二進(jìn)制數(shù)據(jù)message
算途,這里有必要說一下這個(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í)候塞耕,如果沒有傳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
寫入莉钙, 這里不展開講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
類型的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類型是FlutterViewController
,這個(gè)類在初始化的時(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
類型的指針
fml::WeakPtr<PlatformView> GetPlatformView();
所以在PlatformView類中可以找到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
或其子類中
class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler
Shell
類就是PlatformView::Delegate
的子類了,我們也找到了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));
}
});
}
繞了一圈逊移,原來预吆,_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage)
就是調(diào)用Shell::OnPlatformViewDispatchPlatformMessage
,這里task_runners_.GetUITaskRunner()->PostTask
應(yīng)該是把一段代碼加到一個(gè)任務(wù)隊(duì)列里執(zhí)行胳泉,可能類似dispatch_async的作用拐叉,PostTask
真實(shí)的實(shí)現(xiàn)原理不再這里深入討論,這里先給出大膽的假設(shè)扇商。engine_->GetWeakPtr()
這里使用弱引用估計(jì)也是為了在block中不引起對(duì)engine的強(qiáng)引用吧凤瘦。實(shí)際還是Engine
類的實(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
的,是為了防止引擎沒有在運(yùn)行? 或者說runtime
沒工作姑子?
接下來的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)該可以說壁酬,我又回來了次酌,上一篇文章離開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ù)說是有dart_vm剂公,但找了半天也沒找到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ì)走到這里,來到下面的_invoke3
這里已經(jīng)能夠和本文最上面給出的堆棧吻合上了璃搜,下面執(zhí)行_invoke3
方法拖吼,這里是不能調(diào)試的, 所以只能從源碼上進(jìn)行分析这吻,這里_invoke1
_invoke2
_invoke3
是根據(jù)參數(shù)的不同來定義的吊档,除了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ì)涉及到上一篇文章說到的Zone
,runGuarded
就是增加了保護(hù)舟误,大神寫代碼就是會(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
方法堵腹,這樣通過_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)用通過閉包的層層回溯完成了setMethodCallHandler
的回調(diào)笆檀。
遺留問題
-
FlutterStandardWriter
的工作機(jī)制忌堂,這里也會(huì)結(jié)合上上一篇文章的WriteBuffer
進(jìn)行講解,并深入研究codec的作用酗洒,了解通信過程中數(shù)據(jù)是如何傳遞的士修。 -
FlutterViewController
中為什么使用engine_.get()
以及_engine
的類型為什么是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)
寫在最后
Flutter現(xiàn)在還不能說很穩(wěn)定雹锣,截止發(fā)稿网沾,查閱了一些資料,也對(duì)比了一些源碼蕊爵,發(fā)現(xiàn)有些引擎層的實(shí)現(xiàn)代碼已經(jīng)發(fā)生了改變辉哥,而且現(xiàn)階段也還有些設(shè)計(jì)不夠合理或者嚴(yán)謹(jǐn)?shù)牡胤接写倘叮磥鞦lutter底層的研究以及性能的優(yōu)化還會(huì)持續(xù)一段時(shí)間攒射。