Flutter学习系列(10)— Platform Channel通信(上)

Platform Channel Demo

Flutter是使用Dart语言开发,使用PUB管理package包,目前已经有很多可用的功能包,但是很多情况还是需要和Native代码进行交互,调用一些平台特偶的功能。Flutter提供了platform-specific API来和Native进行交互。

这张是官网上的图,描述了Flutter APP和Host平台之间是通过MethodChannel进行通信的。

Flutter -> Android

下面的代码是官网上的Demo,Flutter App通过MethodChannle调用Android获取电量。

Android提供服务:

Android层定义了一个指定名称的MethodChannel,并且setMethodCallHandler来接收Flutter端的请求。根据请求的方法名调用对应的方法。

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "samples.flutter.dev/battery";

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);

        new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
                new MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall call, Result result) {
                        // Note: this method is invoked on the main thread.
                       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();
                        }
                    }
                });
    }
}
Flutter请求:

而Flutter端,使用同样的channel name创建了一个MethodChannel, 并调用invokeMethod方法告知Android层要调用的方法名和参数,并且可以获取结果。(异步调用)

class _MyHomePageState extends State<MyHomePage> {
  static const platform = const MethodChannel('samples.flutter.dev/battery');

  // Get battery level.
  String _batteryLevel = 'Unknown battery level.';

  Future<void> _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;
    });
  }
}


Android -> Flutter

网上基本都是Flutter调用Android的,基本没有Android调用Flutter方法的,甚至有的人写的blog说MethodChannle使用场景是Flutter调用Android。 其实Channel是双向的。 只是Android调用Flutter可能有一个问题,就是调用时FlutterView可能还没有初始化好。(经过测试,如果未初始化好,Android端会收到未实现的错误。)

Flutter提供服务:

代码和前面Android提供服务时基本一样的。但是_onMethodCall方法中并没有Result参数告知执行结果。

class FlutterTestChannel{

  static const platform2 = const MethodChannel('com.test.flutter/common');

  _FlutterPrintHandler() {
    platform2.setMethodCallHandler(_onMethodCall);
  }

