前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dart和Java通信源码分析和实践

Dart和Java通信源码分析和实践

作者头像
静默加载
发布2020-05-29 11:16:03
1.3K0
发布2020-05-29 11:16:03
举报
文章被收录于专栏:振兴的Android修炼手册

前言

DartJava 通信这块的知识点涵盖了 Dart&C 以及 Java&C 的通信,我们先有简单的业务组件的定义再到底层实现原理进行分,我们现在从Flutter定义的三种 Channel 中的 MethodChannel 使用进行剖析。

面无表情的我.png

Dart和Java通信的实践

Java端ChannelPlugin的创建

代码语言:javascript
复制
public class FileProviderPlugin implements MethodChannel.MethodCallHandler {
    public final static String NAME = "plugins.flutter.io/file_plugin";
    private final Registrar mRegistrar;
    private Context application;
    public FileProviderPlugin(Registrar mRegistrar, Context context) {
        this.mRegistrar = mRegistrar;
        this.application = context.getApplicationContext();
    }

    public static void registerWith(Registrar registrar, Context context) {
        MethodChannel channel =
                new MethodChannel(registrar.messenger(), NAME);
        FileProviderPlugin instance = new FileProviderPlugin(registrar, context);
        channel.setMethodCallHandler(instance);
    }

    @TargetApi(Build.VERSION_CODES.FROYO)
    @Override
    public void onMethodCall(MethodCall methodCall, Result result) {
        String path;
        switch (methodCall.method) {
            case "getExternalStoragePublicDirectory":
                path = Environment.getExternalStoragePublicDirectory(methodCall.arguments.toString()).getAbsolutePath();
                result.success(path);
                break;
        }
    }
}

Java端ChannelPlugin的注册

代码语言:javascript
复制
public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
    FileProviderPlugin.registerWith(this.registrarFor(FileProviderPlugin.NAME), this);
  }
}

Dart端ChannelPlugin的创建

代码语言:javascript
复制
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
const MethodChannel _channel = const MethodChannel('plugins.flutter.io/file_plugin');
const String DIRECTORY_DCIM = "DCIM";
Future<Directory> getExternalStoragePublicDirectory(String type) async {
  if (Platform.isIOS)
    throw new UnsupportedError("Functionality not available on iOS");
  final String path = await _channel.invokeMethod('getExternalStoragePublicDirectory', type);
  if (path == null) {
    return null;
  }
  return new Directory(path);
}

Dart端ChannelPlugin的使用

