這篇“Android與Flutter之間如何實(shí)現(xiàn)通信”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Android與Flutter之間如何實(shí)現(xiàn)通信”文章吧。
目前創(chuàng)新互聯(lián)建站已為數(shù)千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計(jì)、烈山網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
1、架構(gòu)概述
消息通過(guò)平臺(tái)通道在native(host)與flutter(client)之間傳遞,如下圖所示:
為了確保用戶界面能夠正確響應(yīng),消息都是以異步的方式進(jìn)行傳遞。無(wú)論是native向flutter發(fā)送消息,還是flutter向native發(fā)送消息。
在flutter中,MethodChannel可以發(fā)送與方法調(diào)用相對(duì)應(yīng)的消息。在native平臺(tái)上,MethodChannel在Android可以接收方法調(diào)用并返回結(jié)果。這些類可以幫助我們用很少的代碼就能開(kāi)發(fā)平臺(tái)插件。
注意:本節(jié)內(nèi)容來(lái)自flutter官網(wǎng),讀者可自行查閱。
2、平臺(tái)通道數(shù)據(jù)類型支持和編解碼器
平臺(tái)通道可以使用提供的編解碼器對(duì)消息進(jìn)行編解碼,這些編解碼器支持簡(jiǎn)單類似JSON的值的高效二進(jìn)制序列化,例如布爾值,數(shù)字,字符串,字節(jié)緩沖區(qū)以及這些的列表和映射。當(dāng)你發(fā)送和接收值時(shí),會(huì)自動(dòng)對(duì)這些值進(jìn)行序列化和反序列化。
下表顯示了如何在平臺(tái)端接收Dart值,反之亦然:
關(guān)于編解碼器,Android端提供了以下幾種。
BinaryCodec:是最簡(jiǎn)單的一種編解碼器,其返回值類型與入?yún)⒌念愋拖嗤?,均為二進(jìn)制格式(ByteBuffer)。由于BinaryCodec在編解碼過(guò)程中什么都沒(méi)做,只是原封不動(dòng)的將二進(jìn)制數(shù)據(jù)返回。所以傳遞的數(shù)據(jù)在編解碼時(shí)會(huì)免于拷貝,這種方式在傳遞的數(shù)據(jù)量比較大時(shí)很有用。比如從Android側(cè)傳入一張圖片到Flutter側(cè)顯示。
StandardMessageCodec:是BasicMessageChannel的默認(rèn)編解碼器,支持基礎(chǔ)數(shù)據(jù)類型、列表及字典等。在編碼時(shí)會(huì)先將數(shù)據(jù)寫(xiě)入到ByteArrayOutputStream流中,然后再將該流中的數(shù)據(jù)寫(xiě)入到ByteBuffer中。在解碼時(shí),直接從ByteBuffer中讀取數(shù)據(jù)。
StandardMethodCodec:是基于StandardMessageCodec的封裝。是MethodChannel與EventChannel的默認(rèn)編解碼器。
StringCodec:是用于字符串與二進(jìn)制數(shù)據(jù)之間的編解碼,其編碼格式為UTF-8。在編碼時(shí)會(huì)將String轉(zhuǎn)成byte數(shù)組,然后再將該數(shù)組寫(xiě)入到ByteBuffer中。在解碼時(shí),直接從ByteBuffer中讀取數(shù)據(jù)
JSONMessageCodec:內(nèi)部調(diào)用StringCodec來(lái)實(shí)現(xiàn)編解碼。
JSONMethodCodec:基于JSONMessageCodec的封裝??梢栽贛ethodChannel與EventChannel中使用。
ByteBuffer是Nio中的一個(gè)類,顧名思義——就是一塊存儲(chǔ)字節(jié)的區(qū)域。它有兩個(gè)實(shí)現(xiàn)類——DirectByteBuffer與HeapByteBuffer,DirectByteBuffer是直接在內(nèi)存中開(kāi)辟了一塊區(qū)域來(lái)存儲(chǔ)數(shù)據(jù),而HeapByteBuffer是在JVM堆中開(kāi)辟一塊區(qū)域來(lái)存儲(chǔ)數(shù)據(jù),所以要想數(shù)據(jù)在DirectByteBuffer中與HeapByteBuffer互通,就需要進(jìn)行一次拷貝。
3、通信方式
前面講了Android與flutter通信的一些基礎(chǔ)知識(shí),下面就進(jìn)入正題,來(lái)看Android如何與flutter進(jìn)行通信。
Android與Flutter之間的通信共有四種實(shí)現(xiàn)方式。
由于在初始化flutter頁(yè)面時(shí)會(huì)傳遞一個(gè)字符串——route,因此我們就可以拿route來(lái)做文章,傳遞自己想要傳遞的數(shù)據(jù)。該種方式僅支持單向數(shù)據(jù)傳遞且數(shù)據(jù)類型只能為字符串,無(wú)返回值。
通過(guò)EventChannel來(lái)實(shí)現(xiàn),EventChannel僅支持?jǐn)?shù)據(jù)單向傳遞,無(wú)返回值。
通過(guò)MethodChannel來(lái)實(shí)現(xiàn),MethodChannel支持?jǐn)?shù)據(jù)雙向傳遞,有返回值。
通過(guò)BasicMessageChannel來(lái)實(shí)現(xiàn),BasicMessageChannel支持?jǐn)?shù)據(jù)雙向傳遞,有返回值。
下面就來(lái)看一下這幾種方式的使用。
3.1、初始化時(shí)傳值
主要是利用了創(chuàng)建flutter頁(yè)面?zhèn)鬟f的route來(lái)做文章,筆者認(rèn)為該種方式屬于取巧,但還是可以用來(lái)傳遞數(shù)據(jù)。它的使用很簡(jiǎn)單,代碼如下。
首先來(lái)看Android代碼。
//第三個(gè)參數(shù)可以換成我們想要字符串。 FlutterView flutterView = Flutter.createView(this, getLifecycle(), "route");
在flutter中,我們只需要通過(guò)下面代碼來(lái)獲取值即可。
void main() => runApp(MyApp( initParams: window.defaultRouteName, )); class MyApp extends StatelessWidget { final String initParams;//既是前面?zhèn)鬟f的值——route MyApp({Key key, @required this.initParams}) : super(key: key); @override Widget build(BuildContext context) {...} }
通過(guò)該種方式就可以在初始化flutter時(shí),Android給flutter傳遞數(shù)據(jù)。由于runApp僅會(huì)調(diào)用一次,所以該種方式只能傳遞一次數(shù)據(jù)且數(shù)據(jù)只能是字符串。
使用window的相關(guān)API需要導(dǎo)入包dart:ui
3.2、EventChannel
EventChannel是一種native向flutter發(fā)送數(shù)據(jù)的單向通信方式,flutter無(wú)法返回任何數(shù)據(jù)給native。主要用于native向flutter發(fā)送手機(jī)電量變化、網(wǎng)絡(luò)連接變化、陀螺儀、傳感器等。它的使用方式如下。
首先來(lái)看Android代碼。
public class EventChannelPlugin implements EventChannel.StreamHandler { private static final String TAG = EventChannelPlugin.class.getSimpleName(); private EventChannel.EventSink eventSink; private Activity activity; static EventChannelPlugin registerWith(FlutterView flutterView) { EventChannelPlugin plugin = new EventChannelPlugin(flutterView); new EventChannel(flutterView, "EventChannelPlugin").setStreamHandler(plugin); return plugin; } private EventChannelPlugin(FlutterView flutterView) { this.activity = (Activity) flutterView.getContext(); } void send(Object params) { if (eventSink != null) { eventSink.success(params); } } void sendError(String str1, String str2, Object params) { if (eventSink != null) { eventSink.error(str1, str2, params); } } void cancel() { if (eventSink != null) { eventSink.endOfStream(); } } //第一個(gè)參數(shù)為flutter初始化EventChannel時(shí)返回的值,僅此一次 @Override public void onListen(Object o, EventChannel.EventSink eventSink) { this.eventSink = eventSink; Log.i(TAG, "eventSink:" + eventSink); Log.i(TAG, "Object:" + o.toString()); Toast.makeText(activity, "onListen——obj:" + o, Toast.LENGTH_SHORT).show(); } @Override public void onCancel(Object o) { Log.i(TAG, "onCancel:" + o.toString()); Toast.makeText(activity, "onCancel——obj:" + o, Toast.LENGTH_SHORT).show(); this.eventSink = null; } }
筆者對(duì)Android端代碼做了一個(gè)簡(jiǎn)單的封裝,還是很好理解的。下面就來(lái)看flutter代碼實(shí)現(xiàn)。
class _MyHomePageState extends State<MyHomePage> { EventChannel _eventChannelPlugin = EventChannel("EventChannelPlugin"); StreamSubscription _streamSubscription; @override void initState() { _streamSubscription = _eventChannelPlugin //["abc", 123, "你好"]對(duì)應(yīng)著Android端onListen方法的第一個(gè)參數(shù),可不傳值 .receiveBroadcastStream(["abc", 123, "你好"]) .listen(_onToDart, onError: _onToDartError, onDone: _onDone); super.initState(); } @override void dispose() { if (_streamSubscription != null) { _streamSubscription.cancel(); _streamSubscription = null; } super.dispose(); } //native端發(fā)送正常數(shù)據(jù) void _onToDart(message) { print(message); } //當(dāng)native出錯(cuò)時(shí),發(fā)送的數(shù)據(jù) void _onToDartError(error) { print(error); } //當(dāng)native發(fā)送數(shù)據(jù)完成時(shí)調(diào)用的方法,每一次發(fā)送完成就會(huì)調(diào)用 void _onDone() { print("消息傳遞完畢"); } @override Widget build(BuildContext context) {...} }
上面就是通過(guò)EventChannel來(lái)進(jìn)行通信的代碼實(shí)現(xiàn),調(diào)用EventChannelPlugin的send方法就能給flutter發(fā)送數(shù)據(jù)。
3.3、MethodChannel
MethodChannel是一種native與flutter之間互相發(fā)送數(shù)據(jù)的通信方式,顧名思義,通過(guò)MethodChannel就能調(diào)用native與flutter中相對(duì)應(yīng)的方法,該種方式有返回值。它的使用方式如下。
首先來(lái)看Android端的代碼實(shí)現(xiàn)。
public class MethodChannelPlugin implements MethodChannel.MethodCallHandler { private Activity activity; private MethodChannel channel; public static MethodChannelPlugin registerWith(FlutterView flutterView) { MethodChannel channel = new MethodChannel(flutterView, "MethodChannelPlugin"); MethodChannelPlugin methodChannelPlugin = new MethodChannelPlugin((Activity) flutterView.getContext(), channel); channel.setMethodCallHandler(methodChannelPlugin); return methodChannelPlugin; } private MethodChannelPlugin(Activity activity, MethodChannel channel) { this.activity = activity; this.channel = channel; } //調(diào)用flutter端方法,無(wú)返回值 public void invokeMethod(String method, Object o) { channel.invokeMethod(method, o); } //調(diào)用flutter端方法,有返回值 public void invokeMethod(String method, Object o, MethodChannel.Result result) { channel.invokeMethod(method, o, result); } @Override public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { switch (methodCall.method) { case "send"://返回的方法名 //給flutter端的返回值 result.success("MethodChannelPlugin收到:" + methodCall.arguments); Toast.makeText(activity, methodCall.arguments + "", Toast.LENGTH_SHORT).show(); if (activity instanceof FlutterAppActivity) { ((FlutterAppActivity) activity).showContent(methodCall.arguments); } break; default: result.notImplemented(); break; } } }
筆者對(duì)Android端代碼做了一個(gè)簡(jiǎn)單的封裝,還是很好理解的。下面就來(lái)看flutter代碼實(shí)現(xiàn)。
class _MyHomePageState extends State<MyHomePage> { MethodChannel _methodChannel = MethodChannel("MethodChannelPlugin"); @override void initState() { _methodChannel.setMethodCallHandler((handler) => Future<String>(() { print("_methodChannel:${handler}"); //監(jiān)聽(tīng)native發(fā)送的方法名及參數(shù) switch (handler.method) { case "send": _send(handler.arguments);//handler.arguments表示native傳遞的方法參數(shù) break; } })); super.initState(); } //native調(diào)用的flutter方法 void _send(arg) { setState(() { _content = arg; }); } String _resultContent = ""; //flutter調(diào)用native的相應(yīng)方法 void _sendToNative() { Future<String> future = _methodChannel.invokeMethod("send", _controller.text); future.then((message) { setState(() { //message是native返回的數(shù)據(jù) _resultContent = "返回值:" + message; }); }); } @override Widget build(BuildContext context) {...} }
上面就是通過(guò)MethodChannel來(lái)進(jìn)行通信的代碼實(shí)現(xiàn)。還是比較簡(jiǎn)單的。在Android端使用只需要調(diào)用MethodChannelPlugin的invokeMethod方法即可。在flutter端使用只需要參考_sendToNative方法的實(shí)現(xiàn)即可。
3.4、BasicMessageChannel
BasicMessageChannel是一種能夠在native與flutter之間互相發(fā)送消息的通信方式,它支持?jǐn)?shù)據(jù)類型最多,使用范圍最廣。EventChannel與MethodChannel的應(yīng)用場(chǎng)景可以使用BasicMessageChannel來(lái)實(shí)現(xiàn),但BasicMessageChannel的應(yīng)用場(chǎng)景就不一定能夠使用EventChannel與MethodChannel來(lái)實(shí)現(xiàn)。該方式有返回值。它的使用方式如下。
首先來(lái)看Android代碼的實(shí)現(xiàn)。
//這里支持的數(shù)據(jù)類型為String。 public class BasicMessageChannelPlugin implements BasicMessageChannel.MessageHandler<String> { private Activity activity; private BasicMessageChannel<String> messageChannel; static BasicMessageChannelPlugin registerWith(FlutterView flutterView) { return new BasicMessageChannelPlugin(flutterView); } private BasicMessageChannelPlugin(FlutterView flutterView) { this.activity = (Activity) flutterView.getContext(); this.messageChannel = new BasicMessageChannel<String>(flutterView, "BasicMessageChannelPlugin", StringCodec.INSTANCE); messageChannel.setMessageHandler(this); } @Override public void onMessage(String s, BasicMessageChannel.Reply<String> reply) { reply.reply("BasicMessageChannelPlugin收到:" + s); if (activity instanceof FlutterAppActivity) { ((FlutterAppActivity) activity).showContent(s); } } void send(String str, BasicMessageChannel.Reply<String> reply) { messageChannel.send(str, reply); } }
筆者對(duì)Android端代碼做了一個(gè)簡(jiǎn)單的封裝,還是很好理解的。下面就來(lái)看flutter代碼實(shí)現(xiàn)。
class _MyHomePageState extends State<MyHomePage> { //StringCodec()為編碼格式 BasicMessageChannel<String> _basicMessageChannel = BasicMessageChannel("BasicMessageChannelPlugin", StringCodec()); @override void initState() { _basicMessageChannel.setMessageHandler((message) => Future<String>(() { print(message); //message為native傳遞的數(shù)據(jù) setState(() { _content = message; }); //給Android端的返回值 return "收到Native消息:" + message; })); _controller = TextEditingController(); super.initState(); } //向native發(fā)送消息 void _sendToNative() { Future<String> future = _basicMessageChannel.send(_controller.text); future.then((message) { _resultContent = "返回值:" + message; }); } @override Widget build(BuildContext context) {...} }
上面就是通過(guò)BasicMessageChannel來(lái)進(jìn)行通信的代碼實(shí)現(xiàn)。在Android端只需要調(diào)用BasicMessageChannelPlugin的send方法就可以向flutter發(fā)送數(shù)據(jù),BasicMessageChannel.Reply是返回值的回調(diào)方法。在flutter端使用只需要參考_sendToNative方法的實(shí)現(xiàn)即可。
4、通信原理
從分析Android與Flutter通信的源碼來(lái)看,實(shí)現(xiàn)還是比較簡(jiǎn)單的,都是以ByteBuffer為數(shù)據(jù)載體,然后通過(guò)BinaryMessenger來(lái)發(fā)送與接收數(shù)據(jù)。整體設(shè)計(jì)如下。
從圖中可以看出,Android側(cè)與flutter側(cè)采用了相同的設(shè)計(jì)。前面說(shuō)過(guò)通信時(shí)是異步進(jìn)行的,那么線程切換在哪?其實(shí)是在系統(tǒng)底層實(shí)現(xiàn)的。在Android與Flutter通信中,系統(tǒng)底層屏蔽了線程切換、數(shù)據(jù)拷貝等大量復(fù)雜操作。使得Android側(cè)與flutter側(cè)能方便的來(lái)進(jìn)行通信。
在Android側(cè),BinaryMessenger是一個(gè)接口,在FlutterView中實(shí)現(xiàn)了該接口,在BinaryMessenger的方法中通過(guò)JNI來(lái)與系統(tǒng)底層溝通。在Flutter側(cè),BinaryMessenger是一個(gè)類,該類的作用就是與類window溝通,而類window才真正與系統(tǒng)底層溝通。
以上就是關(guān)于“Android與Flutter之間如何實(shí)現(xiàn)通信”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)頁(yè)題目:Android與Flutter之間如何實(shí)現(xiàn)通信
本文鏈接:http://www.rwnh.cn/article0/gopdoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、用戶體驗(yàn)、手機(jī)網(wǎng)站建設(shè)、標(biāo)簽優(yōu)化、Google、ChatGPT
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)