  Future<void> _onMethodCall(MethodCall call) {
    switch(call.method) {
      case 'print':
        platform.invokeMethod("d", {"tag": "MyApp", "log": "Dart receive android call! "});
        break;
      default:
        throw UnimplementedError('${call.method} was invoked but isn't implemented by PlatformViewsService');
    }
    return null;
  }
Android请求:

Android端请求和之前Flutter也基本一致, 但是比Dart多了一个Result回调。

    @Override
    protected void onResume() {
        super.onResume();

        // android->Flutter
        MethodChannel channel = new MethodChannel(getFlutterView(), "com.test.flutter/common");
        channel.invokeMethod("print", "123", new MethodChannel.Result() {
            @Override
            public void success(Object result) {

            }

            @Override
            public void error(String errorCode, String errorMessage, Object errorDetails) {

            }

            @Override
            public void notImplemented() {

            }
        });
    }

从上面代码可以看出:
– Channle需要有一个唯一的名字
– Channel通信是双向的
– Flutter约定了通信的规则


BinaryMessenger

Facility for communicating with Flutter using asynchronous message passing with binary messages.

之前在介绍FlutterView的时候我们有了解过它实现了BinaryMesenger接口,这个接口定义如何同Flutter进行通信。下面是相关的类图。
![](点击查看大图)

主要包括4部分
1. BinaryMessenger: 定义了通信接口和格式
2. 上面的FlutterView等4个类实现了BinaryMessenger接口,他们是实际负责和Flutter进行数据交互的类
3. 中间黄色的3种Channel,内部都是使用BinaryMessenger来进行交互,只是进行了封装,适用于不同场景。
4. 最下面2层是用于把低层二进制数据转换为各自Channle使用的数据。

因为通信是双向的,所以这个接口定义了Send方法用来从Android向Flutter发送数据,并且通过BinaryReply内部接口接收Flutter的响应。同样,当收到Flutter发送过来的数据时,通过BinaryMessageHandler接口进行回应。通信过程数据都是使用ByteBuffer。当然最重要的是需指定发到那个channel。 需要注意的是,数据发送必须在主线程


向Flutter发送数据

DartMessenger

从类图中可以看到,一共有4个类实现了BinaryMessage接口,也就是说这4个类都具有发送消息给Flutter的能力。去看一下内部实现发现调用关系是:FlutterView --> FlutterNativeView --> DartExecute --> DartMessenger。真正实现调用的是DartMessenger(之前1.3版本中,我记得FlutterNativeView中是自己实现的调用,现在看最新的1.7.8已经都是由DartMessenger实现了)。最终通过FlutterJNI调用到了C++的代码。

创建

 public DartExecutor(@NonNull FlutterJNI flutterJNI) {
    this.flutterJNI = flutterJNI;
    this.messenger = new DartMessenger(flutterJNI);
    messenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
  }

DartMessenger是在创建DartExecutor时创建的,之前Flutter初始化流程中我们提到过DartExecutor是在创建FlutterView时创建的。 这里创建DartMessenger时设置了一个isolateChannelMessageHandler来接收Flutter通过isolate channel发送的数据。

结构

private final FlutterJNI flutterJNI;

// 记录从Flutter接收对应channel数据的Handler
private final Map<String, BinaryMessenger.BinaryMessageHandler> messageHandlers;

// 记录发送给Fullter数据的回应的接口
private final Map<Integer, BinaryMessenger.BinaryReply> pendingReplies;
private int nextReplyId = 1;

在DartMessenger中定义了2个Map,用来存放所有的channel的BinaryMessageHandlerBinaryReply。所以setMessageHandler实现很简单:

public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
    if (handler == null) {
      Log.v(TAG, "Removing handler for channel '" + channel + "'");
      messageHandlers.remove(channel);
    } else {
      Log.v(TAG, "Setting handler for channel '" + channel + "'");
      messageHandlers.put(channel, handler);
    }
  }

发送数据

   public void send(
      @NonNull String channel,
      @Nullable ByteBuffer message,
      @Nullable BinaryMessenger.BinaryReply callback
  ) {
    Log.v(TAG, "Sending message with callback over channel '" + channel + "'");
    int replyId = 0;
    if (callback != null) {
      replyId = nextReplyId++;
      pendingReplies.put(replyId, callback);
    }
    if (message == null) {
      flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
    } else {
      flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
    }
  }

我们可以看到,如果callback不为空,每次发送一个数据,都有一个replyId (因为发送数据必须在UI线程,所以不需要进行同步)并且添加到pendingReplies中, 否则传0。最终调用flutterJNI来发送消息给C++层。下面是Native层的调用时序图 (这个是用markdown画的效果不太行:joy:):


PaltformView

其中PlatformView::DispatchPlatformMessage方法接收的是PlatformMessage参数, 所以这里对Java层传入数据进行了转换。 其中response_id就是Java层的replyId, 如果为0不创建PlatformMessageResponseAndroid, 用于接收调用结果。

void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env,
                                                  std::string name,
                                                  jobject java_message_data,
                                                  jint java_message_position,
                                                  jint response_id) {
  uint8_t* message_data =
      static_cast<uint8_t*>(env->GetDirectBufferAddress(java_message_data));
  std::vector<uint8_t> message =
      std::vector<uint8_t>(message_data, message_data + java_message_position);

  // 创建了一个PlatformMessageResponseAndroid对象,其中java_object_是FlutterJNI对象
  fml::RefPtr<flutter::PlatformMessageResponse> response;
  if (response_id) {
    response = fml::MakeRefCounted<PlatformMessageResponseAndroid>(
        response_id, java_object_, task_runners_.GetPlatformTaskRunner());
  }

  // 创建PlatformMessage对象
  PlatformView::DispatchPlatformMessage(
      fml::MakeRefCounted<flutter::PlatformMessage>(
          std::move(name), std::move(message), std::move(response)));
Shell

Shell在调用Engine时,使用了UI线程。

void Shell::OnPlatformViewDispatchPlatformMessage(
    fml::RefPtr<PlatformMessage> message) {
  FML_DCHECK(is_setup_);
  FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

  task_runners_.GetUITaskRunner()->PostTask(
      [engine = engine_->GetWeakPtr(), message = std::move(message)] {
        if (engine) {
          engine->DispatchPlatformMessage(std::move(message));
        }
      });
}
Engine
void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {

  // 处理系统指定channel数据
  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;
  }

    // 处理其他channle数据
  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));
}

