敞开生长之旅!这是我参加「日新计划 12 月更文应战」的第31天,点击检查活动详情

Platform Channel作业原理

Flutter界说了三种不同类型的Channel,它们分别是

  • BasicMessageChannel:用于传递字符串和半结构化的信息。
  • MethodChannel:用于传递办法调用(method invocation)。
  • EventChannel: 用于数据流(event streams)的通讯。

三种Channel之间互相独立,各有用处,但它们在设计上却非常附近。每种Channel均有三个重要成员变量:

  • name: String类型,代表Channel的名字,也是其仅有标识符。
  • messager:BinaryMessenger类型,代表音讯信使,是音讯的发送与接纳的东西。
  • codec: MessageCodec类型或MethodCodec类型,代表音讯的编解码器。

运用办法

BasicMessageChannel

Android端:

BasicMessageChannel mBasicMessageChannel = new BasicMessageChannel(getFlutterView(), "basic_channel", StringCodec.INSTANCE);
mBasicMessageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler() {
   //承受音讯
   @Override
   public void onMessage(Object o, BasicMessageChannel.Reply reply) {
     Log.e("basic_channel", "接纳到来自flutter的音讯:"+o.toString());
     reply.reply("回馈音讯");
   }
});
//发送音讯
mBasicMessageChannel.send("向flutter发送音讯");
//发送音讯并承受flutter的回馈
mBasicMessageChannel.send("向flutter发送音讯", new BasicMessageChannel.Reply() {
       @Override
       public void reply(Object o) {
        
       }
});

Flutter端:

const basicMessageChannel = const BasicMessageChannel('basic_channel', StringCodec());
//承受并回复音讯
basicMessageChannel.setMessageHandler(
    (String message) => Future<String>(() {
       setState(() {
        this.message = message;
       });
       return "回复native音讯";
    }),
);
//发送音讯
basicMessageChannel.send("来自flutter的message");
//flutter并没有发送并承受回复音讯的`send(T message, BasicMessageChannel.Reply<T> callback)`办法

MethodChannel

Android端:

MethodChannel mMethodChannel = new MethodChannel(getFlutterView(), "method_channel");
mMethodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
   //响应flutter端的调用
   @Override
   public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
     if (methodCall.method.equals("noticeNative")) {
       todo()
       result.success("承受成功");
     }
   }
});
//原生调用flutter
mMethodChannel.invokeMethod("noticeFlutter", "argument", new MethodChannel.Result() {
       @Override
       public void success(Object o) {
         //回调成功
       }
       @Override
       public void error(String s,String s1, Object o) {
         //回调失利
       }
       @Override
       public void notImplemented() {
​
       }
});

Flutter端:

const methodChannel = const MethodChannel('method_channel');
Future<Null> getMessageFromNative() async {
   //flutter调原生办法
   try {
    //回调成功
    final String result = await methodChannel.invokeMethod('noticeNative');
    setState(() {
     method = result;
    });
   } on PlatformException catch (e) {
    //回调失利
   }
  }
methodChannel.setMethodCallHandler(
    (MethodCall methodCall) => Future<String>(() {
       //响应原生的调用
      if(methodCall.method == "noticeFlutter"){
       setState(() {
       
       });
      }
    }),
); 

EventChannel

Android端:

EventChannel eventChannel = new EventChannel(getFlutterView(),"event_channel");
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
   @Override
   public void onListen(Object o, EventChannel.EventSink eventSink) {
     eventSink.success("成功");
     //eventSink.error("失利","失利","失利");
   }
   @Override
   public void onCancel(Object o) {
     //撤销监听时调用
   }
});

Flutter端:

const eventChannel = const EventChannel('event_channel');
eventChannel.receiveBroadcastStream().listen(_onEvent,onError:_onError);
void _onEvent(Object event) {
   //返回的内容
}
void _onError(Object error) {
   //返回的回调
}

其中:Object args是传递的参数,EventChannel.EventSink eventSink是Native回调Dart时的会回调函数,eventSink供给success、error与endOfStream三个回调办法分别对应事件的不同状况

源码初探

Platform Channel基本结构

首先了解一下这三种Channel的代码:

