目錄介紹
- 01.flutter和原生之間交互
- 02.MethodChanel流程
- 03.MethodChanel使用流程
- 04.MethodChanel代碼實(shí)踐
- 05.EventChannel流程
- 06.EventChannel基本流程
- 07.EventChannel代碼實(shí)現(xiàn)
- 08.BasicMessageChannel流程
- 09.BasicMessageChannel基本流程
- 10.BasicMessageChannel代碼實(shí)現(xiàn)
- 11.Channel編解碼器說(shuō)明
- 12.Channel通信可以子線程嗎
- 13.Channel通信傳遞穩(wěn)定性
- 14.onActivityResult如何實(shí)現(xiàn)
推薦
- fluter Utils 工具類庫(kù):https://github.com/yangchong211/YCFlutterUtils
- flutter 混合項(xiàng)目代碼案例:https://github.com/yangchong211/YCVideoPlayer
01.flutter和原生之間交互
1.1 交互簡(jiǎn)單介紹
- 官方給的通信方式
- 看圖片,channel通信方式
- 從底層來(lái)看,F(xiàn)lutter和平臺(tái)端通信的方式是發(fā)送異步的二進(jìn)制消息,該基礎(chǔ)通信方式在Flutter端由BinaryMessages來(lái)實(shí)現(xiàn), 而在Android端是一個(gè)接口BinaryMessenger,其具體實(shí)現(xiàn)為FlutterNativeView,在iOS端是一個(gè)協(xié)議 FlutterBinaryMessenger,F(xiàn)lutterViewController遵守并實(shí)現(xiàn)了這個(gè)協(xié)議。
- flutter可以與native之間進(jìn)行通信,幫助我們使用native提供的能力。
- 通信是雙向的,我們可以從Native層調(diào)用flutter層的dart代碼,同時(shí)也可以從flutter層調(diào)用Native的代碼。
- 我們需要使用Platform Channels APIs進(jìn)行通信,主要包括下面三種:
- MethodChannel:用于傳遞方法調(diào)用(method invocation)
- EventChannel:用于事件流的發(fā)送(event streams)
- BasicMessageChannel:用于傳遞字符串和半結(jié)構(gòu)化的消息,這里什么叫做半結(jié)構(gòu)化?下面會(huì)解釋……
- channel通信是異步還是同步的
- 為了保證用戶界面在交互過(guò)程中的流暢性,無(wú)論是從Flutter向Native端發(fā)送消息,還是Native向Flutter發(fā)送消息都是以異步的形式進(jìn)行傳遞的。那為何不使用同步來(lái)操作,下面會(huì)說(shuō)到……
- 幾種channel應(yīng)用場(chǎng)景分析
- MethodChannel使用場(chǎng)景:無(wú)論是Flutter端還是Native端都可以通過(guò)MethodChannel向?qū)Ψ狡脚_(tái)發(fā)送兩端提前定義好的方法名來(lái)調(diào)用對(duì)方平臺(tái)相對(duì)應(yīng)的消息處理邏輯并且?guī)Щ胤祷刂到o被調(diào)用方。
- EventChannel的使用場(chǎng)景:更側(cè)重于Native平臺(tái)主動(dòng)向Flutter平臺(tái),單向給Flutter平臺(tái)發(fā)送消息,F(xiàn)lutter無(wú)法返回任何數(shù)據(jù)給Native端,EventChannel描述是單通的??梢灶惐華ndroid里面的廣播……
- BasicMessageChannel的使用場(chǎng)景:比如flutter想拍照,拍完照后的圖片路徑需要傳給flutter,照片的路徑發(fā)送可以使用BasicMessageChannel.Reply回復(fù),也可以使用sendMessage主動(dòng)再發(fā)一次消息。個(gè)人認(rèn)為接收消息并回復(fù)消息屬于一次通信,所以傾向于使用BasicMessageChannel.Reply。
- 混合開(kāi)發(fā)通常用那種channel
- 只是混合開(kāi)發(fā)通常涉及到兩端頻繁通信,個(gè)人更加傾向使用BasicMessageChannel,不分主客,使用和通信更方便。
1.2 核心類重點(diǎn)說(shuō)明
- MethodCall
- 方法調(diào)用Java層封裝,主要是數(shù)據(jù)類
- MethodChannel
- 這個(gè)主要用戶和dart進(jìn)行方法通信,類
- MethodCallHandler
- 這個(gè)java層處理dart層時(shí)間的接口,在通訊協(xié)議中屬于上層接口,接口
- BinaryMessageHandler
- java層和dart層通訊的最底層抽象接口,面向二進(jìn)制數(shù)據(jù)包,接口
- DartMessenger
- 最底層用于接收J(rèn)NI發(fā)送過(guò)來(lái)的數(shù)據(jù)。實(shí)現(xiàn)類
- DartExecutor
- 配置、引導(dǎo)并開(kāi)始執(zhí)行Dart代碼。BinaryMessenger的具體實(shí)現(xiàn)類
- FlutterView
- NA用來(lái)承載flutter的容器view
- IncomingMethodCallHandler
- BinaryMessageHandler的實(shí)現(xiàn)類,用戶接收底層發(fā)送過(guò)來(lái)的數(shù)據(jù)包,然后轉(zhuǎn)發(fā)給MethodCallHandler,并對(duì)MethodCallHandler 發(fā)送過(guò)的結(jié)果進(jìn)行打包發(fā)送給dart層。實(shí)現(xiàn)類
- FlutterJNI
- JNI層的封裝用于跟底層引擎?zhèn)冗M(jìn)行通訊
02.MethodChannel流程
- 其中最常用的是MethodChanel,MethodChanel的使用與在Android的JNI調(diào)用非常類似,但是MethodChanel更加簡(jiǎn)單,而且相對(duì)于JNI的同步調(diào)用MethodChanel的調(diào)用是異步的:
- [站外圖片上傳中...(image-2f72c-1629975250841)]
- 從flutter架構(gòu)圖上可以看到,flutter與native的通信發(fā)生在Framework和Engine之間,framewrok內(nèi)部會(huì)將MethodChannel以BinaryMessage的形式與Engine進(jìn)行數(shù)據(jù)交換。
03.MethodChanel使用流程
3.1 flutter調(diào)用native
- flutter調(diào)用native步驟
- [native] 使用MethodChannel#setMethodCallHandler注冊(cè)回調(diào)
- [flutter] 通過(guò)MethodChannel#invokeMethod發(fā)起異步調(diào)用
- [native] 調(diào)用native方法通過(guò)Result#success返回Result,出錯(cuò)時(shí)返回error
- [flutter] 收到native返回的Result
- 如圖所示
- [站外圖片上傳中...(image-864617-1629975250841)]
3.2 native調(diào)用flutter
- native調(diào)用flutter
- 與flutter調(diào)用native的順序完全一致,只是[native]與[flutter]角色反調(diào)
- 如圖所示
- [站外圖片上傳中...(image-b7c0c0-1629975250841)]
- NA端使用MethodChannel
- 首先定義Channel名稱,需要保證是唯一的,在Flutter端需要使用同樣的名稱來(lái)創(chuàng)建MethodChannel。如果名稱不一樣,則會(huì)導(dǎo)致匹配不上……
- 第一個(gè)參數(shù):是messenger,類型是BinaryMessenger,是一個(gè)接口,代表消息信使,是消息發(fā)送與接收的工具;
- 第二個(gè)參數(shù):是name,就是Channel名稱,和flutter定義的要一樣;
- 第三個(gè)參數(shù):是codec,類型是MethodCodec,代表消息的編解碼器,如果沒(méi)有傳該參數(shù),默認(rèn)使用StandardMethodCodec。
04.MethodChanel代碼實(shí)踐
4.1 native調(diào)用flutter
- 定義好了MethodChannel之后調(diào)用setMethodCallHandler()方法設(shè)置消息處理回調(diào),參數(shù)是MethodHandler類型,需要實(shí)現(xiàn)它的onMethodCall()方法。onMethodCall()方法有兩個(gè)參數(shù)methodCall和result,methodCall記錄了調(diào)用的方法信息,包括方法名和參數(shù),result用于方法的返回值,可以通過(guò)result.success()方法返回信息給Flutter端。
private void createChannel() { nativeChannel = new MethodChannel(binaryMessenger, METHOD_CHANNEL, StandardMethodCodec.INSTANCE); // 注冊(cè)Handler實(shí)現(xiàn) nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() { @Override public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) { if ("android".equals(methodCall.method)) { //接收來(lái)自flutter的指令 String flutter = methodCall.argument("flutter"); //返回給flutter的參數(shù) result.success("Na收到指令"); } } }); } - 可以通過(guò)invokeMethod方法讓NA執(zhí)行調(diào)用flutter方法。那么執(zhí)行了flutter方法后需要回傳數(shù)據(jù),這個(gè)時(shí)候就需要用到Result接口呢,代碼如下所示:
HashMap<String , String> map = new HashMap<>(); map.put("invokeKey","你好,這個(gè)是從NA傳遞過(guò)來(lái)的數(shù)據(jù)"); //nativeChannel.resizeChannelBuffer(100); nativeChannel.invokeMethod("getFlutterResult", map , new MethodChannel.Result() { @SuppressLint("SetTextI18n") @Override public void success(@Nullable Object result) { tvContent.setText("測(cè)試內(nèi)容:"+result); } @SuppressLint("SetTextI18n") @Override public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { tvContent.setText("測(cè)試內(nèi)容:flutter傳遞給na數(shù)據(jù)傳遞錯(cuò)誤"); } @Override public void notImplemented() { } }); - 事件接收處理端
- 接收處理回調(diào)時(shí)onMethodCall(MethodCall call, MethodChannel.Result result)通過(guò)methodCall接收事件發(fā)送者傳遞回來(lái)的信息,通過(guò)Result把處理完的結(jié)果發(fā)送給事件發(fā)送方。
- 通過(guò)methodCall.method:來(lái)區(qū)分不同函數(shù)名(方法)名以執(zhí)行不同的業(yè)務(wù)邏輯,
- 通過(guò)methodCall.hasArgument("key"):判斷是否有某個(gè)key對(duì)應(yīng)的value
- 通過(guò)methodCall.argument("key"):獲取key對(duì)應(yīng)的value值
- 通過(guò)result.success(object):把處理完的結(jié)果返回給事件發(fā)送方
- 事件發(fā)送端
- 處理事件發(fā)送方通過(guò)methodChannel.invokeMethod("方法名","要傳遞的參數(shù)")把需要傳遞的參數(shù)傳遞給事件監(jiān)聽(tīng)者。 其中
- 方法名:不能為空
- 要傳遞的參數(shù):可以為空,若不為空則必須為可Json序列化的對(duì)象。
- callback:可以為空,若不為空則表示執(zhí)行了flutter方法后的回調(diào)監(jiān)聽(tīng)狀態(tài)
4.2 flutter調(diào)用native
- Flutter使用MethodChannel
- 在Flutter端同樣需要定義一個(gè)MethodChannel,使用MethodChannel需要引入services.dart包,Channel名稱要和Android端定義的相同。
static const method = const MethodChannel('com.ycbjie.android/method'); - 添加監(jiān)聽(tīng)NA調(diào)用flutter方法的監(jiān)聽(tīng),flutter代碼是setMethodCallHandler方法實(shí)現(xiàn)。return則表示flutter回傳給NA的數(shù)據(jù)操作。
method.setMethodCallHandler(nativeCallHandler); // 注冊(cè)方法,等待被原生通過(guò)invokeMethod喚起 Future<dynamic> nativeCallHandler(MethodCall methodCall) async { switch (methodCall.method) { case "getFlutterResult": //獲取參數(shù) String paramsFromNative = await methodCall.arguments["invokeKey"]; print("原生android傳遞過(guò)來(lái)的參數(shù)為------ $paramsFromNative"); return "你好,這個(gè)是從flutter回傳給NA的數(shù)據(jù)"; break; } } - flutter是如何給NA發(fā)送消息的呢,直接調(diào)用invokeMethod方法,代碼如下所示
Future<Null> _jumpToNativeWithParams1() async { Map<String, String> map = { "flutter": "這是一條來(lái)自flutter的參數(shù)" }; String result = await method.invokeMethod('android', map); print(result); }
05.EventChannel流程
- EventChannel用于從native向flutter發(fā)送通知事件,例如flutter通過(guò)其監(jiān)聽(tīng)Android的重力感應(yīng)變化等。與MethodChannel不同,EventChannel是native到flutter的單向調(diào)用,調(diào)用是多播(一對(duì)多)的,可以類比成Android的Brodecast廣播。
06.EventChannel基本流程
- 照例先看一下API使用的基本流程:
- [native]EventChannel#setStreamHandler注冊(cè)Handler實(shí)現(xiàn)
- [native]EventChannel初始化結(jié)束后,在StreamHandler#onLister回調(diào)中獲取EventSink引用并保存
- [flutter]EventChannel#receiveBroadcastStream注冊(cè)listener,建立監(jiān)聽(tīng)
- [native]使用EventSink#sucess發(fā)送通知事件
- [flutter]接受到事件通知
- [native]通知結(jié)束時(shí)調(diào)用endOfStream結(jié)束
- 如圖所示
- [站外圖片上傳中...(image-550062-1629975250841)]
07.EventChannel代碼實(shí)現(xiàn)
- flutter端
- 創(chuàng)建EventChannel,注冊(cè)“包名/標(biāo)識(shí)符”的channel名
- 通過(guò)StreamSubscription#listen注冊(cè)listener,其中cancelOnError參數(shù)表示遇到錯(cuò)誤時(shí)是否自動(dòng)結(jié)束監(jiān)聽(tīng)
class _MyHomePageState extends State<MyHomePage> { static const EventChannel _channel = const EventChannel('com.example.eventchannel/interop'); StreamSubscription _streamSubscription; String _platformMessage; void _enableEventReceiver() { _streamSubscription = _channel.receiveBroadcastStream().listen( (dynamic event) { print('Received event: $event'); setState(() { _platformMessage = event; }); }, onError: (dynamic error) { print('Received error: ${error.message}'); }, cancelOnError: true); } void _disableEventReceiver() { if (_streamSubscription != null) { _streamSubscription.cancel(); _streamSubscription = null; } } @override initState() { super.initState(); _enableEventReceiver(); } @override void dispose() { super.dispose(); _disableEventReceiver(); } - native(android)端
- 通過(guò)EventChannel#setStreamHandler注冊(cè)Handler實(shí)現(xiàn)
- 初始化完成后,獲取eventSink引用并保存
- eventSink發(fā)送事件通知
- 通知結(jié)束時(shí)調(diào)用event#endOfStream,此時(shí)onCancel會(huì)被調(diào)用
- 必要時(shí),可通過(guò)evnetSink#error發(fā)送錯(cuò)誤通知,flutter的StreamSubscription#onError會(huì)收到通知
class MainActivity: FlutterActivity() { private lateinit var channel: EventChannel var eventSink: EventSink? = null override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine) channel = EventChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.eventchannel/interop") channel.setStreamHandler( object : StreamHandler { override fun onListen(arguments: Any?, events: EventSink) { eventSink = events Log.d("Android", "EventChannel onListen called") Handler().postDelayed({ eventSink?.success("Android") //eventSink?.endOfStream() //eventSink?.error("error code", "error message","error details") }, 500) } override fun onCancel(arguments: Any?) { Log.w("Android", "EventChannel onCancel called") } }) } }
08.BasicMessageChannel流程
- BasicMessageChannel用于在flutter和native互相發(fā)送消息,一方給另一方發(fā)送消息,收到消息之后給出回復(fù)。
09.BasicMessageChannel基本流程
- flutter向native發(fā)送消息
- [flutter]創(chuàng)建BasicMessageChannel
- [native]通過(guò)BasicMessageChannel#MessageHandler注冊(cè)Handler
- [flutter]通過(guò)BasicMessageChannel#send發(fā)送消息
- [native]BasicMessageChannel#MessageHandler#onMessage中接收消息,然后reply
- 如圖所示
- [站外圖片上傳中...(image-51c43d-1629975250841)]
- native向flutter發(fā)送消息
- 流程也是一樣的,只是將[flutter]與[native]反調(diào)
- 如圖所示
- [站外圖片上傳中...(image-a28b6f-1629975250841)]
10.BasicMessageChannel代碼實(shí)現(xiàn)
10.1flutter端
- flutter需要完成以下工作
- 創(chuàng)建BasicMessageChannel
- 通過(guò)BasicMessageChannel#send發(fā)送消息
- 相對(duì)與其他Channel類型的創(chuàng)建,MessageChannel的創(chuàng)建除了channel名以外,還需要指定編碼方式:
BasicMessageChannel(String name, MessageCodec<T> codec, {BinaryMessenger binaryMessenger}) - 發(fā)送的消息會(huì)以二進(jìn)制的形式進(jìn)行處理,所以要針對(duì)不同類型的數(shù)進(jìn)行二進(jìn)制編碼
- 編碼類型 消息格式
- BinaryCodec 發(fā)送二進(jìn)制消息時(shí)
- JSONMessageCodec 發(fā)送Json格式消息時(shí)
- StandardMessageCodec 發(fā)送基本型數(shù)據(jù)時(shí)
- StringCodec 發(fā)送String類型消息時(shí)
- 代碼
class _MyHomePageState extends State<MyHomePage> { static const _channel = BasicMessageChannel('com.ycbjie.android/basic', StringCodec()); String _platformMessage; void _sendMessage() async { final String reply = await _channel.send('Hello World form Dart'); print(reply); } @override initState() { super.initState(); // Receive messages from platform _channel.setMessageHandler((String message) async { print('Received message = $message'); setState(() => _platformMessage = message); return 'Reply from Dart'; }); // Send message to platform _sendMessage(); }
10.2 native(android)端
- android端完成以下工作:
- 創(chuàng)建BasicMessageChannel
- 通過(guò)setHandler注冊(cè)MessageHandler
- MessageHandler#onMessage回調(diào)中接收到message后,通過(guò)reply進(jìn)行回復(fù)
- 代碼
class MainActivity: FlutterActivity() { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine) val channel = BasicMessageChannel( flutterEngine.dartExecutor.binaryMessenger, "com.ycbjie.android/basic", StringCodec.INSTANCE) // Receive messages from Dart channel.setMessageHandler { message, reply -> Log.d("Android", "Received message = $message") reply.reply("Reply from Android") } // Send message to Dart Handler().postDelayed({ channel.send("Hello World from Android") { reply -> Log.d("Android", "$reply") } }, 500) } }
11.Channel編解碼器說(shuō)明
11.1 什么是消息編解碼器
- 什么是消息編解碼器
- 在Flutter和平臺(tái)間進(jìn)行相互通信了,但是收發(fā)的數(shù)據(jù)都是二進(jìn)制的,這就需要開(kāi)發(fā)者考慮更多的細(xì)節(jié),如字節(jié)順序(大小端)和怎么表示更高級(jí)的消息類型,如字符串,map等。
- 因此,F(xiàn)lutter 還提供了消息編解碼器(Codec), 用于高級(jí)數(shù)據(jù)類型(字符串,map等)和二進(jìn)制數(shù)據(jù)(byte)之間的轉(zhuǎn)換,即消息的序列化和反序列化。
- 消息編解碼器種類有哪些
- MethodCodec:方法傳遞的編解碼器抽象,接口
- JSONMethodCodec:MethodCodec的實(shí)現(xiàn)類,會(huì)把數(shù)據(jù)打包成json結(jié)構(gòu)發(fā)送給dart,類
- StandardMethodCodec:MethodCodec的實(shí)現(xiàn)類,會(huì)把數(shù)據(jù)打包成默認(rèn)格式發(fā)送給dart,類
11.2 四種消息編解碼器類型
- BinaryCodec
- MessageCodec的實(shí)現(xiàn)類,直接發(fā)送二進(jìn)制數(shù)據(jù)
- BinaryCodec是最為簡(jiǎn)單的一種Codec,因?yàn)槠浞祷刂殿愋秃腿雲(yún)⒌念愋拖嗤?,均為二進(jìn)制格式(Android中為ByteBuffer,iOS中為NSData)。實(shí)際上,BinaryCodec在編解碼過(guò)程中什么都沒(méi)做,只是原封不動(dòng)將二進(jìn)制數(shù)據(jù)消息返回而已。或許你會(huì)因此覺(jué)得BinaryCodec沒(méi)有意義,但是在某些情況下它非常有用,比如使用BinaryCodec可以使傳遞內(nèi)存數(shù)據(jù)塊時(shí)在編解碼階段免于內(nèi)存拷貝。
- StringCodec
- MessageCodec的實(shí)現(xiàn)類,負(fù)責(zé)解碼和編碼String類型的消息
- 使用 UTF-8 編碼格式對(duì)字符串?dāng)?shù)據(jù)進(jìn)行編解碼,在Android平臺(tái)轉(zhuǎn)換為 java.util.String 類型
- JSONMessageCodec
- MessageCodec的實(shí)現(xiàn)類,負(fù)責(zé)解碼和編碼Json類型的消息
- JSONMessageCodec用于處理 JSON 數(shù)據(jù)類型(字符串型,數(shù)字型,布爾型,null,只包含這些類型的數(shù)組,和key為string類型,value為這些類型的map),在編碼過(guò)程中,數(shù)據(jù)會(huì)被轉(zhuǎn)換為JSON字符串,然后在使用 UTF-8 格式轉(zhuǎn)換為字節(jié)型。
- StandardMessageCodec
- MessageCodec的實(shí)現(xiàn)類,負(fù)責(zé)解碼和編碼默認(rèn)類型的消息
- StandardMessageCodec 可以認(rèn)為是 JSONMessageCodec 的升級(jí)版,能夠處理的數(shù)據(jù)類型要比 JSONMessageCodec 更普遍一些,且在處理 int 型數(shù)據(jù)時(shí),會(huì)根據(jù) int 數(shù)據(jù)的大小來(lái)轉(zhuǎn)為平臺(tái)端的32位類型(int)或者是64位類型(long),StandardMessageCodec 也是 Flutter Platform channel 的默認(rèn)編解碼器
11.3 編碼器的源碼分析下
- 首先看下MessageCodec
abstract class MessageCodec<T> { ByteData encodeMessage(T message); T decodeMessage(ByteData message); }
11.4 看StandardMessageCodec
- StandardMessageCodec稍微復(fù)雜
- StandardMessageCodec在寫入數(shù)據(jù)的時(shí)候,顯示寫入這個(gè)數(shù)據(jù)的類型值定義,然后在寫入其對(duì)應(yīng)的具體值,什么意思呢?
- 查看一下如何寫入指定類型的值,代碼如下所示:
protected void writeValue(ByteArrayOutputStream stream, Object value) { if (value == null || value.equals(null)) { stream.write(NULL); } else if (value == Boolean.TRUE) { stream.write(TRUE); } else if (value == Boolean.FALSE) { stream.write(FALSE); } else if (value instanceof Number) { if (value instanceof Integer || value instanceof Short || value instanceof Byte) { stream.write(INT); writeInt(stream, ((Number) value).intValue()); } else if (value instanceof Long) { stream.write(LONG); writeLong(stream, (long) value); } else if (value instanceof Float || value instanceof Double) { stream.write(DOUBLE); writeAlignment(stream, 8); writeDouble(stream, ((Number) value).doubleValue()); } else if (value instanceof BigInteger) { stream.write(BIGINT); writeBytes(stream, ((BigInteger) value).toString(16).getBytes(UTF8)); } else { throw new IllegalArgumentException("Unsupported Number type: " + value.getClass()); } } else if (value instanceof String) { stream.write(STRING); writeBytes(stream, ((String) value).getBytes(UTF8)); } else if (value instanceof byte[]) { stream.write(BYTE_ARRAY); writeBytes(stream, (byte[]) value); } else if (value instanceof int[]) { stream.write(INT_ARRAY); final int[] array = (int[]) value; writeSize(stream, array.length); writeAlignment(stream, 4); for (final int n : array) { writeInt(stream, n); } } else if (value instanceof long[]) { stream.write(LONG_ARRAY); final long[] array = (long[]) value; writeSize(stream, array.length); writeAlignment(stream, 8); for (final long n : array) { writeLong(stream, n); } } else if (value instanceof double[]) { stream.write(DOUBLE_ARRAY); final double[] array = (double[]) value; writeSize(stream, array.length); writeAlignment(stream, 8); for (final double d : array) { writeDouble(stream, d); } } else if (value instanceof List) { stream.write(LIST); final List<?> list = (List) value; writeSize(stream, list.size()); for (final Object o : list) { writeValue(stream, o); } } else if (value instanceof Map) { stream.write(MAP); final Map<?, ?> map = (Map) value; writeSize(stream, map.size()); for (final Entry<?, ?> entry : map.entrySet()) { writeValue(stream, entry.getKey()); writeValue(stream, entry.getValue()); } } else { throw new IllegalArgumentException("Unsupported value: " + value); } } - 查看一下如何讀取指定類型的值,代碼如下所示:
protected Object readValueOfType(byte type, ByteBuffer buffer) { final Object result; switch (type) { case NULL: result = null; break; case TRUE: result = true; break; case FALSE: result = false; break; case INT: result = buffer.getInt(); break; case LONG: result = buffer.getLong(); break; case BIGINT: { final byte[] hex = readBytes(buffer); result = new BigInteger(new String(hex, UTF8), 16); break; } case DOUBLE: readAlignment(buffer, 8); result = buffer.getDouble(); break; case STRING: { final byte[] bytes = readBytes(buffer); result = new String(bytes, UTF8); break; } case BYTE_ARRAY: { result = readBytes(buffer); break; } case INT_ARRAY: { final int length = readSize(buffer); final int[] array = new int[length]; readAlignment(buffer, 4); buffer.asIntBuffer().get(array); result = array; buffer.position(buffer.position() + 4 * length); break; } case LONG_ARRAY: { final int length = readSize(buffer); final long[] array = new long[length]; readAlignment(buffer, 8); buffer.asLongBuffer().get(array); result = array; buffer.position(buffer.position() + 8 * length); break; } case DOUBLE_ARRAY: { final int length = readSize(buffer); final double[] array = new double[length]; readAlignment(buffer, 8); buffer.asDoubleBuffer().get(array); result = array; buffer.position(buffer.position() + 8 * length); break; } case LIST: { final int size = readSize(buffer); final List<Object> list = new ArrayList<>(size); for (int i = 0; i < size; i++) { list.add(readValue(buffer)); } result = list; break; } case MAP: { final int size = readSize(buffer); final Map<Object, Object> map = new HashMap<>(); for (int i = 0; i < size; i++) { map.put(readValue(buffer), readValue(buffer)); } result = map; break; } default: throw new IllegalArgumentException("Message corrupted"); } return result; }
11.5 如何選擇合適編解碼器
- 編解碼的實(shí)現(xiàn)類并不復(fù)雜
- 可以先了解一下這個(gè)比較能更好的理解數(shù)據(jù)傳遞,其實(shí)不關(guān)java上層使用那種方式,最終傳遞給底層數(shù)據(jù)都是固定格式,約定統(tǒng)一的數(shù)據(jù)格式雙方才能識(shí)別出來(lái),正常的來(lái)說(shuō)用默認(rèn)的編解碼格式就可以了。
- 關(guān)于四種解碼器使用場(chǎng)景
- BinaryCodec
- 暫未找到使用的場(chǎng)景
- StringCodec
- 適用發(fā)送單一的字符串?dāng)?shù)據(jù),數(shù)據(jù)量單一的情況,比如LifecycleChannel
public void appIsInactive() { Log.v(TAG, "Sending AppLifecycleState.inactive message."); channel.send("AppLifecycleState.inactive"); } - JSONMessageCodec
- 適用數(shù)據(jù)量比較復(fù)雜的情況,比如有攜帶多個(gè)數(shù)據(jù)字段的傳遞,比如KeyEventChannel
public void keyDown(@NonNull FlutterKeyEvent keyEvent) { Map<String, Object> message = new HashMap<>(); message.put("type", "keydown"); message.put("keymap", "android"); encodeKeyEvent(keyEvent, message); channel.send(message); } - StandardMessageCodec
- 默認(rèn)的數(shù)據(jù)編解碼,絕大多數(shù)的情況下使用默認(rèn)的就可以了。比如:MethodChannel,EventChannel
- BinaryCodec
12.Channel通信可以子線程嗎
12.1 Android發(fā)送通信信息
- 首先看一下Android發(fā)送通信信息,主要分析入口是:nativeChannel.invokeMethod("setNum", a , null);
public void invokeMethod(String method, @Nullable Object arguments, Result callback) { messenger.send( name, codec.encodeMethodCall(new MethodCall(method, arguments)), callback == null ? null : new IncomingResultHandler(callback)); } - 最終定位找到DartMessenger類的send方法,代碼如下所示:
@Override public void send( @NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryMessenger.BinaryReply callback) { Log.v(TAG, "Sending message with callback over channel '" + channel + "'"); int replyId = 0; if (callback != null) { replyId = nextReplyId++; pendingReplies.put(replyId, callback); } if (message == null) { flutterJNI.dispatchEmptyPlatformMessage(channel, replyId); } else { flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId); } } - 嘗試一下子線程發(fā)送消息,發(fā)現(xiàn)會(huì)出現(xiàn)崩潰
new Thread(new Runnable() { @Override public void run() { nativeChannel.invokeMethod("setNum", a , null); } }).start(); - 崩潰信息如下所示
java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: Thread-2574 at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:992) at io.flutter.embedding.engine.FlutterJNI.dispatchPlatformMessage(FlutterJNI.java:736) at io.flutter.embedding.engine.dart.DartMessenger.send(DartMessenger.java:72) at io.flutter.embedding.engine.dart.DartExecutor$DefaultBinaryMessenger.send(DartExecutor.java:370) at io.flutter.plugin.common.MethodChannel.invokeMethod(MethodChannel.java:94) at com.ycbjie.ycandroid.channel.MethodChannelActivity.test1000(MethodChannelActivity.java:302) at com.ycbjie.ycandroid.channel.MethodChannelActivity.access$000(MethodChannelActivity.java:46) at com.ycbjie.ycandroid.channel.MethodChannelActivity$1.run(MethodChannelActivity.java:98) at java.lang.Thread.run(Thread.java:818)
12.Flutter給NA發(fā)送數(shù)據(jù)
- 從method.invokeMethod('android', map);開(kāi)始分析
@optionalTypeArgs Future<T> _invokeMethod<T>(String method, { bool missingOk, dynamic arguments }) async { assert(method != null); final ByteData result = await binaryMessenger.send( name, codec.encodeMethodCall(MethodCall(method, arguments)), ); return codec.decodeEnvelope(result) as T; } - 最后定位到_DefaultBinaryMessenger類中的send方法
Future<ByteData> _sendPlatformMessage(String channel, ByteData message) { final Completer<ByteData> completer = Completer<ByteData>(); // ui.window is accessed directly instead of using ServicesBinding.instance.window // because this method might be invoked before any binding is initialized. // This issue was reported in #27541. It is not ideal to statically access // ui.window because the Window may be dependency injected elsewhere with // a different instance. However, static access at this location seems to be // the least bad option. ui.window.sendPlatformMessage(channel, message, (ByteData reply) { try { completer.complete(reply); } catch (exception, stack) { FlutterError.reportError(FlutterErrorDetails( exception: exception, stack: stack, library: 'services library', context: ErrorDescription('during a platform message response callback'), )); } }); return completer.future; }
13.Channel通信傳遞穩(wěn)定性
- channel傳遞數(shù)據(jù)是否會(huì)丟失,如何測(cè)試呢?可以模擬,Android給flutter發(fā)送1000條信息,然后flutter給Android發(fā)送1000條信息,接下來(lái)看一下如何測(cè)試:
13.1 Android給flutter發(fā)送數(shù)據(jù)
- Android給flutter發(fā)送數(shù)據(jù),代碼如下所示
int a = 0; private void test1000() { if (nativeChannel!=null){ for (int i=0 ; i<1000 ; i++){ a++; Log.i("測(cè)試數(shù)據(jù)test1000 :", a+""); nativeChannel.invokeMethod("setNum", a , new MethodChannel.Result() { @SuppressLint("SetTextI18n") @Override public void success(@Nullable Object result) { if (result==null){ return; } Log.i("測(cè)試數(shù)據(jù):",result.toString()); } @SuppressLint("SetTextI18n") @Override public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { Log.i("測(cè)試數(shù)據(jù)異常:",errorMessage); } @Override public void notImplemented() { } }); } } } - flutter接收數(shù)據(jù)并回傳數(shù)據(jù)給Android
//接受na端傳遞過(guò)來(lái)的方法,并做出響應(yīng)邏輯處理 method.setMethodCallHandler(nativeCallHandler); // 注冊(cè)方法,等待被原生通過(guò)invokeMethod喚起 Future<dynamic> nativeCallHandler(MethodCall methodCall) async { switch (methodCall.method) { case "setNum": //獲取參數(shù) int message = await methodCall.arguments; print("原生android傳遞過(guò)來(lái)的參數(shù)為------ $message"); return "flutter回調(diào)數(shù)據(jù):${message.toString()}"; break; } }
13.2 查看數(shù)據(jù)穩(wěn)定性和及時(shí)性
- Android發(fā)送消息日志
2021-08-26 11:58:03.837 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 990 2021-08-26 11:58:03.837 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 991 2021-08-26 11:58:03.837 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 992 2021-08-26 11:58:03.837 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 993 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 994 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 995 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 996 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 997 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 998 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 999 2021-08-26 11:58:03.838 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù)test1000:: 1000 - flutter接收Android發(fā)送數(shù)據(jù)
2021-08-26 11:52:39.708 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 992 2021-08-26 11:52:39.709 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 993 2021-08-26 11:52:39.709 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 994 2021-08-26 11:52:39.709 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 995 2021-08-26 11:52:39.709 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 996 2021-08-26 11:52:39.710 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 997 2021-08-26 11:52:39.710 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 998 2021-08-26 11:52:39.710 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 999 2021-08-26 11:52:39.710 23106-23627/com.ycbjie.ychybrid I/flutter: 原生android傳遞過(guò)來(lái)的參數(shù)為------ 1000 - flutter收到消息后,回調(diào)給Android數(shù)據(jù)。Android監(jiān)聽(tīng)回調(diào)數(shù)據(jù),打印日志如下
2021-08-26 11:58:03.964 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):600 2021-08-26 11:58:03.964 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):601 2021-08-26 11:58:03.964 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):602 2021-08-26 11:58:03.965 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):603 2021-08-26 11:58:03.965 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):604 2021-08-26 11:58:03.965 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):605 2021-08-26 11:58:03.965 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):606 2021-08-26 11:58:03.966 23106-23106/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù):: flutter回調(diào)數(shù)據(jù):607 - 然后再看一波打印日志,如下所示
2021-08-26 12:07:09.158 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 1 2021-08-26 12:07:09.237 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):1 2021-08-26 12:07:09.240 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 2 2021-08-26 12:07:09.241 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 3 2021-08-26 12:07:09.241 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):2 2021-08-26 12:07:09.241 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):3 2021-08-26 12:07:09.241 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 4 2021-08-26 12:07:09.241 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):4 2021-08-26 12:07:09.241 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 5 2021-08-26 12:07:09.241 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):5 2021-08-26 12:07:09.242 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 6 2021-08-26 12:07:09.242 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):6 2021-08-26 12:07:09.242 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 7 2021-08-26 12:07:09.242 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):7 2021-08-26 12:07:09.272 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 131 2021-08-26 12:07:09.273 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):131 2021-08-26 12:07:09.273 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 132 2021-08-26 12:07:09.273 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):132 2021-08-26 12:07:09.273 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 133 2021-08-26 12:07:09.273 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):133 2021-08-26 12:07:09.273 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 134 2021-08-26 12:07:09.273 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):134 2021-08-26 12:07:09.273 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 135 2021-08-26 12:07:09.274 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):135 2021-08-26 12:07:09.274 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 136 2021-08-26 12:07:09.274 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):136 2021-08-26 12:07:09.274 24237-24990/com.ycbjie.ychybrid I/flutter: 測(cè)試數(shù)據(jù),flutter接收NA數(shù)據(jù): 137 2021-08-26 12:07:09.274 24237-24237/com.ycbjie.ychybrid I/測(cè)試數(shù)據(jù),NA接收f(shuō)lutter回調(diào):: flutter回調(diào)數(shù)據(jù):137 - 因此查看日志可以得知,傳遞數(shù)據(jù)保證了數(shù)據(jù)的時(shí)效性,發(fā)送消息和接收消息是一一對(duì)應(yīng)。并沒(méi)有失敗的情況,因此傳遞數(shù)據(jù)是穩(wěn)定的。
- 重點(diǎn)說(shuō)明,有小伙伴有疑惑,你這遍歷1000次,每次傳遞都是int值,那實(shí)際開(kāi)發(fā)中可能傳遞大json,數(shù)據(jù)量大的情況會(huì)怎樣,這個(gè)下面會(huì)說(shuō)到……
14.onActivityResult如何實(shí)現(xiàn)
- 先說(shuō)一個(gè)場(chǎng)景
- 在開(kāi)發(fā)中我們經(jīng)常會(huì)遇到關(guān)閉當(dāng)前頁(yè)面的同時(shí)返回給上一個(gè)頁(yè)面數(shù)據(jù)的場(chǎng)景,在Android中是通過(guò)startActivityForResult和onActivityResult()實(shí)現(xiàn)的。
- 而純Flutter頁(yè)面之間可以通過(guò)在Navigator.of(context).pop()方法中添加參數(shù)來(lái)實(shí)現(xiàn),那么對(duì)于Flutter頁(yè)面和Android原生頁(yè)面之間如何在返回上一頁(yè)時(shí)傳遞數(shù)據(jù)呢,通過(guò)MethodChannel就可以實(shí)現(xiàn)。
14.1 Flutter頁(yè)面返回Android原生頁(yè)面
- 在Flutter端調(diào)用原生的返回方法就可以了,首先在Flutter頁(yè)面添加一個(gè)按鈕,點(diǎn)擊按鈕返回原生頁(yè)面,代碼如下:
new Padding( padding: const EdgeInsets.only( left: 10.0, top: 10.0, right: 10.0), child: new RaisedButton( textColor: Colors.black, child: new Text('返回上一界面,并攜帶數(shù)據(jù)'), onPressed: () { Map<String, dynamic> map = {'message': '我從Flutter頁(yè)面回來(lái)了'}; String result = await method.invokeMethod('goBackWithResult', map); }), ), - Android端依然是通過(guò)判斷methodCall.method的值來(lái)執(zhí)行指定的代碼,通過(guò)methodCall.argument()獲取Flutter傳遞的參數(shù)。
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() { @Override public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) { if ("goBackWithResult".equals(methodCall.method)) { // 返回上一頁(yè),攜帶數(shù)據(jù) Intent backIntent = new Intent(); backIntent.putExtra("message", (String) methodCall.argument("message")); setResult(RESULT_OK, backIntent); finish(); } } });
14.2 Android原生頁(yè)面返回Flutter頁(yè)面
- Android原生頁(yè)面返回Flutter頁(yè)面
- 這種情況需要原生來(lái)調(diào)用Flutter代碼,和Flutter調(diào)用原生方法的步驟是一樣的。首先觸發(fā)flutter頁(yè)面按鈕,從flutter跳轉(zhuǎn)na頁(yè)面,然后觸發(fā)na頁(yè)面返回操作,返回到Flutter頁(yè)面,并傳遞數(shù)據(jù)。
- 首先是flutter頁(yè)面觸發(fā)跳轉(zhuǎn)到na頁(yè)面的代碼操作邏輯,代碼如下所示
//flutter new Padding( padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0), child: new RaisedButton( textColor: Colors.black, child: new Text('跳轉(zhuǎn)到原生逗比界面,回調(diào)結(jié)果:$_methodResult1'), onPressed: () { _jumpToNative(); }), ), //na,注意na接收到flutter指令后,na是調(diào)用startActivityForResult操作跳轉(zhuǎn)到na的新頁(yè)面 nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() { @Override public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) { if ("doubi".equals(methodCall.method)) { //接收來(lái)自flutter的指令 //跳轉(zhuǎn)到指定Activity Intent intent = new Intent(MethodChannelActivity.this, MethodResultActivity.class); startActivityForResult(intent,RESULT_OK2); //返回給flutter的參數(shù) result.success("Na收到指令"); } } }); - 然后接下來(lái)的一步是,從NA返回到flutter頁(yè)面,然后再去調(diào)用flutter方法。具體操作代碼如下所示
//na flutter觸發(fā)打開(kāi)na的新的頁(yè)面 public class MethodResultActivity extends AppCompatActivity { @SuppressLint("SetTextI18n") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_android); TextView tv = findViewById(R.id.tv); tv.setText("flutter頁(yè)面打開(kāi)NA頁(yè)面,測(cè)試Android原生頁(yè)面返回Flutter頁(yè)面"); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(); intent.putExtra("message", "我從原生頁(yè)面回來(lái)了"); setResult(RESULT_OK2, intent); finish(); } }); } } // na flutter承載容器的na的原生頁(yè)面 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (data != null && resultCode==RESULT_OK2) { // MethodResultActivity返回的數(shù)據(jù) String message = data.getStringExtra("message"); Map<String, Object> result = new HashMap<>(); result.put("message", message); // 調(diào)用Flutter端定義的方法 nativeChannel.invokeMethod("onActivityResult", result, new MethodChannel.Result() { @SuppressLint("SetTextI18n") @Override public void success(@Nullable Object result) { tvContent.setText("測(cè)試內(nèi)容2:"+result); } @SuppressLint("SetTextI18n") @Override public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { tvContent.setText("測(cè)試內(nèi)容:flutter傳遞給na數(shù)據(jù)傳遞錯(cuò)誤2"); } @Override public void notImplemented() { } }); } } //flutter Future<dynamic> handler(MethodCall call) async { switch (call.method) { case 'onActivityResult': // 獲取原生頁(yè)面?zhèn)鬟f的參數(shù) print(call.arguments['message']); return "你好,這個(gè)是從flutter傳遞過(guò)來(lái)的數(shù)據(jù)"; } } flutterChannel.setMethodCallHandler(handler);
推薦
- fluter Utils 工具類庫(kù):https://github.com/yangchong211/YCFlutterUtils
- flutter 混合項(xiàng)目代碼案例:https://github.com/yangchong211/YCVideoPlayer