flutter通信机制-MethodChannel

流程图如下:


流程图

1、发送和接收

1.1 flutter端发送消息方式是:

class InteractUtil {
    static const platform = const MethodChannel("com.yourname.yourname/method");
      
    factory InteractUtil() => _getInstance();
    
    static InteractUtil get instance => _getInstance();
    static InteractUtil _instance;
    
    InteractUtil._internal();
  
    static InteractUtil _getInstance() {
        if (_instance == null) {
        _instance = new InteractUtil._internal();
        }
        return _instance;
    }
    
    Future<String> customMethodName(
    String parameter1, String parameter2) async {
        Future<String> result;
        try {
            print("customMethodName $parameter1 and $parameter2");
            result = await platform.invokeMethod("customMethodName", {
                "parameter1": parameter1,
                "parameter2": parameter2,
            });
        } on PlatformException catch (e) {
            print(e.toString());
        }
        return result;
    }
}

1.2 Android端接收消息的方式是:

class MainActivity : FlutterActivity() {
    val METHOD_CHANNEL = "com.yourname.yourname/method"
    override fun onCreate(savedInstanceState: Bundle?) {
        FlutterMain.startInitialization(this)
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)

        MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler { p0, p1 ->
        Log.d(TAG, "method is ${p0.method}")
            when (p0.method) {
                "customMethodName" -> {
                    val parameter1 = p0.argument<String>("parameter1") as String
                    val parameter2 = p0.argument<String>("parameter2") as String
                }
            }
        }
    }
}

p0是MethodCall类型,p1是Result类型

两端的MethodChannel name必须一致,另外flutter端调用invokeMethod 的方法名称要在Android或iOS端有定义。

2、flutter端

2.1 MethodChannel初始化

MethodChannel构造函数如下:

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

先初始化了一个StandardMethodCodec对象,看看构造函数,如下:

const StandardMethodCodec([this.messageCodec = const StandardMessageCodec()]);

StandardMethodCodec实现了MethodCodec接口

构造函数中又初始化了一个StandardMessageCodec对象,StandardMessageCodec实现了MessageCodec接口。

2.2 _binaryMessenger初始化

MethodChannel初始化成员变量的时候,会初始化_binaryMessenger参数,也就是set,看看定义:

BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; // ignore: deprecated_member_use_from_same_package
final BinaryMessenger _binaryMessenger;

此处的binaryMessenger是null,但是下次当需要get的时候会走defaultBinaryMessenger参数,这个参数来自哪里呢?在src\services\binary_messenger.dart文件中定义了get方法:

BinaryMessenger get defaultBinaryMessenger {
  return ServicesBinding.instance.defaultBinaryMessenger;
}

看看ServicesBinding的defaultBinaryMessenger怎么初始化的:

packages\flutter\lib\src\services\binding.dart\ServicesBinding

mixin ServicesBinding on BindingBase {
    @override
    void initInstances() {
        _instance = this;
        _defaultBinaryMessenger = createBinaryMessenger();
        window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
        SystemChannels.system.setMessageHandler(handleSystemMessage);
    }
    BinaryMessenger get defaultBinaryMessenger =>  _defaultBinaryMessenger;
    BinaryMessenger _defaultBinaryMessenger;
}

同一个文件中看看createBinaryMessenger方法:

BinaryMessenger createBinaryMessenger() {
    return const _DefaultBinaryMessenger._();
}

创建了_DefaultBinaryMessenger对象,其继承自BinaryMessenger。

2.3 window.onPlatformMessage

将defaultBinaryMessenger.handlePlatformMessage方法设置给window.onPlatformMessage。也就是_DefaultBinaryMessenger的handlePlatformMessage方法。

看看onPlatformMessage的定义:

lib\ui\window.dart\Window

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

这里的callback就是_DefaultBinaryMessenger的handlePlatformMessage方法。

看看这个方法的定义:

packages\flutter\lib\src\services\binding.dart\_DefaultBinaryMessenger

@override
Future<void> handlePlatformMessage(String channel,ByteData data,ui.PlatformMessageResponseCallback callback,) async {
    ByteData response;
    try {
      final MessageHandler handler = _handlers[channel];
      if (handler != null) {
        response = await handler(data);
      } else {
        ui.channelBuffers.push(channel, data, callback);
        callback = null;
      }
    } catch (exception, stack) {
    } finally {
      if (callback != null) {
        callback(response);
      }
    }
}

onPlatformMessage接收到特定平台的消息时,就会调用到handlePlatformMessage方法。window.onPlatformMessage是一个全局的变量,在很多消息传递的地方都可以调用。

2.4 setMessageHandler

handleSystemMessage在ServicesBinding中,可以被其他Binding重载,如下:

Future<void> handleSystemMessage(Object systemMessage) async { }

看看system变量:

packages\flutter\lib\src\services\system_channels.dart\SystemChannels

static const BasicMessageChannel<dynamic> system = BasicMessageChannel<dynamic>(
  'flutter/system',
  JSONMessageCodec(),
);

通过JSON来编解码消息。JSONMessageCodec实现了MessageCodec接口。

2.5 MethodChannel.invokeMethod

我们自己的dart调用invokeMethod方法发送消息,如下:

Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async {
    assert(method != null);
    final ByteData result = await binaryMessenger.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;
}

其实还有invokeListMethod和invokeMapMethod方法,最终都是执行到invokeMethod方法。

binaryMessenger对应的类是_DefaultBinaryMessenger,codec对应的是StandardMethodCodec类。

2.5.1 数据编码

此处先将方法和参数通过MethodCall封装,然后在StandardMethodCodec中编码,看看具体怎么编码的:

StandardMethodCodec

@override
ByteData encodeMethodCall(MethodCall call) {
    final WriteBuffer buffer = WriteBuffer();
    messageCodec.writeValue(buffer, call.method);
    messageCodec.writeValue(buffer, call.arguments);
    return buffer.done();
}

看看WriteBuffer的构造函数:

packages\flutter\lib\src\foundation\serialization.dart\WriteBuffer

WriteBuffer() {
    _buffer = Uint8Buffer();
    _eightBytes = ByteData(8);
    _eightBytesAsList = _eightBytes.buffer.asUint8List();
}

WriteBuffer构造函数中初始化的Uint8Buffer类型,可以看做是一个List<int>,而ByteData可以看做是一个byte数组,长度为8。

messageCodec是一个StandardMessageCodec类型,看看他的writeValue方法:

void writeValue(WriteBuffer buffer, dynamic value) {
    writeSize(buffer, value.length);
    buffer.putxxx(_valueFloat64);
}

根据value的不同类型,put到不同的集合中。如果value是int类型,就放到_buffer中;如果是float类型,占8位,放到_eightBytes中;而我们的method是String类型,将其转换为utf-8之后,转成byte数组放到_buffer中。对于value占位大于1的,先写占用长度,再写占用值。不同的长度对应不同的数字,如下:

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;

看done方法:

packages\flutter\lib\src\foundation\serialization.dart\WriteBuffer

ByteData done() {
    final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes);
    _buffer = null;
    return result;
}

其实是将刚才write进去的数据转成一个byte数组返回,这个数组的代表就是ByteData对象。

2.6 发送消息(binaryMessenger.send)

上面提到binaryMessenger是_DefaultBinaryMessenger类型,看看里面的send方法:

@override
Future<ByteData> send(String channel, ByteData message) {
    final MessageHandler handler = _mockHandlers[channel];
    if (handler != null)
      return handler(message);
    return _sendPlatformMessage(channel, message);
}

这里的_mockHandlers是Map<String, MessageHandler>类型,而MessageHandler的类型却是:

typedef MessageHandler = Future<ByteData> Function(ByteData message);

一个函数。所以send方法最开始从这个Map中查找channel名称对应的函数是否存在,存在的话,直接调用,而不用执行后面的方法了。明显的,这里需要调用_sendPlatformMessage方法:

Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    final Completer<ByteData> completer = Completer<ByteData>();
    ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
        completer.complete(reply);
    });
    return completer.future;
}

看看ui.window的sendPlatformMessage方法:

ui\window.dart\Window

void sendPlatformMessage(String name,ByteData data,PlatformMessageResponseCallback callback) {
    final String error = _sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
}
String _sendPlatformMessage(String name,
                          PlatformMessageResponseCallback callback,
                          ByteData data) native 'Window_sendPlatformMessage';

最终调用到了native的Window_sendPlatformMessage方法:

ui\window\window.cc\Window

void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
    {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
}

void _SendPlatformMessage(Dart_NativeArguments args) {
  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();

  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();
}

DartCallStatic方法将args转换成了dart可处理的变量类型。

2.6.1 预定义返回

这里response对应的是PlatformMessageResponseDart类型,看看这个方法:

ui\window\platform_message_response_dart.cc\PlatformMessageResponseDart

mMessageResponseDart::PlatformMessageResponseDart(
    tonic::DartPersistentValue callback,
    fml::RefPtr<fml::TaskRunner> ui_task_runner)
    : callback_(std::move(callback)),
      ui_task_runner_(std::move(ui_task_runner)) {}

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});
      }));
}

调用完成时会回调到这里,最终会调用callback对应的闭包。

2.6.3 处理消息(HandlePlatformMessage)

接下来执行HandlePlatformMessage,看看一系列调用堆栈:

runtime\runtime_controller.cc

// |WindowClient|
void RuntimeController::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
  client_.HandlePlatformMessage(std::move(message));
}

shell\common\engine.cc

void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
  if (message->channel() == kAssetChannel) {
    HandleAssetPlatformMessage(std::move(message));
  } else {
    delegate_.OnEngineHandlePlatformMessage(std::move(message));
  }
}

shell\common\shell.cc

// |Engine::Delegate|
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));
        }
    });
}

view对应类,以Android平台为例:

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

接下来调用FlutterViewHandlePlatformMessage方法,这个方法对应的是Java jni注册的方法,看看方法体:

shell\platform\android\platform_view_android_jni.cc

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注册的地方:

shell\platform\android\platform_view_android_jni.cc

g_handle_platform_message_method = env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage","(Ljava/lang/String;[BI)V");

2.6.4 到系统平台处理消息

对应Java中的handlePlatformMessage方法,参数是String,byte数组,int。看看handlePlatformMessage方法:

shell\platform\android\io\flutter\embedding\engine\FlutterJNI.java

private void handlePlatformMessage(
  @NonNull final String channel, byte[] message, final int replyId) {
    if (platformMessageHandler != null) {
      platformMessageHandler.handleMessageFromDart(channel, message, replyId);
    }
}

在FlutterJNI类中,通过setPlatformMessageHandler方法设置platformMessageHandler对象,看看是哪里设置的。还记得FlutterNativeView构造函数中,最后调用了attach方法,如下:

shell\platform\android\io\flutter\view\FlutterNativeView.java

private void attach(FlutterNativeView view, boolean isBackgroundView) {
    mFlutterJNI.attachToNative(isBackgroundView);
    dartExecutor.onAttachedToJNI();
}

看看onAttachedToJNI方法:

shell\platform\android\io\flutter\embedding\engine\dart\DartExecutor.java

public void onAttachedToJNI() {
    flutterJNI.setPlatformMessageHandler(dartMessenger);
}

这里的dartMessenger对应的是DartMessenger类,所以此处的platformMessageHandler对应的是DartMessenger对象。另外在dartMessenger初始化的时候,会调用setMessageHandler方法:

shell\platform\android\io\flutter\embedding\engine\dart\DartExecutor.java

private final BinaryMessenger.BinaryMessageHandler isolateChannelMessageHandler =
  new BinaryMessenger.BinaryMessageHandler() {
    @Override
    public void onMessage(ByteBuffer message, final BinaryReply callback) {
      isolateServiceId = StringCodec.INSTANCE.decodeMessage(message);
      if (isolateServiceIdListener != null) {
        isolateServiceIdListener.onIsolateServiceIdAvailable(isolateServiceId);
      }
    }
};

public DartExecutor(@NonNull FlutterJNI flutterJNI, @NonNull AssetManager assetManager) {
    this.flutterJNI = flutterJNI;
    this.assetManager = assetManager;
    this.dartMessenger = new DartMessenger(flutterJNI);
    dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
    this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
}

这里的isolateChannelMessageHandler对应的是BinaryMessenger.BinaryMessageHandler类,channel name是flutter/isolate。在DartMessenger中,通过setMessageHandler方法将channel name和MessageHandler放到了messageHandlers这个Map对象中。如下:

@Override
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);
    }
}

回到开始调用handleMessageFromDart的地方,这个方法在DartMessenger中有定义:

shell\platform\android\io\flutter\embedding\engine\dart\DartMessenger.java

@Override
public void handleMessageFromDart(
  @NonNull final String channel, @Nullable byte[] message, final int replyId) {
    Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
    BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
    if (handler != null) {
      try {
        Log.v(TAG, "Deferring to registered handler to process message.");
        final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
        handler.onMessage(buffer, new Reply(flutterJNI, replyId));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message listener", ex);
        flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
      }
    } else {
      Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message.");
      flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
    }
}

从messageHandlers这个Map中取出channel name对应的MessageHandler,然后回调到他的onMessage方法中。

3、Android端

3.1 MethodChannel

Android端最开始注册接收的代码如下:

MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler {
}

flutterView其实是FlutterActivityDelegate中的FlutterView flutterView对象,而FlutterView实现了BinaryMessenger接口。

看看MethodChannel构造函数:

MethodChannel

public MethodChannel(BinaryMessenger messenger, String name) {
    this(messenger, name, StandardMethodCodec.INSTANCE);
}

public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
    this.messenger = messenger;
    this.name = name;
    this.codec = codec;
}

这里的messenger就是FlutterView类型。

3.2 MethodCallHandler

接下来看看MethodChannel的setMethodCallHandler方法:

shell\platform\android\io\flutter\plugin\common\MethodChannel.java

public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
    messenger.setMessageHandler(name,handler == null ? null : new IncomingMethodCallHandler(handler));
}

到这里,我们的handler其实是在我们的MainActivity中定义了的,只不过lamada表达式将类名隐藏,只显示了闭包接收的参数。完整的形式是:

MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler(MethodChannel.MethodCallHandler { p0, p1 ->
}

3.2.1 IncomingMethodCallHandler

最终通过IncomingMethodCallHandler将我们的MethodCallHandler初始化给IncomingMethodCallHandler类的handler对象,如下:

private final class IncomingMethodCallHandler implements BinaryMessageHandler {
    private final MethodCallHandler handler;

    IncomingMethodCallHandler(MethodCallHandler handler) {
      this.handler = handler;
    }
    public void onMessage(ByteBuffer message, final BinaryReply reply) {
      
    }
}

这里的codec在MethodChannel构造的时候默认为StandardMethodCodec实例。

看看messenger所属的FlutterView中的setMessageHandler函数:

FlutterView

public void setMessageHandler(String channel, BinaryMessageHandler handler) {
    mNativeView.setMessageHandler(channel, handler);
}

这里的handler就是IncomingMethodCallHandler,看看setMessageHandler的setMessageHandler方法:

FlutterNativeView

public void setMessageHandler(String channel, BinaryMessageHandler handler) {
    dartExecutor.getBinaryMessenger().setMessageHandler(channel, handler);
}

3.3 DefaultBinaryMessenger

又回到dartExecutor这里了,getBinaryMessenger()方法对应的是DefaultBinaryMessenger,看看他的setMessageHandler方法:

public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
  messenger.setMessageHandler(channel, handler);
}

DefaultBinaryMessenger构造的时候,有初始化一个messenger对象,他对应的是DartMessenger,就可以发现最终是向他所属的Map中添加channel对应的BinaryMessenger.BinaryMessageHandler。

messageHandlers.put(channel, handler);

这里终于将dart发送过来的消息和java层的注册对接起来了。

3.4 MethodCallHandler中处理消息

handleMessageFromDart中通过handler执行的onMessage方法,即IncomingMethodCallHandler类中的onMessage方法,通过StandardMethodCodec解码之后得到MethodCall对象,然后回调给MainActivity里面MethodCallHandler的onMethodCall方法。

IncomingMethodCallHandler直接处理dart来的数据,并分发

public void onMessage(ByteBuffer message, final BinaryReply reply) {
    final MethodCall call = codec.decodeMethodCall(message);
    handler.onMethodCall(call,new Result() {
        @Override
        public void success(Object result) {
            reply.reply(codec.encodeSuccessEnvelope(result));
        }
        
        @Override
        public void error(String errorCode, String errorMessage, Object errorDetails) {
            reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
        }
    });
}

MainActicity注册Handler之后接收数据,处理数据,完成之后返回

MethodChannel(flutterView, METHOD_CHANNEL).setMethodCallHandler(MethodChannel.MethodCallHandler { p0, p1 ->
    MyLog.d(TAG, "method is ${p0.method}")
    when (p0.method) {
        "method_name" -> {
            p1.success(data)
        }
    }
}

4、返回

Android端处理完dart的消息之后,可以通过Result对象将需要返回的数据返回,包括成功,失败,未完成。

reply其实是在handleMessageFromDart方法中初始化的,handler.onMessage(buffer, new Reply(flutterJNI, replyId))

4.1 返回成功或失败

成功的话,会通过StandardMethodCodec的encodeSuccessEnvelope将数据编码:

reply.reply(codec.encodeSuccessEnvelope(result));

public ByteBuffer encodeSuccessEnvelope(Object result) {
    final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
    stream.write(0);
    messageCodec.writeValue(stream, result);
    final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
    buffer.put(stream.buffer(), 0, stream.size());
    return buffer;
}

先写进去一个成功的标志位,messageCodec是StandardMethodCodec类型,将要返回的数据写进一个byte数组中,然后放到ByteBuffer中,返回。

失败的话,会有失败原因:

reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));

@Override
public ByteBuffer encodeErrorEnvelope(
  String errorCode, String errorMessage, Object errorDetails) {
    final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
    stream.write(1);
    messageCodec.writeValue(stream, errorCode);
    messageCodec.writeValue(stream, errorMessage);
    messageCodec.writeValue(stream, errorDetails);
    final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
    buffer.put(stream.buffer(), 0, stream.size());
    return buffer;
}

编码失败数据时,与成功唯一的差别是标志位不一样。

4.2 Reply返回数据

看看Reply的具体返回方式:

4.2.1 Reply

@Override
public void reply(@Nullable ByteBuffer reply) {
  if (done.getAndSet(true)) {
    throw new IllegalStateException("Reply already submitted");
  }
  if (reply == null) {
    flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
  } else {
    flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
  }
}

我们这里的reply不为空,执行invokePlatformMessageResponseCallback方法:

shell\platform\android\io\flutter\embedding\engine\FlutterJNI.java

public void invokePlatformMessageResponseCallback(int responseId, @Nullable ByteBuffer message, int position) {
    if (isAttached()) {
      nativeInvokePlatformMessageResponseCallback(nativePlatformViewId, responseId, message, position);
    }
}

private native void nativeInvokePlatformMessageResponseCallback(long nativePlatformViewId, int responseId, @Nullable ByteBuffer message, int position);

这里的nativePlatformViewId其实是我们在应用启动时,初始化引擎返回给我们的一个long类型的id。

4.3 引擎中处理数据

nativeInvokePlatformMessageResponseCallback对应注册的native方法是InvokePlatformMessageResponseCallback:

shell\platform\android\platform_view_android_jni.cc

bool RegisterApi(JNIEnv* env) {
  static const JNINativeMethod flutter_jni_methods[] = {
    {
      .name = "nativeInvokePlatformMessageResponseCallback",
      .signature = "(JILjava/nio/ByteBuffer;I)V",
      .fnPtr = reinterpret_cast<void*>(&InvokePlatformMessageResponseCallback),
    },
  }
}

具体看看InvokePlatformMessageResponseCallback的调用栈:

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);
}

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;
    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)));
}

4.3 平台返回数据回到dart

这里的Complete对应的是在PlatformMessageResponseDart中,flutter发送消息的过程中有定义,这个方法中对应的callback方法在dart send方法的时候就有定义,这里再写一遍:

Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
        completer.complete(reply);
    });
    return completer.future;
}

最终执行到这个闭包了。Completer是一个工作流的状态管理类,最开始的时候新建一个对象,接下来执行future任务,任务完成后执行complete表示执行完成。

执行完成的时候,在MethodChannel的invokeMethod方法中就接收到了返回数据:

flutter\lib\src\services\platform_channel.dart

Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async {
    final ByteData result = await binaryMessenger.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;
}

这里的codec是StandardMethodCodec类型,将返回的数据解码就可以返回了。最终也在我们自己的dart代码中接收到返回数据了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容