一次典型的方法调用过程类似网络调用,由作为客户端的 Flutter,通过方法通道向作为服务端的原生代码宿主发送方法调用请求,原生代码宿主在监听到方法调用的消息后,调用平台相关的 API 来处理 Flutter 发起的请求,最后将处理完毕的结果通过方法通道回发至 Flutter。调用过程如下图所示:
1. 基本用法以跳转应用市场为例
//声明MethodChannel
const platform = MethodChannel('channelName');
//处理按钮点击
handleButtonClick() async{
int result;
//异常捕获
try {
//异步等待方法通道的调用结果
result = await platform.invokeMethod('openAppMarket');
}
catch (e) {
result = -1;
}
print("Result:$result");
}
1.1 Android端实现
MainActivity.java
public class MainActivity extends FlutterActivity {
MethodChannel methodChannel;
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
methodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "channelName");
methodChannel.setMethodCallHandler((call, result) -> {
//判断方法名是否支持
if(call.method.equals("openAppMarket")) {
try {
//应用市场URI
Uri uri = Uri.parse("market://details?id=com.hangchen.example.flutter_module_page.host");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//打开应用市场
startActivity(intent);
//返回处理结果
result.success(0);
} catch (Exception e) {
//打开应用市场出现异常
result.error("UNAVAILABLE", "没有安装应用市场", null);
}
}else {
//方法名暂不支持
result.notImplemented();
}
});
}
}
1.2 iOS端实现
AppleDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//创建命名方法通道
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"samples.chenhang/utils" binaryMessenger:(FlutterViewController *)self.window.rootViewController];
//往方法通道注册方法调用处理回调
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
//方法名称一致
if ([@"openAppMarket" isEqualToString:call.method]) {
//打开App Store(本例打开微信的URL)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/xy/app/foo/id414478124"]];
//返回方法处理结果
result(@0);
} else {
//找不到被调用的方法
result(FlutterMethodNotImplemented);
}
}];
...
}
2. 原理分析
Dart这边的MethodChannel类,有几个重要的成员变量:
/// 方法通道的名字 not null
final String name;
/// 信息的编解码器 not null
final MethodCodec codec;
/// 用来发送消息的messenger
/// 未设定的话就用默认的
BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger;
final BinaryMessenger? _binaryMessenger;
2.1 调用invokeMethod来获取通信结果
Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async {
final ByteData? result = await binaryMessenger.send(
name,
codec.encodeMethodCall(MethodCall(method, arguments)),
);
if (result == null) {
if (missingOk) {
return null;
}
throw MissingPluginException('No implementation found for method $method on channel $name');
}
return codec.decodeEnvelope(result) as T?;
}
先是将我们要调用的方法名构造了一个MethodCall,然后用codec编码,之后通过binaryMessenger发送了一条消息,调用结果会被封装成一个ByteData,然后用codec解码。
2.2 StandartMethodCodec
codec默认是一个StandardMethodCodec,看下它的encodeMethodCall方法做了什么
@override
ByteData encodeMethodCall(MethodCall call) {
final WriteBuffer buffer = WriteBuffer();
messageCodec.writeValue(buffer, call.method);
messageCodec.writeValue(buffer, call.arguments);
return buffer.done();
}
构造了一个WriteBuffer,然后将方法名和buffer传进messageCodec
void writeValue(WriteBuffer buffer, dynamic value) {
...
//会走到这
else if (value is String) {
//先写进一个标识为String的int值,其它类型有不同的值
buffer.putUint8(_valueString);
//转换为Uinnt8List,就是一个二进制数组
final Uint8List bytes = utf8.encoder.convert(value);
//将非负32位整数[值]写入[缓冲区]使用扩展的1-5字节编码来优化小值。
writeSize(buffer, bytes.length);
//将二进制数组写入buffer
buffer.putUint8List(bytes);
}
}
2.3 WriteBuffer
调用buffer.done()方法,将ByteBuffer转换为ByteData。
ByteData done() {
final ByteData result = _buffer!.buffer.asByteData(0, _buffer!.lengthInBytes);
_buffer = null;
return result;
}
2.4 Send
回到[2.1]invokeMethod方法,看下binaryMessenger的send方法做了什么,这个binaryMessenger实际上是binding.dart里面的一个类_DefaultBinaryMessenger,继承了BinaryMessager,它的send方法如下:
@override
Future<ByteData?>? send(String channel, ByteData? message) {
//先判断有没有设置mockHandler,有的话就用mockhandler处理信息,这种情况一般用于单元测试
final MessageHandler? handler = _mockHandlers[channel];
if (handler != null)
return handler(message);
return _sendPlatformMessage(channel, message);
}
调用_sendPlatformMessage()
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
final Completer<ByteData?> completer = Completer<ByteData?>();
//调用PatformDispatcher的sendPlatformMessage方法
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message response callback'),
));
}
});
return completer.future;
}
最后会调用到PlatformDispatcher的_sendPlatformMessage方法,进入flutter engine层的_SendPlatformMessage。
3. Engine层3.1 PlatformConfiguration
//platform_configuration.cc
void _SendPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&SendPlatformMessage, args);
}
}
void PlatformConfiguration::RegisterNatives(
tonic::DartLibraryNatives* natives) {
natives->Register({
{"PlatformConfiguration_sendPlatformMessage", _SendPlatformMessage, 4,
true},
...
});
}
PlatformDispatcher中的_sendPlatformMessage最终对应于引擎层中platform_configuration.cc的_SendPlatformMessage()方法,继续调用SendPlatformMessage()。
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->platform_configuration()) {
return tonic::ToDart(
"Platform messages can only be sent from the main isolate");
}
fml::RefPtr<PlatformMessageResponse> response;
if (!Dart_IsNull(callback)) {
//PlatformMessageResponseDart对象中采用的是UITaskRunner
response = fml::MakeRefCounted<PlatformMessageResponseDart>(
tonic::DartPersistentValue(dart_state, callback),
dart_state->GetTaskRunners().GetUITaskRunner());
}
if (Dart_IsNull(data_handle)) {
dart_state->platform_configuration()->client()->HandlePlatformMessage(
std::make_unique<PlatformMessage>(name, response));
} else {
tonic::DartByteData data(data_handle);
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
dart_state->platform_configuration()->client()->HandlePlatformMessage(
std::make_unique<PlatformMessage>(
name, fml::MallocMapping::Copy(buffer, data.length_in_bytes()),
response));
}
return Dart_Null();
}
name: channel名
data_handle: 待执行的方法名和参数
callback: 执行后回调反馈结果数据的方法
这里还创建了一个PlatformMessageResponseDart对象,保存callback方法。
最后调用RuntimeController(继承了PlatformConfigurationClient)的HandlePlatformMessage来处理平台消息。
3.2 RuntimeController
//flutter/runtime/runtime_controller.cc
void RuntimeController::HandlePlatformMessage(
std::unique_ptr<PlatformMessage> message) {
client_.HandlePlatformMessage(std::move(message));
}
Flutter engine的调用关系如下:
上面的client来自engine,所以走到engine的HandlePlatformMessage方法。
3.3 Engine
//flutter/shell/common/engine.cc
static constexpr char kAssetChannel[] = "flutter/assets";
void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));
} else {
delegate_.OnEngineHandlePlatformMessage(std::move(message));
}
}
这里的delegate_来自shell,走到shell的OnEngineHandlePlatformMessage。
3.4 Shell
//flutter/shell/common/shell.cc
constexpr char kSkiaChannel[] = "flutter/skia";
void Shell::OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
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));
}
});
}
接下来将HandlePlatformMessage的工作交给主线程的PlatformTaskRunner来处理,调用了platform_view的HandlePlatformMessage方法,这个view对于Android平台的实例为PlatformViewAndroid。
3.5 PlatformViewAndroid
//flutter/shell/platform/android/platform_view_android.cc
std::unordered_map<int, fml::RefPtr<flutter::PlatformMessageResponse>>
pending_responses_;
// |PlatformView|
void PlatformViewAndroid::HandlePlatformMessage(
std::unique_ptr<flutter::PlatformMessage> message) {
int response_id = 0;
if (auto response = message->response()) {
response_id = next_response_id_++;
pending_responses_[response_id] = response;
}
// This call can re-enter in InvokePlatformMessageXxxResponseCallback.
jni_facade_->FlutterViewHandlePlatformMessage(std::move(message),
response_id);
message = nullptr;
}
pending_response_是一个map数据类型,key为response_id(一个计数),value为message的response,这个map里面记录这所有待响应的PlatformMessageResponse数据。
//flutter/shell/platform/android/platform_view_android_jni_impl.cc
void FlutterViewHandlePlatformMessage(JNIEnv* env, jobject obj,
jstring channel, jobject message,
jint responseId) {
env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message, responseId);
}
这里就回到Java层了,对应FlutterJNI.java中的handlePlatformMessage()方法。
4. 宿主层先来看看Java层的MethodChannel
public final class MethodChannel {
private final BinaryMessenger messenger;
private final String name;
private final MethodCodec codec;
public MethodChannel(BinaryMessenger messenger, String name) {
//创建MethodChannel
this(messenger, name, StandardMethodCodec.INSTANCE);
}
public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
this.messenger = messenger;
this.name = name;
this.codec = codec;
}
}
可以发现是跟Dart的MethodChannel一一对应的,其中的BinaryMessenger是一个接口,在Activity重写configFlutterEngine函数的时候通过flutterEngine.getDartExecutor().getBinaryMessenger()拿到,然后创建MethodChannel。
configFlutterEngine函数定义在FlutterActivityAndFragmentDelegate类的内部接口FlutterActivityAndFragmentDelegate.Host,而FlutterActivity实现了这个接口,并且持有一个FlutterActivityAndFragmentDelegate成员变量delegate,在onCreate中初始化这个delegate。
4.1 FlutterActivity
// FlutterActivity.java
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
delegate = new FlutterActivityAndFragmentDelegate(this);
//在这里会触发flutterEngin的初始化setupFlutterEngine()
delegate.onAttach(this);
delegate.onRestoreInstanceState(savedInstanceState);
}
4.2 FlutterActivityAndFragmentDelegate
// FlutterActivityAndFragmentDelegate.java
void setupFlutterEngine() {
// 先检查是否需要从缓存中获取
String cachedEngineId = host.getCachedEngineId();
if (cachedEngineId != null) {
flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
isFlutterEngineFromHost = true;
if (flutterEngine == null) {
throw new IllegalStateException(
"The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
+ cachedEngineId
+ "'");
}
return;
}
// 其次把创建FlutterEngine的任务委托给子类,这里的Host即为FlutterActivity
flutterEngine = host.provideFlutterEngine(host.getContext());
if (flutterEngine != null) {
isFlutterEngineFromHost = true;
return;
}
// FlutterActivity不创建,则系统创建
flutterEngine =
new FlutterEngine(
host.getContext(),
host.getFlutterShellArgs().toArray(),
/*automaticallyRegisterPlugins=*/ false,
/*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
isFlutterEngineFromHost = false;
}
FlutterEngine的构造函数中会初始化dartExecutor,DartExecutor的构造函数中会初始化一个DefaultBinaryMessenger。
回到MethodChannel的创建部分,我们调用了它的setMethodCallHandler方法。
4.3 MethodChannel
// io/flutter/plugin/common/MethodChannel.java
public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
messenger.setMessageHandler(
name, handler == null ? null : new IncomingMethodCallHandler(handler));
}
调用了messeger的setMethodCallHandler方法。
4.4 DefaultBinaryMessenger
// DefaultBinaryMessenger
public void setMessageHandler(
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
messenger.setMessageHandler(channel, handler);
}
这里的messenger是一个DartMessenger,在创建DefaultBinaryMessenger的时候传进来的。
4.5 DartMessenger
@NonNull private final Map<String, BinaryMessenger.BinaryMessageHandler> messageHandlers;
@Override
public void setMessageHandler(
@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
if (handler == null) {
messageHandlers.remove(channel);
} else {
messageHandlers.put(channel, handler);
}
}
将传进来的BinaryMessageHandler保存进了一个map,跟dart层一样,messageHandlers记录着每一个channel所对应的handler方法,此处的handler为IncomingMethodCallHandler。
private final class IncomingMethodCallHandler implements BinaryMessageHandler {
private final MethodCallHandler handler;
//保存了我们写的MethodCallHandler
IncomingMethodCallHandler(MethodCallHandler handler) {
this.handler = handler;
}
}
5. Java层
再回到[3.5]FlutterViewHandlePlatformMessage方法,经过JNI将调用FlutterJNI.handlePlatformMessage()方法。
5.1 FlutterJNI
// flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
private void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
//这里的replyId即为之前传入的response_id[3.5]
if (platformMessageHandler != null) {
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
}
FlutterEngine初始化过程,会创建DartExecutor,调用其onAttachedToJNI()方法来设置platformMessageHandler,其值等于DartMessenger。
public void onAttachedToJNI() {
//Attached to JNI. Registering the platform message handler for this Dart execution context.
flutterJNI.setPlatformMessageHandler(dartMessenger);
}
5.2 DartMessenger
看下DartMessenger的handleMessageFromDart方法。
// io/flutter/embedding/engine/dart/DartMessenger.java
public void handleMessageFromDart(final String channel,
byte[] message, final int replyId) {
//从messageHandlers中获取handler
BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
if (handler != null) {
try {
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
//之前保存的IncomingMethodCallHandler
handler.onMessage(buffer, new Reply(flutterJNI, replyId));
} catch (Exception ex) {
...
}
} else {
...
}
}
这里的Reply是DartMessenger中的一个静态内部类,继承了BinaryMessager.BinaryReply。
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
private static class Reply implements BinaryMessenger.BinaryReply {
private final FlutterJNI flutterJNI;
private final int replyId;
private final AtomicBoolean done = new AtomicBoolean(false);
Reply(@NonNull FlutterJNI flutterJNI, int replyId) {
this.flutterJNI = flutterJNI;
this.replyId = replyId;
}
}
}
5.3 IncomingMethodCallHandler
来到IncomingMethodCallHandler的onMessage方法。
@Override
@UiThread
public void onMessage(ByteBuffer message, final BinaryReply reply) {
//从消息中解码出MethodCall
final MethodCall call = codec.decodeMethodCall(message);
try {
//这里回调了我们自己写的代码,见MainActivity.java
handler.onMethodCall(
call,
new Result() {
@Override
public void success(Object result) {
// 给dart层发送回复
reply.reply(codec.encodeSuccessEnvelope(result));
}
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {
reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}
@Override
public void notImplemented() {
reply.reply(null);
}
});
} catch (RuntimeException e) {
reply.reply(
codec.encodeErrorEnvelopeWithStacktrace(
"error", e.getMessage(), null, getStackTrace(e)));
}
}
6. 给Dart层回传结果
// DartMessenger/Reply
public void reply(ByteBuffer reply) {
if (reply == null) {
flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
} else {
//走这里
flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
}
}
6.1 FlutterJNI
进入FlutterJNI
public void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position) {
if (isAttached()) {
nativeInvokePlatformMessageResponseCallback(
nativePlatformViewId, responseId, message, position);
}
}
到这里message就进入native层了。
6.2 InvokePlatformMessageResponseCallback
// flutter/engine/blob/master/shell/platform/android/platform_view_android_jni_impl.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 //
);
}
这里的platformView是PlatformViewAndroid。
6.3 PlatformViewAndroid
// flutter/shell/platform/android/platform_view_android.cc
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
JNIEnv* env, jint response_id,
jobject java_response_data, jint java_response_position) {
//从pending_responses_根据response_id来查找PlatformMessageResponse
auto it = pending_responses_.find(response_id);
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);
//将结果写入到之前保存的PlatformMessageResponseDart
message_response->Complete(std::make_unique<fml::DataMapping>(std::move(response)));
}
调用了PlatformMessageResponseDart的Complete()方法。
6.4 PlatformMessageResponseDart
// flutter/lib/ui/window/platform_message_response_dart.cc
void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
is_complete_ = true;
//post到UI线程来执行
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();
tonic::DartState::Scope scope(dart_state);
Dart_Handle byte_buffer = WrapByteData(std::move(data));
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}
此处将任务Post到UI线程的UITaskRunner来执行。
6.5 DartInvoke
// third_party/tonic/logging/dart_invoke.cc
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);
return handle;
}
该方法参数closure,也就是PlatformMessageResponseDart中的callback_,不断回溯可知所对应方法便是Dart层BinaryMessages的_senPlatformMessage方法里sendPlatformMessage()的第3个参数[2.4],是一个闭包函数如下所示。
(ByteData reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
...
}
}
到这里就是触发Future的返回结果了,dart那边就会从await的地方继续执行。
7. 参考
深入理解Flutter的Platform Channel机制
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)