代码语言:javascript
复制
class Page extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Reading and Writing Files')),
      body: Center(
        child: Text("this page name is test"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _click,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  void _click() {
    _getExternalStoragePublicDirectory(FileUtils.DIRECTORY_DCIM).then((path) {
      print(path);
    });
  }
    //获取存储图片和视频文件目录
  Future<String> _getExternalStoragePublicDirectory(String s) async {
    final directory = await FileUtils.getExternalStoragePublicDirectory(s);
    return directory.path;
  }
}

结果输出

代码语言:javascript
复制
I/flutter (16780): /storage/emulated/0/DCIM

源代码分析

Dart端代码

MethodChannel信息的封装

代码语言:javascript
复制
class MethodChannel {
  const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
  final String name;
  final MethodCodec codec;
  @optionalTypeArgs
  Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
    assert(method != null);
    final ByteData result = await BinaryMessages.send(
      name,
      //构造一个MethodCall对象,并调用StandardMethodCodec的encode将其写入一个ByteData中。
      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;
  }
  /******部分代码省略******/
}
//MethodCall对象
class MethodCall {
  const MethodCall(this.method, [this.arguments]): assert(method != null);
  final String method;
  final dynamic arguments;
  @override
  String toString() => '$runtimeType($method, $arguments)';
}
//默认的对函数进行编解码工具
class StandardMethodCodec implements MethodCodec {
  const StandardMethodCodec([this.messageCodec = const StandardMessageCodec()]);
  final StandardMessageCodec messageCodec;
  @override
  ByteData encodeMethodCall(MethodCall call) {
    final WriteBuffer buffer = WriteBuffer();
    messageCodec.writeValue(buffer, call.method);
    messageCodec.writeValue(buffer, call.arguments);
    return buffer.done();
  }
  /******部分代码省略******/
}
//默认的对数据信息编解码工具
class StandardMessageCodec implements MessageCodec<dynamic> {
  const StandardMessageCodec();
  static const int _valueNull = 0;
  static const int _valueTrue = 1;
  static const int _valueFalse = 2;
  static const int _valueInt32 = 3;
  static const int _valueInt64 = 4;
  static const int _valueLargeInt = 5;
  static const int _valueFloat64 = 6;
  static const int _valueString = 7;
  static const int _valueUint8List = 8;
  static const int _valueInt32List = 9;
  static const int _valueInt64List = 10;
  static const int _valueFloat64List = 11;
  static const int _valueList = 12;
  static const int _valueMap = 13;
  //数据转化
  void writeValue(WriteBuffer buffer, dynamic value) {
    if (value == null) {
      buffer.putUint8(_valueNull);
    } else if (value is bool) {
      buffer.putUint8(value ? _valueTrue : _valueFalse);
    }/******部分代码省略******/
}

信息传到C层

代码语言:javascript
复制
class BinaryMessages {
  BinaryMessages._();
  static final Map<String, _MessageHandler> _handlers =
      <String, _MessageHandler>{};
  static final Map<String, _MessageHandler> _mockHandlers =
      <String, _MessageHandler>{};
  static Future<ByteData> send(String channel, ByteData message) {
    final _MessageHandler handler = _mockHandlers[channel];
    if (handler != null)
      return handler(message);
    return _sendPlatformMessage(channel, message);
  }

  static Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    final Completer<ByteData> completer = Completer<ByteData>();
    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;
  }
  /******部分代码省略******/
}

class Window {
  Window._();
  /******部分代码省略******/
  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';
  /******部分代码省略******/
}

C层代码分析

Window_sendPlatformMessage方法

代码语言:javascript
复制
//engine/lib/ui/window/window.cc
void Window::RegisterNatives(tonic::DartLibraryNatives *natives) { 
    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},
        {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true},
    }); 
}
void _SendPlatformMessage(Dart_NativeArguments args){
    //由DART_NATIVE_CALLBACK_STATIC宏生成的方法调用;
    //详见:/fuchsia/tonic/dart_binding_macros.h
    tonic::DartCallStatic(&SendPlatformMessage, args);
}
Dart_Handle SendPlatformMessage(Dart_Handle window, const std::string &name, Dart_Handle callback, Dart_Handle data_handle){
    UIDartState *dart_state = UIDartState::Current();
    //判断当前的window对象
    if (!dart_state->window()){
        return tonic::ToDart("Platform messages can only be sent from the main isolate");
    }
    //如果需要返回值构造返回体(PlatformMessageResponseDart),再向dart端做数据返回的时候需要
    fml::RefPtr<PlatformMessageResponse> response;
    if (!Dart_IsNull(callback)){
        response = fml::MakeRefCounted<PlatformMessageResponseDart>(tonic::DartPersistentValue(dart_state, callback), dart_state->GetTaskRunners().GetUITaskRunner());
    }
    //调用window的client对象的HandlePlatformMessage方法处理消息
    //window=>WindowClient=>RuntimeController(RuntimeDelegate=>Engine).
    //所以最终调用的是Engine.HandlePlatformMessage
    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();
}

Engine.HandlePlatformMessage

代码语言:javascript
复制
//engine/shell/common/engine.h
private:Engine::Delegate& delegate_;
//engine/shell/common/engine.cc
static constexpr char kAssetChannel[] = "flutter/assets";
void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message){
    //判断当前的channel是不是flutter/assets
    if (message->channel() == kAssetChannel){
        HandleAssetPlatformMessage(std::move(message));
    }else{
        delegate_.OnEngineHandlePlatformMessage(std::move(message));
    }
}

Engine对象的delegate_

Shell 作为 Engine::Delegate 的子类:

代码语言:javascript
复制
//engine/shell/common/shell.h
class Shell final : public PlatformView::Delegate, 
                    public Animator::Delegate, 
                    public Engine::Delegate, 
                    public Rasterizer::Delegate, 
                    public ServiceProtocol::Handler{

    /*******部分代码省略********/
    // |Engine::Delegate|
    void OnEngineHandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
}

OnEngineHandlePlatformMessage方法实现

代码语言:javascript
复制
// sengine/hell/common/shell.cc
constexpr char kSkiaChannel[] = "flutter/skia";
// |Engine::Delegate|
void Shell::OnEngineHandlePlatformMessage(
    fml::RefPtr<PlatformMessage> message){
    //判断Shell是不是进行过setup
    FML_DCHECK(is_setup_);
    FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
    //判断当前的channel是不是flutter/skia
    if (message->channel() == kSkiaChannel){
        HandleEngineSkiaMessage(std::move(message));
        return;
    }
    //在主线程中post一个task
    task_runners_.GetPlatformTaskRunner()->PostTask(
        //platform_view_是shell创建时候传过来的,也就是在Flutterview进行attach的时候出现的
        //在这里的PlatformView是PlatformViewAndroid
        [view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
            if (view){
                view->HandlePlatformMessage(std::move(message));
            }
        });
}

PlatformView

代码语言:javascript
复制
/// engine/shell/platform/android/platform_view_android.cc
// |PlatformView|
void PlatformViewAndroid::HandlePlatformMessage(
    fml::RefPtr<flutter::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_++;
        //将当前的response_id存储在pending_responses_
        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);
    }
}

JNI_OnLoad

Android 程序中 so 的加载都会调用 so 中的 JNI_OnLoad 方法, 详细的知识点可以从 从JNI_OnLoad看so的加载 这篇文章中学习。

代码语言:javascript
复制
//engine/shell/platform/android/library_loader.cc
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved){
    // Initialize the Java VM.
    fml::jni::InitJavaVM(vm);
    JNIEnv *env = fml::jni::AttachCurrentThread();
    bool result = false;
    // Register FlutterMain.
    result = flutter::FlutterMain::Register(env);
    FML_CHECK(result);
    // Register PlatformView
    result = flutter::PlatformViewAndroid::Register(env);
    FML_CHECK(result);
    // Register VSyncWaiter.
    result = flutter::VsyncWaiterAndroid::Register(env);
    FML_CHECK(result);
    return JNI_VERSION_1_4;
}
FlutterMain::Register
代码语言:javascript
复制
// engine/shell/platform/android/platform_view_android_jni.cc
void FlutterViewHandlePlatformMessage(JNIEnv *env,
                                      jobject obj,
                                      jstring channel,
                                      jobject message,
                                      jint responseId){
    //即调用FlutterJNI.handlePlatformMessage方法
    env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message,
                        responseId);
    FML_CHECK(CheckException(env));
}

bool RegisterApi(JNIEnv *env){
    /*******部分代码省略********/
    //这里的g_handle_platform_message_method为io/flutter/embedding/engine/FlutterJNI
    g_handle_platform_message_method =
        env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
                         "(Ljava/lang/String;[BI)V");
    return true;
}
PlatformViewAndroid::Register
代码语言:javascript
复制
//engine/shell/platform/android/flutter_main.cc
static std::unique_ptr<FlutterMain> g_flutter_main;
void FlutterMain::Init(JNIEnv *env,
                       jclass clazz,
                       jobject context,
                       jobjectArray jargs,
                       jstring kernelPath,
                       jstring appStoragePath,
                       jstring engineCachesPath){
    /*******部分代码省略********/
    g_flutter_main.reset(new FlutterMain(std::move(settings)));
    g_flutter_main->SetupObservatoryUriCallback(env);
}

void FlutterMain::SetupObservatoryUriCallback(JNIEnv *env){
    /*******部分代码省略********/
    g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
        env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
}

Java端代码

从上面我们看到了最终调用到了 FlutterJNI.handlePlatformMessage 方法:

代码语言:javascript
复制
//engine/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
// Called by native.
// TODO(mattcarroll): determine if message is nonull or nullable
@SuppressWarnings("unused") 
private void handlePlatformMessage(@NonNull final String channel, byte[] message, final int replyId){
    if (platformMessageHandler != null){
        platformMessageHandler.handleMessageFromDart(channel, message, replyId);
    }
}

@UiThread 
public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler){
    ensureRunningOnMainThread();
    this.platformMessageHandler = platformMessageHandler;
}

我们现在找到 FlutterJNI 中的 platformMessageHandler 实例就行。

FlutterActivity中FlutterView的创建

代码语言:javascript
复制
public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {
    private static final String TAG = "FlutterActivity";
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
    private final FlutterActivityEvents eventDelegate;
    private final Provider viewProvider;
    private final PluginRegistry pluginRegistry;

    public FlutterActivity() {
        this.eventDelegate = this.delegate;
        this.viewProvider = this.delegate;
        this.pluginRegistry = this.delegate;
    }
    /*******部分代码省略********/
}

FlutterActivityDelegate 中的委托实现:

代码语言:javascript
复制
public final class FlutterActivityDelegate implements FlutterActivityEvents, Provider, PluginRegistry {
    /*******部分代码省略********/
    public void onCreate(Bundle savedInstanceState) {
        /*******部分代码省略********/
        String[] args = getArgsFromIntent(this.activity.getIntent());
        FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
        this.flutterView = this.viewFactory.createFlutterView(this.activity);
        if (this.flutterView == null) {
            FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
            this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
            this.flutterView.setLayoutParams(matchParent);
            this.activity.setContentView(this.flutterView);
            this.launchView = this.createLaunchView();
            if (this.launchView != null) {
                this.addLaunchView();
            }
        }
        /*******部分代码省略********/
    }
    /*******部分代码省略********/
}

FlutterNativeView中platformMessageHandler的注册

FlutterNativeView 构造函数中我们直接看到 了往 FlutterJNI 中注册的是 FlutterNativeView.PlatformMessageHandlerImpl

代码语言:javascript
复制
public class FlutterNativeView implements BinaryMessenger {
    /*******部分代码省略********/
    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.PlatformMessageHandlerImpl

代码语言:javascript
复制
private final class PlatformMessageHandlerImpl implements PlatformMessageHandler {
    /*******部分代码省略********/
    public void handleMessageFromDart(final String channel, byte[] message, final int replyId) {
        FlutterNativeView.this.assertAttached();
        //通过channel获取注册的BinaryMessageHandler
        BinaryMessageHandler handler = (BinaryMessageHandler)FlutterNativeView.this.mMessageHandlers.get(channel);
        if (handler != null) {
            try {
                ByteBuffer buffer = message == null ? null : ByteBuffer.wrap(message);
                //调用BinaryMessageHandler的onMessage方法
                handler.onMessage(buffer, new BinaryReply() {
                    /*******部分代码省略********/
                });
            } 
            /*******部分代码省略********/
        }
    }
    /*******部分代码省略********/
}

上面根据 channel 获取对应的 BinaryMessagehandler 实例,那么这个实现是通过什么方式在 FlutterNativeView 中的 mMessageHandlers 注册的呢?

代码语言:javascript
复制
//FlutterNativeView
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
    if (handler == null) {
      this.mMessageHandlers.remove(channel);
    } else {
      this.mMessageHandlers.put(channel, handler);
    }
}

我们发现是在调用 FlutterNativeViewsetMessageHandler 方法往 mMessageHandlers 添加 BinaryMessageHandler

BinaryMessagehandler的注册

我们先回头看一下我们自定的 FileProviderPlugin 的实现:

