本文已授权「玉刚说」微信公众号独家发布
Flutter使用了一个灵活的系统,允许开发者调用特定平台的API,无论在Android上的Java或Kotlin代码中,还是iOS上的ObjectiveC或Swift代码中均可用。
Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:
- 应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)。
- 宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言) - 并将响应发送回客户端,即应用程序的Flutter部分。
以Android平台上通过Flutter获取手机电池电量为栗子,栗子参考自看Flutter中文网下调用代码怎么写。
1.获取电池电量
首先看下Flutter层的代码,需要给Channel取一个整个应用中唯一的名称,比如samples.flutter.io/battery
。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class _MyHomePageState extends State<MyHomePage> {
static const platform = const MethodChannel('samples.flutter.io/battery');
String _batteryLevel = 'Unknown battery level.';
// Get battery level.
}
接下来调用通道上的方法,通过字符串标识调用的方法,比如getBatteryLevel
,调用也可能失败,可以通过try-catch包装。
返回的结果通过
setState
更新用户界面状态,_batteryLevel
,其中await
会返回Future,在得到Android
平台返回的电量结果后才会赋值给result,然后代码接着往下走赋值给batteryLevel
,然后更新状态.
Future<Null> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
最后,在build创建一个按钮用于刷新值,一个Text用于显示电量值。
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel),
],
),
),
);
}
上面就是Flutter
层的代码,接下来以Android
平台为例看下平台层怎么实现。在MainActivity
中需要定义一个和Flutter
层相同的通道名称,通过Result
返回结果给Flutter
:
private static final String CHANNEL = "samples.flutter.io/battery";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler((call, result) -> {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
});
GeneratedPluginRegistrant.registerWith(this);
}
接下来添加Java代码,使用Android
电池API获取电池电量:
private int getBatteryLevel() {
int batterylevel = -1;
if (VERSION.SDK_INT > VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batterylevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batterylevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batterylevel;
}
看下效果图:
接下来看下Flutter
和Native
通信的原理,主要是上面Flutter
主动发送的原理。
2.Flutter
层原理
先看下官方放出来的一场通信图:
2.1 MethodChannel
入口就是MethodChannel
,首先看下这个代码:
### platform_channel.dart
class MethodChannel {
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
/// The logical channel on which communication happens, not null.
final String name;
/// The message codec used by this channel, not null.
final MethodCodec codec;
@optionalTypeArgs
Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
assert(method != null);
final ByteData result = await BinaryMessages.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;
}
构造函数需要一个name和可选的MethodCodec
,name
就是MethodChannel
的标识,MethodCodec
是编解码器,决定了我们能传递什么类型的数据。看下官网提供的数据
MethodCodec
是可选的,不传默认是StandardMethodCodec
,这个在发起方法调用invokeMethod
的时候会用到。StandardMethodCodec
会将方法名称和参数序列化成二进制,收到平台返回的结果也是二进制数据,然后反序列化成Dart
数据类型。
2.2 invokeMethod
另外invokeMethod
是异步方法,返回Future<dynamic>
类型,在接受这个方法的返回值的时候,就必须要使用 await进行修饰。要调用使用 await,必须在有 async标记的函数中运行。
接着发送消息BinaryMessages.send
2.3 BinaryMessages.send
### platform_messages.dart
static Future<ByteData> send(String channel, ByteData message) {
final _MessageHandler handler = _mockHandlers[channel];
if (handler != null)
return handler(message);
return _sendPlatformMessage(channel, message);
}
send就是用来发送二进制消息给平台插件对应的通道。
其中_mockHandlers
是用来调试用的,看下数据结构,如果设置了调试用的Handler
就会直接返回,不会和平台通信。
### platform_messages.dart
// Mock handlers that intercept and respond to outgoing messages.
static final Map<String, _MessageHandler> _mockHandlers =
<String, _MessageHandler>{};
static void setMockMessageHandler(String channel, Future<ByteData> handler(ByteData message)) {
if (handler == null)
_mockHandlers.remove(channel);
else
_mockHandlers[channel] = handler;
}
接下来看下send
中调用到_sendPlatformMessage
2.4 _sendPlatformMessage
### platform_messages.dart
static 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: 'during a platform message response callback',
));
}
});
return completer.future;
}
上面的Completer
是一个用于可以控制Future
的对象,因为正常的Future
其实创建后就执行了或者放到队列中去等待执行了,用户只能被动接收到Future
的回调。Completer
就可以通过completer.complete
去执行完成Future
或者completer.error
报错。
会调用到window
下的sendPlatformMessage
2.5 sendPlatformMessage
void sendPlatformMessage(String name,
ByteData data,
PlatformMessageResponseCallback callback) {
final String error =
_sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
if (error != null)
throw new Exception(error);
}
String _sendPlatformMessage(String name,
PlatformMessageResponseCallback callback,
ByteData data) native 'Window_sendPlatformMessage';
这里调用了一个native方法,那么我们就需要去找这个native方法。需要先下载Engine
层的代码,地址: Engine.
3.0 Engine
层原理
3.1 _SendPlatformMessage
根据上面的标识符Window_sendPlatformMessage
去Engine层找到注册的方法:
### window.cc
natives->Register({
{"Window_defaultRouteName", DefaultRouteName, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, true},
{"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
{"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
{"Window_render", Render, 2, true},
{"Window_updateSemantics", UpdateSemantics, 2, true},
{"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
{"Window_reportUnhandledException", ReportUnhandledException, 2, true},
});
}
void _SendPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&SendPlatformMessage, args);
}
上面会调到SendPlatformMessage
方法。
3.2 window
--SendPlatformMessage
看下面代码有个有个报错的地方Platform messages can only be sent from the main isolate
,只能在主线程main isolate
发起MethodChannel
调用。
### window.cc
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();
}
接着主要的一行代码,最终会调用到WindowClient
中的虚方法HandlePlatformMessage
dart_state->window()->client()->HandlePlatformMessage
3.3 window
--WindowClient
看下client
定义的地方:
### window.h
class Window final {
public:
explicit Window(WindowClient* client);
~Window();
WindowClient* client() const { return client_; }
...
}
class WindowClient {
public:
virtual std::string DefaultRouteName() = 0;
virtual void ScheduleFrame() = 0;
virtual void Render(Scene* scene) = 0;
virtual void UpdateSemantics(SemanticsUpdate* update) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
virtual FontCollection& GetFontCollection() = 0;
virtual void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) = 0;
protected:
virtual ~WindowClient();
};
遇到纯虚函数了只能去找找看有什么类继承了WindowClient
了.
3.4 RuntimeController
找到只有一个地方继承了:
class RuntimeController final : public WindowClient
到这个类里面:
### RuntimeController.cc
void RuntimeController::HandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
client_.HandlePlatformMessage(std::move(message));
}
最后是通过client_
来调用,看着就是代理模式。接着找client_
,看到构造函数中:
### RuntimeController.cc
RuntimeController::RuntimeController(
RuntimeDelegate& p_client,
DartVM* p_vm,
fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
fml::RefPtr<const DartSnapshot> p_shared_snapshot,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<IOManager> p_io_manager,
std::string p_advisory_script_uri,
std::string p_advisory_script_entrypoint,
std::function<void(int64_t)> idle_notification_callback,
WindowData p_window_data)
: client_(p_client),
vm_(p_vm),
isolate_snapshot_(std::move(p_isolate_snapshot)),
shared_snapshot_(std::move(p_shared_snapshot)),
task_runners_(p_task_runners),
snapshot_delegate_(p_snapshot_delegate),
io_manager_(p_io_manager),
advisory_script_uri_(p_advisory_script_uri),
advisory_script_entrypoint_(p_advisory_script_entrypoint),
idle_notification_callback_(idle_notification_callback),
window_data_(std::move(p_window_data)),
root_isolate_(
DartIsolate::CreateRootIsolate(vm_->GetVMData()->GetSettings(),
isolate_snapshot_,
shared_snapshot_,
task_runners_,
std::make_unique<Window>(this),
snapshot_delegate_,
io_manager_,
p_advisory_script_uri,
p_advisory_script_entrypoint)) {
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
root_isolate->SetReturnCodeCallback([this](uint32_t code) {
root_isolate_return_code_ = {true, code};
});
可以看到是通过client_
其实就是RuntimeDelegate
,
3.5 RuntimeDelegate
那就接着看RuntimeDelegate
了,不巧又遇到了纯虚函数。
### runtime_delegate.h
namespace blink {
class RuntimeDelegate {
public:
virtual std::string DefaultRouteName() = 0;
virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0;
virtual void Render(std::unique_ptr<flow::LayerTree> layer_tree) = 0;
virtual void UpdateSemantics(
blink::SemanticsNodeUpdates update,
blink::CustomAccessibilityActionUpdates actions) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
virtual FontCollection& GetFontCollection() = 0;
virtual void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) = 0;
protected:
virtual ~RuntimeDelegate();
};
} // namespace blink
那就只能再看看哪个类继承了RuntimeDelegate
, 只有一个类Engine
继承了.
3.6 Engine
### engine.h
class Engine final : public blink::RuntimeDelegate
看到engine.cc
中的代码:
### engine.cc
void Engine::HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));
} else {
delegate_.OnEngineHandlePlatformMessage(std::move(message));
}
}
Engine
偷懒又把工作转交给delegate_
, 看到Engine
构造函数里:
### engine.cc
Engine::Engine(Delegate& delegate,
blink::DartVM& vm,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
blink::TaskRunners task_runners,
blink::Settings settings,
std::unique_ptr<Animator> animator,
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<blink::IOManager> io_manager)
: delegate_(delegate),
settings_(std::move(settings)),
animator_(std::move(animator)),
activity_running_(false),
have_surface_(false),
weak_factory_(this) {
// Runtime controller is initialized here because it takes a reference to this
// object as its delegate. The delegate may be called in the constructor and
// we want to be fully initilazed by that point.
runtime_controller_ = std::make_unique<blink::RuntimeController>(
*this, // runtime delegate
&vm, // VM
std::move(isolate_snapshot), // isolate snapshot
std::move(shared_snapshot), // shared snapshot
std::move(task_runners), // task runners
std::move(snapshot_delegate), // snapshot delegate
std::move(io_manager), // io manager
settings_.advisory_script_uri, // advisory script uri
settings_.advisory_script_entrypoint, // advisory script entrypoint
settings_.idle_notification_callback // idle notification callback
);
}
其中Delegate
在engine.h
中定义了:
### engine.h
class Delegate {
public:
virtual void OnEngineUpdateSemantics(
blink::SemanticsNodeUpdates update,
blink::CustomAccessibilityActionUpdates actions) = 0;
virtual void OnEngineHandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) = 0;
virtual void OnPreEngineRestart() = 0;
virtual void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) = 0;
};
还是熟悉的纯虚函数OnEngineHandlePlatformMessage
,回到Engine
,看看哪边构造了这个对象就可以找到 delegate_
了,最终找到shell
.
3.7 Shell
在shell中有个字段属性就是Engine
,构造的时候是将shell传递进去,所以上面的delegate_
就是shell
了
### shell.cc
std::unique_ptr<Engine> engine;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(),
fml::MakeCopyable([&ui_latch, //
&engine, //
shell = shell.get(), //
isolate_snapshot = std::move(isolate_snapshot), //
shared_snapshot = std::move(shared_snapshot), //
vsync_waiter = std::move(vsync_waiter), //
snapshot_delegate = std::move(snapshot_delegate), //
io_manager = io_manager->GetWeakPtr() //
]() mutable {
TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
const auto& task_runners = shell->GetTaskRunners();
// The animator is owned by the UI thread but it gets its vsync pulses
// from the platform.
auto animator = std::make_unique<Animator>(*shell, task_runners,
std::move(vsync_waiter));
engine = std::make_unique<Engine>(*shell, //
*shell->GetDartVM(), //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
task_runners, //
shell->GetSettings(), //
std::move(animator), //
std::move(snapshot_delegate), //
std::move(io_manager) //
);
ui_latch.Signal();
}));
在shell
中找到OnEngineHandlePlatformMessage
方法:
### shell.cc
// |shell::Engine::Delegate|
void Shell::OnEngineHandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (message->channel() == kSkiaChannel) {
HandleEngineSkiaMessage(std::move(message));
return;
}
task_runners_.GetPlatformTaskRunner()->PostTask(
[view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
if (view) {
view->HandlePlatformMessage(std::move(message));
}
});
}
先看到第一个if判断,如果等于kSkiaChannel
就会直接return,看下kSkiaChannel
的值
constexpr char kSkiaChannel[] = "flutter/skia";
很明显我们自定义的channel不会走到这个判断逻辑里面,往下走,就是往PlatformTaskRunner
里面抛一个task
,
关于线程的详细说明,感兴趣的可以看到最后一个小结,因为比较长,为了调用逻辑的连贯性先放到最后了。
3.8 PlatformView
--- PlatformViewAndroid
跟到PlatformView
中,但是是虚函数:
### platform_view.h
virtual void HandlePlatformMessage(
fml::RefPtr<blink::PlatformMessage> message);
接着找到它的继承类PlatformViewAndroid
### platform_view_android.cc
// |shell::PlatformView|
void PlatformViewAndroid::HandlePlatformMessage(
fml::RefPtr<blink::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);
}
}
在这个方法里面已经可以看到Java的一点味道了:
- 首先记录一个回调的id
response_id
,会把回调放到pending_responses_
中
std::unordered_map<int, fml::RefPtr<blink::PlatformMessageResponse>>
pending_responses_;
调用jni下面的
StringToJavaString
转化channel name为Java字符串;如果调用携带参数,会调用
jni:: env->NewByteArray
转为为JNI 数组最后调用
FlutterViewHandlePlatformMessage
而这个函数是定义在platform_view_android_jni.cc
中的
3.9 FlutterViewHandlePlatformMessage
可以看到这里已经开始通过JNIEnv
调用虚拟机里面注册的JNI函数表了。
### platform_view_android_jni.cc
static jmethodID g_handle_platform_message_method = nullptr;
void FlutterViewHandlePlatformMessage(JNIEnv* env,
jobject obj,
jstring channel,
jobject message,
jint responseId) {
env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message,
responseId);
FML_CHECK(CheckException(env));
}
关键就是找到g_handle_platform_message_method
符号表对应的方法了,
### platform_view_android_jni.cc
g_handle_platform_message_method =
env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
"(Ljava/lang/String;[BI)V");
做过JNI的小伙伴们都知道,通过handlePlatformMessage
就可以找到在Android
中对应的方法了。
3.10 FlutterJNI.java
终于来到了Java层,突然觉得Java这么亲切呢。
### FlutterJNI.java
// Called by native.
@SuppressWarnings("unused")
private void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
if (platformMessageHandler != null) {
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
// TODO(mattcarroll): log dropped messages when in debug mode (https://github.com/flutter/flutter/issues/25391)
}
接下来我们从Android
层写的代码入手
4.0 Java
层原理
4.1 MethodChannel.java
再回头看下第一节的内容,
### MainActivity.java
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler((call, result) -> {})
### MethodChannel.java
private final BinaryMessenger messenger;
public MethodChannel(BinaryMessenger messenger, String name) {
this(messenger, name, StandardMethodCodec.INSTANCE);
}
public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) {
this.messenger.setMessageHandler(this.name, handler == null ? null : new MethodChannel.IncomingMethodCallHandler(handler));
}
4.2 MethodChannel.java
BinaryMessenger
是个接口,实现类有多个,在我们构造函数里面传入的是FlutterView
,
最终会调用到FlutterNativeView
下面
### FlutterNativeView.java
private final Map<String, BinaryMessageHandler> mMessageHandlers;
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
if (handler == null) {
this.mMessageHandlers.remove(channel);
} else {
this.mMessageHandlers.put(channel, handler);
}
}
那么前面FlutterJNI
下面的platformMessageHandler
和FlutterNativeView
有关系吗?
看下FlutterNativeView
的构造函数:
### FlutterNativeView.java
public FlutterNativeView(Context context, boolean isBackgroundView) {
this.mNextReplyId = 1;
this.mPendingReplies = new HashMap();
this.mContext = context;
this.mPluginRegistry = new FlutterPluginRegistry(this, context);
this.mFlutterJNI = new FlutterJNI();
this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl());
this.mFlutterJNI.setPlatformMessageHandler(new FlutterNativeView.PlatformMessageHandlerImpl());
this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
this.attach(this, isBackgroundView);
this.assertAttached();
this.mMessageHandlers = new HashMap();
}
可以看到FlutterNativeView
持有FlutterJNI
,PlatformMessageHandlerImpl
也是它的内部类:
### FlutterNativeView.java
private final class PlatformMessageHandlerImpl implements PlatformMessageHandler {
private PlatformMessageHandlerImpl() {
}
public void handleMessageFromDart(final String channel, byte[] message, final int replyId) {
FlutterNativeView.this.assertAttached();
BinaryMessageHandler handler = (BinaryMessageHandler)FlutterNativeView.this.mMessageHandlers.get(channel);
if (handler != null) {
try {
ByteBuffer buffer = message == null ? null : ByteBuffer.wrap(message);
handler.onMessage(buffer, new BinaryReply() {
private final AtomicBoolean done = new AtomicBoolean(false);
public void reply(ByteBuffer reply) {
if (!FlutterNativeView.this.isAttached()) {
Log.d("FlutterNativeView", "handleMessageFromDart replying ot a detached view, channel=" + channel);
} else if (this.done.getAndSet(true)) {
throw new IllegalStateException("Reply already submitted");
} else {
if (reply == null) {
FlutterNativeView.this.mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
} else {
FlutterNativeView.this.mFlutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
}
}
}
});
} catch (Exception var6) {
Log.e("FlutterNativeView", "Uncaught exception in binary message listener", var6);
FlutterNativeView.this.mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
} else {
FlutterNativeView.this.mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
}
...
}
- 首先会从mMessageHandlers中取出前面注册的
MethodChannel
,然后调用onMessage
方法,有的小伙伴发现了我们通过setMethodCallHandler
设置的是MethodCallHandler
,没有onMessage
方法
public interface MethodCallHandler {
void onMethodCall(MethodCall var1, MethodChannel.Result var2);
}
其实有个细节没说,传进去的MethodCallHandler
会构造成IncomingMethodCallHandler
### MethodChannel.java
IncomingMethodCallHandler(MethodChannel.MethodCallHandler handler) {
this.handler = handler;
}
public void onMessage(ByteBuffer message, final BinaryReply reply) {
MethodCall call = MethodChannel.this.codec.decodeMethodCall(message);
try {
this.handler.onMethodCall(call, new MethodChannel.Result() {
public void success(Object result) {
reply.reply(MethodChannel.this.codec.encodeSuccessEnvelope(result));
}
public void error(String errorCode, String errorMessage, Object errorDetails) {
reply.reply(MethodChannel.this.codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}
public void notImplemented() {
reply.reply((ByteBuffer)null);
}
});
} catch (RuntimeException var5) {
Log.e("MethodChannel#" + MethodChannel.this.name, "Failed to handle method call", var5);
reply.reply(MethodChannel.this.codec.encodeErrorEnvelope("error", var5.getMessage(), (Object)null));
}
}
- 接着会通过
invokePlatformMessageResponseCallback
回调回去
FlutterNativeView.this.mFlutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
5.0 回调
上面通过replyId
可以在Engine
层找到回调, 其实就是沿着上面的反路径往回调。
5.1 FlutterJNI.java
@UiThread
public void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position) {
this.ensureAttachedToNative();
this.nativeInvokePlatformMessageResponseCallback(this.nativePlatformViewId, responseId, message, position);
}
private native void nativeInvokePlatformMessageResponseCallback(long var1, int var3, ByteBuffer var4, int var5);
再通过native JNI回调到Engine
层
5.2 platform_view_android_jni.cc
### platform_view_android_jni.cc
static void InvokePlatformMessageResponseCallback(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jint responseId,
jobject message,
jint position) {
ANDROID_SHELL_HOLDER->GetPlatformView()
->InvokePlatformMessageResponseCallback(env, //
responseId, //
message, //
position //
);
}
5.3 platform_view_android.cc
在这里主要是找到前面在HandlePlatformMessage
中登记的回调,然后进行调用:
### platform_view_android.cc
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
JNIEnv* env,
jint response_id,
jobject java_response_data,
jint java_response_position) {
if (!response_id)
return;
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
uint8_t* response_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
std::vector<uint8_t> response = std::vector<uint8_t>(
response_data, response_data + java_response_position);
auto message_response = std::move(it->second);
pending_responses_.erase(it);
message_response->Complete(
std::make_unique<fml::DataMapping>(std::move(response)));
}
最后是调用Complete()方法:
5.4 platform_message_response_dart
### platform_message_response_dart.cc
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});
}));
}
有一个点需要注意的就是回调时在UI线程回调的,回调的数据通过WrapByteData
序列化后进行传递。
这个callback
应该就是之前在window.dart
中注册的callback:
### window.dart
void sendPlatformMessage(String name,
ByteData data,
PlatformMessageResponseCallback callback) {
final String error =
_sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
if (error != null)
throw new Exception(error);
}
/// Wraps the given [callback] in another callback that ensures that the
/// original callback is called in the zone it was registered in.
static PlatformMessageResponseCallback _zonedPlatformMessageResponseCallback(PlatformMessageResponseCallback callback) {
if (callback == null)
return null;
// Store the zone in which the callback is being registered.
final Zone registrationZone = Zone.current;
return (ByteData data) {
registrationZone.runUnaryGuarded(callback, data);
};
}
最后体现在dart层面就是通过Completer
进行Future
的控制回调。
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: 'during a platform message response callback',
));
}
});
6.0 线程
6.1 TaskRunner
--- MessageLoop
看下TaskRunner
,构造的时候会传一个 MessageLoopImpl
进去,
### task_runner.h
namespace fml {
class MessageLoopImpl;
class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner> {
public:
virtual ~TaskRunner();
virtual void PostTask(fml::closure task);
virtual void PostTaskForTime(fml::closure task, fml::TimePoint target_time);
virtual void PostDelayedTask(fml::closure task, fml::TimeDelta delay);
virtual bool RunsTasksOnCurrentThread();
static void RunNowOrPostTask(fml::RefPtr<fml::TaskRunner> runner,
fml::closure task);
protected:
TaskRunner(fml::RefPtr<MessageLoopImpl> loop);
private:
fml::RefPtr<MessageLoopImpl> loop_;
FML_FRIEND_MAKE_REF_COUNTED(TaskRunner);
FML_FRIEND_REF_COUNTED_THREAD_SAFE(TaskRunner);
FML_DISALLOW_COPY_AND_ASSIGN(TaskRunner);
};
}
看到MessageLoop
, 会持有一个task_runner_
和loop_
,
### message_loop.h
class MessageLoop {
public:
FML_EMBEDDER_ONLY
static MessageLoop& GetCurrent();
bool IsValid() const;
void Run();
void Terminate();
void AddTaskObserver(intptr_t key, fml::closure callback);
void RemoveTaskObserver(intptr_t key);
fml::RefPtr<fml::TaskRunner> GetTaskRunner() const;
// Exposed for the embedder shell which allows clients to poll for events
// instead of dedicating a thread to the message loop.
void RunExpiredTasksNow();
static void EnsureInitializedForCurrentThread();
static bool IsInitializedForCurrentThread();
~MessageLoop();
private:
friend class TaskRunner;
friend class MessageLoopImpl;
fml::RefPtr<MessageLoopImpl> loop_;
fml::RefPtr<fml::TaskRunner> task_runner_;
MessageLoop();
fml::RefPtr<MessageLoopImpl> GetLoopImpl() const;
FML_DISALLOW_COPY_AND_ASSIGN(MessageLoop);
};
}
再看构造函数里面给上面两个变量的赋值,可以看到会先构造一个MessageLoopImpl
实例,然后传给TaskRunner
### message_loop.cc
MessageLoop::MessageLoop()
: loop_(MessageLoopImpl::Create()),
task_runner_(fml::MakeRefCounted<fml::TaskRunner>(loop_)) {
FML_CHECK(loop_);
FML_CHECK(task_runner_);
}
再回头看下TaskRunner.PostTask
### task_runner.cc
void TaskRunner::PostTask(fml::closure task) {
loop_->PostTask(std::move(task), fml::TimePoint::Now());
}
最终会通过loop_
也就是MessageLoopImpl.PostTask
,然后会push
到delayed_tasks_
中,
### message_loop_impl.cc
void MessageLoopImpl::PostTask(fml::closure task, fml::TimePoint target_time) {
FML_DCHECK(task != nullptr);
RegisterTask(task, target_time);
}
void MessageLoopImpl::RegisterTask(fml::closure task,
fml::TimePoint target_time) {
FML_DCHECK(task != nullptr);
if (terminated_) {
// If the message loop has already been terminated, PostTask should destruct
// |task| synchronously within this function.
return;
}
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
delayed_tasks_.push({++order_, std::move(task), target_time});
WakeUp(delayed_tasks_.top().target_time);
}
而delayed_tasks_
是一个优先级队列:
### message_loop_impl.h
using DelayedTaskQueue = std::
priority_queue<DelayedTask, std::deque<DelayedTask>, DelayedTaskCompare>;
DelayedTaskQueue delayed_tasks_;
总结一下,
TaskRunner.PostTask
最终是将Task
放到MessageLoop
中的队列中。
6.2 Thread
-- ThreadHost
问题来了,放到队列里面的Task
谁负责取出来运行呢?按照尝试这时候应该是线程要出来了,我们找到Shell
中看下线程创建:
### shell_benchmarks.cc
namespace shell {
static void StartupAndShutdownShell(benchmark::State& state,
bool measure_startup,
bool measure_shutdown) {
std::unique_ptr<Shell> shell;
std::unique_ptr<ThreadHost> thread_host;
{
benchmarking::ScopedPauseTiming pause(state, !measure_startup);
blink::Settings settings = {};
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
// Measure the time it takes to setup the threads as well.
thread_host = std::make_unique<ThreadHost>(
"io.flutter.bench.", ThreadHost::Type::Platform |
ThreadHost::Type::GPU | ThreadHost::Type::IO |
ThreadHost::Type::UI);
blink::TaskRunners task_runners(
"test", thread_host->platform_thread->GetTaskRunner(),
thread_host->gpu_thread->GetTaskRunner(),
thread_host->ui_thread->GetTaskRunner(),
thread_host->io_thread->GetTaskRunner());
shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<PlatformView>(shell, shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
}
FML_CHECK(shell);
{
benchmarking::ScopedPauseTiming pause(state, !measure_shutdown);
shell.reset(); // Shutdown is synchronous.
thread_host.reset();
}
FML_CHECK(!shell);
}
...
}
taskRunner
都是从ThreadHost
中拿到,再看看ThreadHost
:
### thread_host.h
namespace shell {
struct ThreadHost {
enum Type {
Platform = 1 << 0,
UI = 1 << 1,
GPU = 1 << 2,
IO = 1 << 3,
};
std::unique_ptr<fml::Thread> platform_thread;
std::unique_ptr<fml::Thread> ui_thread;
std::unique_ptr<fml::Thread> gpu_thread;
std::unique_ptr<fml::Thread> io_thread;
ThreadHost();
ThreadHost(ThreadHost&&);
ThreadHost& operator=(ThreadHost&&) = default;
ThreadHost(std::string name_prefix, uint64_t type_mask);
~ThreadHost();
void Reset();
};
}
主要有四个线程,分别是platform_thread
, ui_thread
, gpu_thread
, io_thread
.,再看看线程Thread
的具体逻辑:
### thread.cc
Thread::Thread(const std::string& name) : joined_(false) {
fml::AutoResetWaitableEvent latch;
fml::RefPtr<fml::TaskRunner> runner;
thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void {
SetCurrentThreadName(name);
fml::MessageLoop::EnsureInitializedForCurrentThread();
auto& loop = MessageLoop::GetCurrent();
runner = loop.GetTaskRunner();
latch.Signal();
loop.Run();
});
latch.Wait();
task_runner_ = runner;
}
具体逻辑步骤:
- 设置线程名
这个逻辑就是在ThreadHost
中,其中name_prefix
就是在shell_benchmarks
中定义的io.flutter.bench.
- 设置线程名
ThreadHost::ThreadHost(std::string name_prefix, uint64_t mask) {
if (mask & ThreadHost::Type::Platform) {
platform_thread = std::make_unique<fml::Thread>(name_prefix + ".platform");
}
if (mask & ThreadHost::Type::UI) {
ui_thread = std::make_unique<fml::Thread>(name_prefix + ".ui");
}
if (mask & ThreadHost::Type::GPU) {
gpu_thread = std::make_unique<fml::Thread>(name_prefix + ".gpu");
}
if (mask & ThreadHost::Type::IO) {
io_thread = std::make_unique<fml::Thread>(name_prefix + ".io");
}
}
- 2.初始化
MessageLoop
### thread.cc
fml::MessageLoop::EnsureInitializedForCurrentThread()
### message_loop.cc
FML_THREAD_LOCAL ThreadLocal tls_message_loop([](intptr_t value) {
delete reinterpret_cast<MessageLoop*>(value);
});
void MessageLoop::EnsureInitializedForCurrentThread() {
if (tls_message_loop.Get() != 0) {
// Already initialized.
return;
}
tls_message_loop.Set(reinterpret_cast<intptr_t>(new MessageLoop()));
}
会有一个ThreadLocal
保存MessageLoop
,避免重复创建。
- 3.获取
loop
和runner
### thread.cc
auto& loop = MessageLoop::GetCurrent();
runner = loop.GetTaskRunner();
### message_loop.cc
MessageLoop& MessageLoop::GetCurrent() {
auto* loop = reinterpret_cast<MessageLoop*>(tls_message_loop.Get());
FML_CHECK(loop != nullptr)
<< "MessageLoop::EnsureInitializedForCurrentThread was not called on "
"this thread prior to message loop use.";
return *loop;
}
fml::RefPtr<fml::TaskRunner> MessageLoop::GetTaskRunner() const {
return task_runner_;
}
- 4.run messageloop
最后调用
### thread.cc
loop.Run();
### message_loop.cc
void MessageLoop::Run() {
loop_->DoRun();
}
上面已经分析到loop_
是MessageLoopImpl
:
### message_loop_impl.cc
void MessageLoopImpl::DoRun() {
if (terminated_) {
// Message loops may be run only once.
return;
}
// Allow the implementation to do its thing.
Run();
// The loop may have been implicitly terminated. This can happen if the
// implementation supports termination via platform specific APIs or just
// error conditions. Set the terminated flag manually.
terminated_ = true;
// The message loop is shutting down. Check if there are expired tasks. This
// is the last chance for expired tasks to be serviced. Make sure the
// terminated flag is already set so we don't accrue additional tasks now.
RunExpiredTasksNow();
// When the message loop is in the process of shutting down, pending tasks
// should be destructed on the message loop's thread. We have just returned
// from the implementations |Run| method which we know is on the correct
// thread. Drop all pending tasks on the floor.
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
delayed_tasks_ = {};
}
最关键的就是Run()
方法,但是很不幸的是在MessageLoopImpl
中Run()
是纯虚函数:
class MessageLoopImpl : public fml::RefCountedThreadSafe<MessageLoopImpl> {
public:
static fml::RefPtr<MessageLoopImpl> Create();
virtual ~MessageLoopImpl();
virtual void Run() = 0;
void PostTask(fml::closure task, fml::TimePoint target_time);
void DoRun();
...
}
其实根据平台有不同的实现:
fml::RefPtr<MessageLoopImpl> MessageLoopImpl::Create() {
#if OS_MACOSX
return fml::MakeRefCounted<MessageLoopDarwin>();
#elif OS_ANDROID
return fml::MakeRefCounted<MessageLoopAndroid>();
#elif OS_LINUX
return fml::MakeRefCounted<MessageLoopLinux>();
#elif OS_WIN
return fml::MakeRefCounted<MessageLoopWin>();
#else
return nullptr;
#endif
在Android
平台下我们看看MessageLoopAndroid
:
### message_loop_android.cc
void MessageLoopAndroid::Run() {
FML_DCHECK(looper_.get() == ALooper_forThread());
running_ = true;
while (running_) {
int result = ::ALooper_pollOnce(-1, // infinite timeout
nullptr, // out fd,
nullptr, // out events,
nullptr // out data
);
if (result == ALOOPER_POLL_TIMEOUT || result == ALOOPER_POLL_ERROR) {
// This handles the case where the loop is terminated using ALooper APIs.
running_ = false;
}
}
}
到这里就是一个死循环了,ALooper_pollOnce
已经跟不进去了,猜测里面逻辑应该就是循环从优先级队列中拿出Task
执行。
是不是看到了Android
开发很熟悉的loop
,
-
TaskRunner
类似于Handler
,可以通过它向队列中抛消息; -
MessageLooperImpl
就是类似于MessageQueue
; - 而
MessageLoopAndroid
就类似于Looper
,循环从队列中取出消息
Refs: