Flutter與android之間的通信

Platform Channel簡介

Flutter引入Platform Channel機制來支持不一樣平臺的API調用。在Flutter中,提供了三種Platform Channel用來支持和平臺之間數據的傳遞:bash

  • BasicMessageChannel:支持字符串和半結構化的數據傳遞,能夠經過BasicMessageChannel來獲取Native項目的圖標等資源
  • MethodChannel:支持傳遞方法調用,Flutter主動調用Native的方法,並獲取相應的返回值。既能夠從Flutter發平臺發起方法調用,也能夠從平臺代碼向Flutter發起調用
  • EventChannel:支持數據流通訊,傳遞事件。收到消息後沒法回覆這次消息,一般用於Native向Dart的通訊

使用方法

BasicMessageChannel

Android端:app

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端:async

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端:ide

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端:ui

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三個回調方法分別對應事件的不一樣狀態this

源碼初探

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都有兩個成員變量:spa

  • 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進行處理。

結語

欲更進一步瞭解Platform Channel設計與實現,可前往深刻Flutter技術內幕:Platform Channel設計與實現,關注大神博客

相關文章
相關標籤/搜索