代码语言:javascript
复制
public class FileProviderPlugin implements MethodChannel.MethodCallHandler {
    public final static String NAME = "plugins.flutter.io/file_plugin";
        /*******部分代码省略********/
    public static void registerWith(Registrar registrar, Context context) {
        MethodChannel channel =
                new MethodChannel(registrar.messenger(), NAME);
        FileProviderPlugin instance = new FileProviderPlugin(registrar, context);
        channel.setMethodCallHandler(instance);
    }
}
//FlutterActivity
public final Registrar registrarFor(String pluginKey) {
    //pluginRegistry的实例是FlutterActivityDelegate对象
    return this.pluginRegistry.registrarFor(pluginKey);
}
//FlutterActivityDelegate
public Registrar registrarFor(String pluginKey) {
    return this.flutterView.getPluginRegistry().registrarFor(pluginKey);
}
//FlutterNativeView
public FlutterPluginRegistry getPluginRegistry() {
    return this.mPluginRegistry;
}
//FlutterPluginRegistry
public Registrar registrarFor(String pluginKey) {
    if (this.mPluginMap.containsKey(pluginKey)) {
      throw new IllegalStateException("Plugin key " + pluginKey + " is already in use");
    } else {
      this.mPluginMap.put(pluginKey, (Object)null);
      return new FlutterPluginRegistry.FlutterRegistrar(pluginKey);
    }
}
//FlutterPluginRegistry.FlutterRegistrar
private class FlutterRegistrar implements Registrar {
    public BinaryMessenger messenger() {
            return FlutterPluginRegistry.this.mNativeView;
        }
}
//MethodChannel
public final class MethodChannel {
    public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) {
        //FlutterNativeView.setMessageHandler
        this.messenger.setMessageHandler(this.name, handler == null ? null : new MethodChannel.IncomingMethodCallHandler(handler));
    }
}

BinaryMessageHandler.onMessage

我们找到了 BinaryMessageHandler 的实例对象为 MethodChannel.IncomingMethodCallHandler :

代码语言:javascript
复制
private final class IncomingMethodCallHandler implements BinaryMessageHandler{
    //这里的Handler为我们定义的FileProviderPlugin
    private final MethodChannel.MethodCallHandler handler;
    IncomingMethodCallHandler(MethodChannel.MethodCallHandler handler) {
        this.handler = handler;
    }
    public void onMessage(ByteBuffer message, final BinaryReply reply) {
        MethodCall call = MethodChannel.this.codec.decodeMethodCall(message);
        try {
          //FileProviderPlugin的onMethodCall方法
            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));
        }
    }
}

消息回传到Dart端

我们 Java 在进行事件响应后执行 MethodChannel.Resultsuccess 或者 error 方法将结果传递给 Dart

代码语言:javascript
复制
//FileProviderPlugin的onMethodCall方法
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);
    }
});

上面代码中我们看到最终调用的是 BinaryReplyreply 方法:

BinaryReply 是我们在消息传递过程中 FlutterNativeView.PlatformMessageHandlerImpl 调用 handleMessageFromDart 方法中产生的实例:

代码语言:javascript
复制
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());
                        }
                    }
                }
            });
        }
    /*******部分代码省略********/
}

可以看到当 replay 不为空的时候我们调用的是 FlutterNativeView.this.mFlutterJNI.invokePlatformMessageResponseCallback

代码语言:javascript
复制
 @UiThread
public void invokePlatformMessageResponseCallback(int responseId) {
    this.ensureAttachedToNative();
    this.nativeInvokePlatformMessageResponseCallback(this.nativePlatformViewId, responseId);
}

从而调用 nativenativeInvokePlatformMessageEmptyResponseCallback ,这个方法在 flutterso 加载的时候已经被注册了。

代码语言:javascript
复制
//engine/shell/platform/android/platform_view_android_jni.cc
{
  .name = "nativeInvokePlatformMessageResponseCallback",
  .signature = "(JI)V",
  .fnPtr = reinterpret_cast<void*>(
    &InvokePlatformMessageResponseCallback),
}

对应的 C++ 的方法是 InvokePlatformMessageEmptyResponseCallback

代码语言:javascript
复制
//engine/shell/platform/android/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     //
      );
}

这个方法有调用 PlatfromViewInvokePlatformMessageResponseCallback 方法,也就是:

代码语言:javascript
复制
//engine/shell/platform/android/platform_view_android.cc
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
    JNIEnv* env,
    jint response_id,
    jobject java_response_data,
    jint java_response_position) {
  if (!response_id)
    return;
  //找到存储在pending_responses_当中的PlatformMessageResponse
  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_当中的PlatformMessageResponse
  pending_responses_.erase(it);
  //调用PlatformMessageResponse的Complete方法
  message_response->Complete(
      std::make_unique<fml::DataMapping>(std::move(response)));
}

