Platform Channel

flutter的android平台的通讯Channel大致有三种。

Name Function
BasicMessageChannel 用于简单的数据传递
MethodChannel 传递一个方法名和参数来完成通讯
EventChannel 类似于长连接的通讯

Channel 结构

每个Channel都会配置一个Codec,用于通讯数据的编解码。Flutter的平台通讯方式采用了二进制协议,图中的 MethodCodec和MessageCodec的实现者都是采用了字节写入写出完成数据的编解码。

MessageCodec完成基础的编解码,MethodCodec在MessageCodec的基础上进一步完成方法名字的编解码。 MessageCodec目前的实现类有四个,BinaryCodec基本不做操作,直接将获得的字节数据返回;StringCodec完成 字节和字符串的转化;JSONMessageCodec完成Json结构的字符串与字节之间转化;而StandardMessageCodec采用了 更加细分的规则。

总的来说参数传递时都是只支持基本数据类型和List与Map类型的数据,只不过StandardMessageCodec比 其他的Codec更加精准,StandardMessageCodec能根据数字编号直接确定当前读到的字节数据是何种类型。

数据结构

如图中所示,一串数据,开头字节表示为类型type,然后才是数据本体,比如当前type表示为Int型数据,那么在取数据时 直接以int形式的方式将data取出。

而MethodCodec先将方法名取出,然后将参数取出,实际还是由MessageCodec来处理。

Channel 回调结构

在Flutter android中真正完成数据收发的是DartMessenger,DartMessenger包含了两个回调集合,一个关于BinaryMessageHandler 的回调集合用于接收来自Flutter的主动调用,一个BinaryReply集合用于接收Flutter对于平台调用的响应,当然BinaryMessageHandler 是需要事先完成注册的,这样Flutter调用原生时才不会扑空。

通讯流程

有了对通道的一个初步认识,现在我们继续来看,Flutter如何实现平台通讯的。

注册

如果Flutter想要调用android平台上一个功能,android就必须实现注册一个接收器,这个接收器就是BinaryMessageHandler。android 平台 事先会将自己定义的Channel进行注册,这里我们选择MethodChannel。并且实现了一个FlutterPlugin 插件,继承于MethodCallHandler。 注册名字就是 flutter_plugin。

1
2
MethodChannel channel = new  MethodChannel(registrar.messenger(), "flutter_plugin");
channel.setMethodCallHandler(new FlutterPlugin());

调用了setMethodCallHandler之后会封装一个BinaryMessageHandler。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public final class MethodChannel {
    ...
    public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) {
        this.messenger.setMessageHandler(this.name, handler == null ? null : new MethodChannel.IncomingMethodCallHandler(handler));
    }
    ...
    private final class IncomingMethodCallHandler implements BinaryMessageHandler {
        ...
    }
    ...
}

最重会调用到DartMessenger的setMessageHandler,根据注册名字来完成注册。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
    ...
    private final Map<String, BinaryMessageHandler> messageHandlers;
    ...
    public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler) {
        if (handler == null) {
            this.messageHandlers.remove(channel);
        } else {
            this.messageHandlers.put(channel, handler);
        }
    }
    ...
}

调用

调用

完成注册之后,从Flutter发起调用。由Dart完成调用逻辑,Dart也实现了跟Java层一样的对接接口, 调用了MethodChannel来完成分发。在MethodChannel中调用codec将参数封装成二进制数据,然后调用 binaryMessenger发送。这里属于异步调用,可以直接将任务的Future返回。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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;
  }

在Dart层代码中binaryMessenger的实现者目前只有_DefaultBinaryMessenger,_DefaultBinaryMessenger 关于发送的逻辑的实现如下,并且设置了相应的回调。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class _DefaultBinaryMessenger extends BinaryMessenger {
    ...
    Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    final Completer<ByteData> completer = Completer<ByteData>();
    //最终调用了window的发送渠道
    ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
      ...
      completer.complete(reply);
      ...
    });
    return completer.future;
  }
  ...
  @override
  Future<ByteData> send(String channel, ByteData message) {
    ...
    return _sendPlatformMessage(channel, message);
  }
  ...
}

在window的实现中最终调用了native层的代码

1
2
3
4
//window.dart
 String _sendPlatformMessage(String name,
                              PlatformMessageResponseCallback callback,
                              ByteData data) native 'Window_sendPlatformMessage';

Window_sendPlatformMessage 这个标示是在Engine层事先注册过的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//window.cc

Dart_Handle SendPlatformMessage(Dart_Handle window,
                                const std::string& name,
                                Dart_Handle callback,
                                const tonic::DartByteData& data) {
    ...
    dart_state->window()->client()->HandlePlatformMessage(
        fml::MakeRefCounted<PlatformMessage>(
            name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
            response));
    ...
}

void _SendPlatformMessage(Dart_NativeArguments args) {
  tonic::DartCallStatic(&SendPlatformMessage, args);
}

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

这里有个client的转发,具体的关联如下图。

native 调用关联

最终会分发到PlatformViewAndroid的HandlePlatformMessage上,之后就会使用JNI技术传给Java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void PlatformViewAndroid::HandlePlatformMessage(
    fml::RefPtr<blink::PlatformMessage> message) {
    ...   
    FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
                                     nullptr, response_id);
    ...
  }
}

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_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
      env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
...
 g_handle_platform_message_method =
      env->GetMethodID(g_flutter_jni_class->obj(), "handlePlatformMessage",
                       "(Ljava/lang/String;[BI)V");
...

上边代码显示,最终java层的FlutterJNI类的handlePlatformMessage方法会被调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class FlutterJNI {
     ...
     private void handlePlatformMessage(@NonNull String channel, byte[] message, int replyId) {
        if (this.platformMessageHandler != null) {
            this.platformMessageHandler.handleMessageFromDart(channel, message, replyId);
        }

    }
    ...
}

继续分发,会给到platformMessageHandler调用。platformMessageHandler其实就是DartMessenger。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
    public void handleMessageFromDart(@NonNull String channel, @Nullable byte[] message, int replyId) {
        BinaryMessageHandler handler = (BinaryMessageHandler)this.messageHandlers.get(channel);
        ...        
            ByteBuffer buffer = message == null ? null : ByteBuffer.wrap(message);
            handler.onMessage(buffer, new DartMessenger.Reply(this.flutterJNI, replyId));
        ...
    }

}

这里会取出之前注册时 ,相应的名字对应的BinaryMessageHandler,这个BinaryMessageHandler应该时MethodChannel中实现的 IncomingMethodCallHandler,而MethodCallHandler就是插件需要实现的逻辑。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public final class MethodChannel {
     private final class IncomingMethodCallHandler implements BinaryMessageHandler {
        private final MethodChannel.MethodCallHandler handler;

        IncomingMethodCallHandler(MethodChannel.MethodCallHandler handler) {
            this.handler = handler;
        }

        @UiThread
        public void onMessage(ByteBuffer message, final BinaryReply reply) {
            MethodCall call = MethodChannel.this.codec.decodeMethodCall(message);
            ...
                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);
                    }
                });
            ...
        }
    }
}

只这里就完成了调用过程,下面就是回传过程。

回传

回传