BasicMessageChannel
class BasicMessageChannel<T> {
  const BasicMessageChannel(this.name, this.codec);
  final String name;
  final MessageCodec<T> codec;
  Future<T> send(T message) async {
   return codec.decodeMessage(await BinaryMessages.send(name, codec.encodeMessage(message)));
  }
  void setMessageHandler(Future<T> handler(T message)) {
   if (handler == null) {
    BinaryMessages.setMessageHandler(name, null);
   } else {
    BinaryMessages.setMessageHandler(name, (ByteData message) async {
     return codec.encodeMessage(await handler(codec.decodeMessage(message)));
    });
   }
  }
  void setMockMessageHandler(Future<T> handler(T message)) {
   if (handler == null) {
    BinaryMessages.setMockMessageHandler(name, null);
   } else {
    BinaryMessages.setMockMessageHandler(name, (ByteData message) async {
     return codec.encodeMessage(await handler(codec.decodeMessage(message)));
    });
   }
  }
}
MethodChannel
class MethodChannel {
  const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
  final String name;
  final MethodCodec codec;
  void setMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
   BinaryMessages.setMessageHandler(
    name,
    handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
   );
  }
  void setMockMethodCallHandler(Future<dynamic> handler(MethodCall call)) {
   BinaryMessages.setMockMessageHandler(
    name,
    handler == null ? null : (ByteData message) => _handleAsMethodCall(message, handler),
   );
  }
  Future<ByteData> _handleAsMethodCall(ByteData message, Future<dynamic> handler(MethodCall call)) async {
   final MethodCall call = codec.decodeMethodCall(message);
   try {
    return codec.encodeSuccessEnvelope(await handler(call));
   } on PlatformException catch (e) {
    returun ...
   } on MissingPluginException {
    return null;
   } catch (e) {
    return ...
   }
  }
  Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
   assert(method != null);
   final ByteData result = await BinaryMessages.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;
  }
}
EventChannel
class EventChannel {
  const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);
  final String name;
  final MethodCodec codec;
  Stream<dynamic> receiveBroadcastStream([dynamic arguments]) {
    final MethodChannel methodChannel = MethodChannel(name, codec);
    StreamController<dynamic> controller;
    controller = StreamController<dynamic>.broadcast(onListen: () async {
      BinaryMessages.setMessageHandler(name, (ByteData reply) async {
        ...
      });
      try {
        await methodChannel.invokeMethod<void>('listen', arguments);
      } catch (exception, stack) {
        ...
      }
    }, onCancel: () async {
      BinaryMessages.setMessageHandler(name, null);
      try {
        await methodChannel.invokeMethod<void>('cancel', arguments);
      } catch (exception, stack) {
        ...
      }
    });
    return controller.stream;
  }
}

这三种Channel都有两个成员变量:

  • name:表明Channel名字,用于区别不同Platform Channel的仅有标志,每个Channel运用仅有的name作为其仅有标志
  • codec: 表明音讯的编解码器,Flutter采用了二进制字节省作为数据传输协议:发送方需要把数据编码成二进制数据,承受方再把数据解码成原始数据.而负责编解码操作的便是Codec。 每个Channel中都运用到了BinaryMessages,它起到了信使的作用,负责将信息进行跨渠道的搬运,是音讯发送和承受的东西。
setMessageHandler

在创建好BasicMessageChannel后,让其承受来自另一渠道的音讯,BinaryMessenger调用它的setMessageHandler办法为其设置一个音讯处理器,合作BinaryMessenger完结音讯的处理以及回复;

send

在创建好BasicMessageChannel后,可以调用它的send办法向另一个渠道传递数据。

setMethodCallHandler

设置用于在此MethodChannel上接纳办法调用的回调

receiveBroadcastStream

设置广播流以接纳此EventChannel上的事件

Handler

Flutter运用Handler处理Codec解码后的音讯。三种Platform Channel相对应,Flutter中也界说了三种Handler:

  • MessageHandler: 用于处理字符串或者半结构化音讯,界说在BasicMessageChannel中.
  • MethodCallHandler: 用于处理办法调用,界说在MethodChannel中.
  • StreamHandler: 用于事件流通讯,界说在EventChannel中

运用Platform Channel时,需要为其注册一个对应BinaryMessageHandler为其设置对应的Handler。二进制数据会被BinaryMessageHanler进行处理,首先运用Codec进行解码操作,然后再分发给具体Handler进行处理。

文末

在Flutter与Native混合开发的模式下,Platform Channel的使用场景非常多,了解Platform Channel的作业原理,有助于咱们在从事这方面开发时能做到称心如意。

跟完MethodChannel的源码,会发现整个通讯机制还挺简单的,先去不去了解Codec的话,等于便是将dart的变量,传到dart Native,然后交到java Native, 再传到java。然后相反的途径,再从java到dart。

然后再去看BasicMessageChannel便是没有MethodCall这个结构的,其他的也是走的BinaryMessages.send办法。然后在Android端,没有=IncomingMethodCallHandler这个类,直接便是BinaryMessageHandler。所以了解了MethodChannelBasicMessageChannel原理自然就懂了。

同样的EventChannel则是根据MethodChannel来实现的,仅仅两端的handler会有一些特殊的处理方式,这个倒是与通讯没有多大关系了,不过设计的也很简单,比较有意思。