从代码中可以看到一开始检查这个消息是否发给系统channel的,从定义中可以看到,系统目前有10个定义好的channel。

// 在Engine中
static constexpr char kAssetChannel[] = "flutter/assets";
static constexpr char kLifecycleChannel[] = "flutter/lifecycle";
static constexpr char kNavigationChannel[] = "flutter/navigation";
static constexpr char kLocalizationChannel[] = "flutter/localization";
static constexpr char kSettingsChannel[] = "flutter/settings";
static constexpr char kIsolateChannel[] = "flutter/isolate";

//其他engine/shell/platform/glfw/目录下的文件中
static constexpr char kFlutterPlatformChannel[] = "flutter/platform";
static constexpr char kTextInputChannel[] = "flutter/textinput";
static constexpr char kKeyEventChannel[] = "flutter/keyevent";
static constexpr char kAccessibilityChannel[] = "flutter/accessibility";

前面讲DartMessenger的时候有提到调用了 messenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler); 其实就是注册了对应的监听来接受Flutter从isolate发来的数据。而之前介绍FlutterView初始化的时候也见到了创建对应Channel的代码:

// Create all platform channels
 navigationChannel = new NavigationChannel(dartExecutor);
keyEventChannel = new KeyEventChannel(dartExecutor);
lifecycleChannel = new LifecycleChannel(dartExecutor);
localizationChannel = new LocalizationChannel(dartExecutor);
platformChannel = new PlatformChannel(dartExecutor);
systemChannel = new SystemChannel(dartExecutor);
settingsChannel = new SettingsChannel(dartExecutor);

最后Engine把消息交给了Dart的Runtime去处理:

void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
  if (!dart_state)
    return;
  tonic::DartState::Scope scope(dart_state);

  // 把java/c++的数据转换为Dart的数据类型
  Dart_Handle data_handle =
      (message->hasData()) ? ToByteData(message->data()) : Dart_Null();
  if (Dart_IsError(data_handle))
    return;

  int response_id = 0;
  if (auto response = message->response()) {
    response_id = next_response_id_++;
    pending_responses_[response_id] = response;
  }

  // 传递给Dart
  tonic::LogIfError(
      tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage",
                             {tonic::ToDart(message->channel()), data_handle,
                              tonic::ToDart(response_id)}));
}

到这里消息被发送给了Dart去进行处理。注意,respones并没有传给dart,而是传递了response_id, 本地记录了id和response对象的关系。

从github下载的Dart和Flutter Engine中并没有DartInvokeField 定义,从网上搜索了下发现fuchsia的源码中有
https://fuchsia.googlesource.com/tonic/+/master/logging/dart_invoke.cc 所以不清楚具体实现,但是可以推断是调用了Dart的 _dispatchPlatformMessage 方法,所以搜索这个方法名就行了。 Flutter中有很多这样的调用。


Dart接收消息

通过搜索发现这个Dart方法在:engine/lib/ui/hooks.dart中。

@pragma('vm:entry-point')
void _dispatchPlatformMessage(String name, ByteData data, int responseId) {
  if (window.onPlatformMessage != null) {
    _invoke3<String, ByteData, PlatformMessageResponseCallback>(
      window.onPlatformMessage,
      window._onPlatformMessageZone,
      name,
      data,
      (ByteData responseData) {
        window._respondToPlatformMessage(responseId, responseData);
      },
    );
  } else {
    window._respondToPlatformMessage(responseId, null);
  }
}

可以看到数据已经转换成了Dart的类型,并且进入到了Dart的执行环境。那么我们可以调试一下我们的程序,最终执行的堆栈如下:

可以看到Dart程序的入口就是我们从源码中找打这个方法。这里主要调用了_invoke3这个方法。看注释就是在给定的zone中执行回调方法,这个回调方法的参数也一起传递了。 简单了解了下Zones,最常见的使用Zone的情况是在异步代码中处理错误或异常信息。 这里我们先忽略这个。

/// Invokes [callback] inside the given [zone] passing it [arg1], [arg2] and [arg3].
void _invoke3<A1, A2, A3>(void callback(A1 a1, A2 a2, A3 a3), Zone zone, A1 arg1, A2 arg2, A3 arg3) {
  if (callback == null)
    return;

  assert(zone != null);

  if (identical(zone, Zone.current)) {
    callback(arg1, arg2, arg3);
  } else {
    zone.runGuarded(() {
      callback(arg1, arg2, arg3);
    });
  }
}

所以实际执行的方法是 window.onPlatformMessage这个callback方法,在engine/lib/ui/window.dart中定义如下

 PlatformMessageCallback get onPlatformMessage => _onPlatformMessage;
  PlatformMessageCallback _onPlatformMessage;
  Zone _onPlatformMessageZone;
  set onPlatformMessage(PlatformMessageCallback callback) {
    _onPlatformMessage = callback;
    _onPlatformMessageZone = Zone.current;
  }

看起来有点复杂,其实_onPlatformMessage 是Window的一个私有成员变量,set和get提供了对私有成员的读写。这里调用的_onPlatformMessage其实是一个函数指针, 是通过set设置进来的。

/// Signature for [Window.onPlatformMessage].
typedef PlatformMessageCallback = void Function(String name, ByteData data, PlatformMessageResponseCallback callback);

看看第三个参数、也是一个函数指针

/// [Window.onPlatformMessage].
typedef PlatformMessageResponseCallback = void Function(ByteData data);

这个函数指针指向的是Windows下的_respondToPlatformMessage函数,而这个函数调用的是C++层的代码,最终对应到C++层Window._RespondToPlatformMessage方法

  void _respondToPlatformMessage(int responseId, ByteData data)
      native 'Window_respondToPlatformMessage';


回调Dart的处理函数

从前面堆栈看,最终是回调到了我们_onMethodCall 方法。 因为我们调用了MethodChannel.setMethodCallHandler 方法。

 // platform_channel.dart
  void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
    binaryMessenger.setMessageHandler(
      name,
      handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
    );
  }

  const MethodChannel(this.name, [this.codec = const StandardMethodCodec(), this.binaryMessenger = defaultBinaryMessenger ])
    : assert(name != null),
      assert(binaryMessenger != null),
      assert(codec != null);

从上面可以看出,实际是调用了_DefaultBinaryMessenger类的方法

// binary_messenger.dart

/// The default instance of [BinaryMessenger].
///
/// This is used to send messages from the application to the platform, and
/// keeps track of which handlers have been registered on each channel so
/// it may dispatch incoming messages to the registered handler.
const BinaryMessenger defaultBinaryMessenger = _DefaultBinaryMessenger._();

  @override
  void setMessageHandler(String channel, MessageHandler handler) {
    if (handler == null)
      _handlers.remove(channel);
    else
      _handlers[channel] = handler;
  }

它也实现了handlePlatformMessage方法,逻辑也很简单。