上面降到过我们在调用 Engine.HandlePlatformMessage 方法时构造的是 PlatformMessageResponse 对象是的 PlatformMessageResponseDart

代码语言:javascript
复制
//engine/lib/ui/window/platform_message_response_dart.h
class PlatformMessageResponseDart : public PlatformMessageResponse {
  FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDart);

 public:
  // Callable on any thread.
  void Complete(std::unique_ptr<fml::Mapping> data) override;
  void CompleteEmpty() override;

 protected:
  explicit PlatformMessageResponseDart(
      tonic::DartPersistentValue callback,
      fml::RefPtr<fml::TaskRunner> ui_task_runner);
  ~PlatformMessageResponseDart() override;

  tonic::DartPersistentValue callback_;
  fml::RefPtr<fml::TaskRunner> ui_task_runner_;
};
//engine/lib/ui/window/platform_message_response_dart.cc
void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
  //判断在构造PlatformMessageResponseDart时的callback是否为空
  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));
        //带着byte_buffer参数调用callback方法,回调到dart端
        tonic::DartInvoke(callback.Release(), {byte_buffer});
      }));
}

总结

事件由 dartC 再到 Java ,相应由 JavaC 再到 dart 的过程可以简单用一下步骤叙述:

1、Application启动的时候加载flutter的so文件; 2、在加载so的时候注册了一系列的相关平台的函数以及操作类; 3、dart调用C层的方法顺便将数据传递给C层; 4、C层调用相关平台的注册的类的对应方法, 5、对应平台进行数据处理并返回数据; 6、事件到达系统底层之后找到事件的相应的句柄进行回调;

在整个源码分析过程不免想了解到系统的更底层,结果引出我也解决不了的问题。哈哈尴尬_~!

真的很头痛。。。。

问题一:

为什么要弄这样的宏定义?

代码语言:javascript
复制
//tonic/dart_class_library.h
#define DART_NATIVE_CALLBACK_STATIC(CLASS, METHOD)          \
static void CLASS##_##METHOD(Dart_NativeArguments args) { \
    tonic::DartCallStatic(&CLASS::METHOD, args);            \
}
//tonic/dart_args.h
template <typename Sig>
void DartCallStatic(Sig func, Dart_NativeArguments args) {
  DartArgIterator it(args, 0);
  using Indices = typename IndicesForSignature<Sig>::type;
  DartDispatcher<Indices, Sig> decoder(&it);
  if (it.had_exception())
    return;
  decoder.Dispatch(func);
}

问题二:

DartInvoke 调用 Dart_Handle 方法就能执行 dart 的函数?Dart_handle 到底在 C 这一层是一个什么样的结构体,它的作用有什么?

代码语言:javascript
复制
//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);
  LogIfError(handle);
  return handle;
}
//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));
}

文章到这里就全部讲述完啦,若有其他需要交流的可以留言哦!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Dart和Java通信的实践
    • Java端ChannelPlugin的创建
      • Java端ChannelPlugin的注册
        • Dart端ChannelPlugin的创建
          • Dart端ChannelPlugin的使用
            • 结果输出
            • 源代码分析
              • Dart端代码
                • MethodChannel信息的封装
                • 信息传到C层
              • C层代码分析
                • Window_sendPlatformMessage方法
                • Engine.HandlePlatformMessage
                • Engine对象的delegate_
                • OnEngineHandlePlatformMessage方法实现
                • PlatformView
                • JNI_OnLoad
              • Java端代码
                • FlutterActivity中FlutterView的创建
                • FlutterNativeView中platformMessageHandler的注册
                • FlutterNativeView.PlatformMessageHandlerImpl
                • BinaryMessagehandler的注册
                • BinaryMessageHandler.onMessage
              • 消息回传到Dart端
              • 总结
                • 问题一:
                  • 问题二:
                  相关产品与服务
                  腾讯云代码分析
                  腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,助力维护团队卓越代码文化。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档