上一篇文章主要分析了dart调用原生代码的实现原理,本文将重点讲原生代码是如何调用和回调dart的。
感性认识
当使用AndroidStudio调试模式调试dart代码的时候,当一个dart代码被调用前,通常会有类似的堆栈
dart层面,是通过setMethodCallHandler
来实现监听的,当原生代码发生调用,会触发handler
被执行,然后进入到Plugin的dart代码进入分发逻辑,dart代码被执行。
JPushPlugin.m
+ (void)registerWithRegistrar:(NSObject*)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]];
}
在原生层面,原生调用dart代码都是通过FlutterMethodChannel
的invokeMethod
进行的,由于invokeMethod
并没有以源码的形式集成进Flutter SDK,所以在原生代码上,这里就已经是调试的尽头了。
原理分析
invokeMethod
的实现在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
,都会对调用的方法名和参数进行一个封装,封装成FlutterMethodCall
类型的对象,再对methodCall
对象进行编码,转换成二进制数据message
,这里有必要说一下这个_codec
FlutterChannels.mm
+ (instancetype)messageChannelWithName:(NSString*)name
binaryMessenger:(NSObject*)messenger {
NSObject* codec = [FlutterStandardMessageCodec sharedInstance];
return [FlutterBasicMessageChannel messageChannelWithName:name
binaryMessenger:messenger
codec:codec];
}
通常在初始化的时候,如果没有传codec
就使用FlutterStandardMessageCodec
作为默认的codec
,我们看原生代码
JPushPlugin.m
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"jpush"
binaryMessenger:[registrar messenger]];
在创建channel的时候确实大部分也是不传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个字节,然后将method
和arguments
写入, 这里不展开讲FlutterStandardWriter
的工作机制, 只需知道,原生调用dart时,会将方法名和参数转换成二进制数据。[_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
,也找到了实现的[代码]:
- (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 response =
(callback == nil) ? nullptr
: fml::MakeRefCounted(
^(NSData* reply) {
callback(reply);
},
_shell->GetTaskRunners().GetPlatformTaskRunner());
fml::RefPtr platformMessage =
(message == nil) ? fml::MakeRefCounted(channel.UTF8String, response)
: fml::MakeRefCounted(
channel.UTF8String, flutter::GetVectorFromNSData(message), response);
_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage);
}
如果reply
存在就构造一个PlatformMessageResponseDarwin
类型的response
platform_message_response_darwin.h
class PlatformMessageResponseDarwin : public flutter::PlatformMessageResponse {
public:
void Complete(std::unique_ptr data) override;
void CompleteEmpty() override;
private:
explicit PlatformMessageResponseDarwin(PlatformMessageResponseCallback callback,
fml::RefPtr platform_task_runner);
~PlatformMessageResponseDarwin() override;
fml::ScopedBlock callback_;
fml::RefPtr platform_task_runner_;
FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDarwin);
};
}
platform_message_response_darwin.mm
namespace flutter {
PlatformMessageResponseDarwin::PlatformMessageResponseDarwin(
PlatformMessageResponseCallback callback,
fml::RefPtr 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 data) {
fml::RefPtr 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 self(this);
platform_task_runner_->PostTask(
fml::MakeCopyable([self]() mutable { self->callback_.get()(nil); }));
}
}
上面是设置方法的回调,_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage)
进行消息的再次转发,这里用到了_shell
,那究竟_shell
是在哪里初始化的呢,在FlutterEngine
中搜索发现是在- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI
方法中,而这个方法的调用是在下面的代码
@implementation FlutterViewController {
std::unique_ptr> _weakFactory;
fml::scoped_nsobject _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;
fml::scoped_nsobject _splashScreenView;
fml::ScopedBlock _flutterViewRenderedCallback;
UIInterfaceOrientationMask _orientationPreferences;
UIStatusBarStyle _statusBarStyle;
flutter::ViewportMetrics _viewportMetrics;
BOOL _initialized;
BOOL _viewOpaque;
BOOL _engineNeedsLaunch;
NSMutableSet* _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 _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>(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>(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
创建FlutterApp后,我们会发现Main.storyboard类型是FlutterViewController
,这个类在初始化的时候会执行initWithNibName
进而执行initWithProject
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle
这个初始化中会调用createShell
,至于为什么这里调用的时候要用_engine.get()
以及为什么这里的_engine
要用fml::scoped_nsobject
先不纠结
从shell.h得知,返回的是PlatformView
类型的指针
fml::WeakPtr GetPlatformView();
所以在PlatformView类中可以找到DispatchPlatformMessage
的实现
void PlatformView::DispatchPlatformMessage(
fml::RefPtr message) {
delegate_.OnPlatformViewDispatchPlatformMessage(std::move(message));
}
根据delegate_
的定义
PlatformView::Delegate& delegate_;
OnPlatformViewDispatchPlatformMessage
的实现是在PlatformView::Delegate
或其子类中
class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler
Shell
类就是PlatformView::Delegate
的子类了,我们也找到了OnPlatformViewDispatchPlatformMessage
的真实实现
void Shell::OnPlatformViewDispatchPlatformMessage(
fml::RefPtr 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)
就是调用Shell::OnPlatformViewDispatchPlatformMessage
,这里task_runners_.GetUITaskRunner()->PostTask
应该是把一段代码加到一个任务队列里执行,可能类似dispatch_async的作用,PostTask
真实的实现原理不再这里深入讨论,这里先给出大胆的假设。engine_->GetWeakPtr()
这里使用弱引用估计也是为了在block中不引起对engine的强引用吧。实际还是Engine
类的实例调用DispatchPlatformMessage
。
engine.cc
void Engine::DispatchPlatformMessage(fml::RefPtr 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();
}
上面的一段代码应该是系统定义的一些channel,kLifecycleChannel
,kLocalizationChannel
,kSettingsChannel
具体的定义后面再研究,下面的是有关runtime_controller_
的调用,源码详情
bool RuntimeController::IsRootIsolateRunning() const {
std::shared_ptr root_isolate = root_isolate_.lock();
if (root_isolate) {
return root_isolate->GetPhase() == DartIsolate::Phase::Running;
}
return false;
}
bool RuntimeController::DispatchPlatformMessage(
fml::RefPtr message) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;
}
return false;
}
这代代码有关DartIsolate
的,是为了防止引擎没有在运行? 或者说runtime
没工作?
接下来的HandleNavigationPlatformMessage
应该就是针对这种异常的处理,暂时不深入研究
runtime_controller.cc
bool RuntimeController::DispatchPlatformMessage(
fml::RefPtr message) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;
}
return false;
}
至此调用window->DispatchPlatformMessage(std::move(message))
,应该可以说,我又回来了,上一篇文章离开dart就是进入了window.cc
void Window::DispatchPlatformMessage(fml::RefPtr message) {
std::shared_ptr 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()
转化成Dart_Handle
,tonic::DartInvokeField
进入dart_invoke.cc
Dart_Handle DartInvokeField(Dart_Handle target,
const char* name,
std::initializer_list args) {
Dart_Handle field = Dart_NewStringFromCString(name);
return Dart_Invoke(target, field, args.size(),
const_cast(args.begin()));
}
Dart_Handle DartInvoke(Dart_Handle closure,
std::initializer_list args) {
int argc = args.size();
Dart_Handle* argv = const_cast(args.begin());
Dart_Handle handle = Dart_InvokeClosure(closure, argc, argv);
LogIfError(handle);
return handle;
}
这里Dart_InvokeClosure
完成调用,这里为什么Dart_InvokeClosure
就能完成C++代码到dart代码的调用,据说是有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));
}
最终就会调用到
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(
window.onPlatformMessage,
window._onPlatformMessageZone,
name,
data,
(ByteData responseData) {
window._respondToPlatformMessage(responseId, responseData);
},
);
} else {
channelBuffers.push(name, data, (ByteData responseData) {
window._respondToPlatformMessage(responseId, responseData);
});
}
}
这里会判断方法名是否是kControlChannelName
,如果是将进行一些系统的处理,我们自定义的方法不会走到这里,来到下面的_invoke3
这里已经能够和本文最上面给出的堆栈吻合上了,下面执行_invoke3
方法,这里是不能调试的, 所以只能从源码上进行分析,这里_invoke1
_invoke2
_invoke3
是根据参数的不同来定义的,除了window.onPlatformMessage
和window._onPlatformMessageZone
后面的参数个数就是invoke的编号,_invoke3
接收3个参数,方法名,方法的参数和回调,原生代码调用dart也是可以传递回调的。
void _invoke3(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);
});
}
}
首先会对invoke的前两个默认参数进行校验,这里也会涉及到上一篇文章说到的Zone
,runGuarded
就是增加了保护,大神写代码就是会比较飘逸
/**
* 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());
然后执行callback(arg1, arg2, arg3)
,window.onPlatformMessage
实际是_DefaultBinaryMessenger
的对象的handlePlatformMessage
方法,是在WidgetsFlutterBinding.ensureInitialized()
初始化绑定的时候进行赋值的:
mixin ServicesBinding on BindingBase {
@override
void initInstances() {
super.initInstances();
_instance = this;
_defaultBinaryMessenger = createBinaryMessenger();
window
..onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
initLicenses();
SystemChannels.system.setMessageHandler(handleSystemMessage);
}
所以执行callback(arg1, arg2, arg3)
会调用handlePlatformMessage
方法
@override
Future 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);
}
}
}
这里会根据channel
取出不同的handler
,_handler
是dart
端setMessageHandler
存储到字典中的
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
端初始化的时候如果设置了setMethodCallHandler
,会调用_DefaultBinaryMessenger
的setMessageHandler
方法,这样通过_handleAsMethodCall
方法封装的handler
就被存储在_DefaultBinaryMessenger
中的_handlers
里了,当_handler
执行的时候会调用_handleAsMethodCall
void setMethodCallHandler(Future handler(MethodCall call)) {
binaryMessenger.setMessageHandler(
name,
handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
);
}
Future _handleAsMethodCall(ByteData message, Future 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);
}
}
这里会将message
转化成MethodCall
,执行handler(call)
就会回调_channel.setMethodCallHandler(_onMethodCall)
里的_onMethodCall
Future _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
层面的分发了,这样就完成了原生代码对dart代码的调用。
总结
原生代码调用Dart接口,经历了两个阶段:
- 原生层的转发,最终执行
Dart_InvokeClosure
- Dart VM实现了原生对Dart接口的调用,进入
vm:entry-point
的_dispatchPlatformMessage
此后方法在Dart层进行一层层传递,最终调用通过闭包的层层回溯完成了setMethodCallHandler
的回调。
遗留问题
-
FlutterStandardWriter
的工作机制,这里也会结合上上一篇文章的WriteBuffer
进行讲解,并深入研究codec的作用,了解通信过程中数据是如何传递的。 -
FlutterViewController
中为什么使用engine_.get()
以及_engine
的类型为什么是fml::scoped_nsobject
-
task_runners_.GetUITaskRunner()->PostTask
的实现原理和作用。 - 系统定义的channel:
kLifecycleChannel
,kLocalizationChannel
,kSettingsChannel
是做什么的,这里也会结合上一篇文章的kSkiaChannel
进行 -
DartIsolate
的核心作用是什么? - Dart VM的工作原理是怎样的?原生代码为什么可以调用到Dart代码,这里也将集合上一篇文章中Dart代码调用原生代码的原理进行。
参考文献
Dart和Java通信源码分析和实践
写在最后
Flutter现在还不能说很稳定,截止发稿,查阅了一些资料,也对比了一些源码,发现有些引擎层的实现代码已经发生了改变,而且现阶段也还有些设计不够合理或者严谨的地方有待商榷,未来Flutter底层的研究以及性能的优化还会持续一段时间。