@override
  Future<void> handlePlatformMessage(
    String channel,
    ByteData data,
    ui.PlatformMessageResponseCallback callback,
  ) async {
    ByteData response;
    try {
      final MessageHandler handler = _handlers[channel]; //找到对用channle的handler
      if (handler != null)
        response = await handler(data); //调用handler处理方法并返回结果
    } catch (exception, stack) {
      FlutterError.reportError(FlutterErrorDetails(
        exception: exception,
        stack: stack,
        library: 'services library',
        context: ErrorDescription('during a platform message callback'),
      ));
    } finally {
      callback(response); //通过callback把结果返回给调用方
    }
  }


监听和回调

目前消息已经从Android发送到了Dart, 而Dart的Handler也已经准备好了,就看看他们是怎么联系起来的,也就是前面的Window.onPlatformMessage是如何被设置成 BinaryMessenger.handlePlatformMessage的。 通过搜索代码终于找到原来在flutter_sdk/packages/flutter/lib/src/servicesbinding.dart文件中,engine的源码中是没有的。

/// Listens for platform messages and directs them to the [defaultBinaryMessenger].
mixin ServicesBinding on BindingBase {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;
    window
      ..onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;  //就是这里把监听和回调关联起来了。
    initLicenses();
  }

  /// The current [ServicesBinding], if one has been created.
  static ServicesBinding get instance => _instance;
  static ServicesBinding _instance;
}

具体这个ServicesBinding是什么时候创建目前不太清楚,但是因为继承与BindingBase, 从构造函数看,应该是在Framework初始化时就设置了。

abstract class BindingBase {
  /// Default abstract constructor for bindings.
  ///
  /// First calls [initInstances] to have bindings initialize their
  /// instance pointers and other state, then calls
  /// [initServiceExtensions] to have bindings initialize their
  /// observatory service extensions, if any.
  BindingBase() {
    developer.Timeline.startSync('Framework initialization');

    assert(!_debugInitialized);
    initInstances();
    assert(_debugInitialized);

    assert(!_debugServiceExtensionsRegistered);
    initServiceExtensions();
    assert(_debugServiceExtensionsRegistered);

    developer.postEvent('Flutter.FrameworkInitialization', <String, String>{});

    developer.Timeline.finishSync();
  }


结果返回

从前面分析知道,Dart方法的结果会通过callback返回给调用方,而这个callback直接指向了C++的Window._RespondToPlatformMessage方法。

void RespondToPlatformMessage(Dart_Handle window,
                              int response_id,
                              const tonic::DartByteData& data) {
  if (Dart_IsNull(data.dart_handle())) {
    UIDartState::Current()->window()->CompletePlatformMessageEmptyResponse(
        response_id);
  } else {
    // TODO(engine): Avoid this copy.
    const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
    UIDartState::Current()->window()->CompletePlatformMessageResponse(
        response_id,
        std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()));
  }
}

// 根据response_id 找到对用的 `PlatformMessageResponse`
void Window::CompletePlatformMessageResponse(int response_id,
                                             std::vector<uint8_t> data) {
  if (!response_id)
    return;
  auto it = pending_responses_.find(response_id);
  if (it == pending_responses_.end())
    return;
  auto response = std::move(it->second);
  pending_responses_.erase(it);
  response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
}

根据response_id 找到PlatformView中之前保存的 PlatformMessageResponseAndroid,执行Complete方法。

void PlatformMessageResponseAndroid::Complete(
    std::unique_ptr<fml::Mapping> data) {
  platform_task_runner_->PostTask(
      fml::MakeCopyable([response = response_id_,               //
                         weak_java_object = weak_java_object_,  //
                         data = std::move(data)                 //
  ]() {
        // We are on the platform thread. Attempt to get the strong reference to
        // the Java object.
        auto* env = fml::jni::AttachCurrentThread();
        auto java_object = weak_java_object.get(env);

        if (java_object.is_null()) {
          // The Java object was collected before this message response got to
          // it. Drop the response on the floor.
          return;
        }

        // Convert the vector to a Java byte array.
        fml::jni::ScopedJavaLocalRef<jbyteArray> data_array(
            env, env->NewByteArray(data->GetSize()));
        env->SetByteArrayRegion(
            data_array.obj(), 0, data->GetSize(),
            reinterpret_cast<const jbyte*>(data->GetMapping()));

        // Make the response call into Java.
        FlutterViewHandlePlatformMessageResponse(env, java_object.obj(),
                                                 response, data_array.obj());
      }));
}

注释写的很清楚,先进行数据转换,然后把结果返回给Java层。 其中java_object是FlutterJNI对象。

static jmethodID g_handle_platform_message_response_method = nullptr;
void FlutterViewHandlePlatformMessageResponse(JNIEnv* env,
                                              jobject obj,
                                              jint responseId,
                                              jobject response) {
  env->CallVoidMethod(obj, g_handle_platform_message_response_method,
                      responseId, response);
  FML_CHECK(CheckException(env));
}

这里调用的是g_handle_platform_message_response_method, 定义在了engine/shell/platform/android/platform_view_android_jni.cc

 g_handle_platform_message_response_method = env->GetMethodID(
      g_flutter_jni_class->obj(), "handlePlatformMessageResponse", "(I[B)V");

最终调用到FlutterJNI

  private void handlePlatformMessageResponse(int replyId, byte[] reply) {
    if (platformMessageHandler != null) {
      platformMessageHandler.handlePlatformMessageResponse(replyId, reply);
    }
    // TODO(mattcarroll): log dropped messages when in debug mode (https://github.com/flutter/flutter/issues/25391)
  }

而在创建FlatterView的时候会设置这个Handler,

  public void onAttachedToJNI() {
    Log.v(TAG, "Attached to JNI. Registering the platform message handler for this Dart execution context.");
    flutterJNI.setPlatformMessageHandler(messenger);
  }

用的就是messenger, 这个messenger就是DartMessenger, 这个根据之前的replyId,找到对应的BinaryReply 。

  @Override
  public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) {
    Log.v(TAG, "Received message reply from Dart.");
    BinaryMessenger.BinaryReply callback = pendingReplies.remove(replyId);
    if (callback != null) {
      try {
        Log.v(TAG, "Invoking registered callback for reply from Dart.");
        callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message reply handler", ex);
      }
    }
  }

对于我们的例子来说,因为使用的是MethodChannle,他继承了BinaryReply接口, 重写了reply方法。

    private final class IncomingResultHandler implements BinaryReply {
        private final Result callback;

        IncomingResultHandler(Result callback) {
            this.callback = callback;
        }

        @Override
        @UiThread
        public void reply(ByteBuffer reply) {
            try {
                if (reply == null) {
                    callback.notImplemented();
                } else {
                    try {
                        callback.success(codec.decodeEnvelope(reply));
                    } catch (FlutterException e) {
                        callback.error(e.code, e.getMessage(), e.details);
                    }
                }
            } catch (RuntimeException e) {
                Log.e(TAG + name, "Failed to handle method call result", e);
            }
        }
    }


总结

这一篇主要以MethodChannel的例子分析了从Android调用Flutter方法并返回结果的整个流程。其实整体看来逻辑很简单:
1. Android和Flutter两端的各自BinaryMessenger实例内部都维护了channel name 和 channel 的对应关系
2. 通关channel name 让两端建立起了联系
3. 数据经过了JAVA — C++ — Dart的转换, 数据格式是可以定义的
4. send方法都如果设置了回调, 都会分配一个replayId,保证请求的结果可以返回
5. 消息发送都是在UI线程进行的


流程图:

0

如果本文对您有帮助,可以扫描下方二维码打赏!您的支持是我的动力!
微信打赏 支付宝打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注