日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Flutter如何与Native(Android)进行交互

發布時間:2024/4/15 Android 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Flutter如何与Native(Android)进行交互 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

前言

BasicMessageChannel

Android端-

(1)不使用engine?cache預熱

(2)使用engine cache預熱

Flutter端-

MethodChannel

Android端=

Flutter端=

源碼分析=

EventChannel

Android端+

Flutter端+

源碼分析+

總結


前言

上一篇文章Flutter混合開發:Android中如何啟動Flutter中我們介紹了如何在Native(Android項目)中啟動Flutter,展示Flutter頁面。但是在開發過程中,很多時候并不是簡單的展示一個頁面即可,還會涉及到各種交互,比如傳遞一些消息。

本篇文章就簡單介紹一下Flutter與原生Native的三種交互方式:

BasicMessageChannel、MethodChannel和EventChannel。

BasicMessageChannel

雖然說是三種交互方式,但是其實本質都是一種,這個我們后面會解釋。


先來看看BasicMessageChannel。它可以實現雙方交互,發送一些簡單消息,消息類型Object,但是并不是所有Object都可以,基礎類型及基礎類型的數組、list、map是可以的。這個可以參考BasicMessageChannel的源碼:

public void send(@Nullable T message, @Nullable final Reply<T> callback) {messenger.send(name,codec.encodeMessage(message),callback == null ? null : new IncomingReplyHandler(callback));}

可以看到進行了encode,這個codec一般是StandardMessageCodec,它的encodeMessage函數源碼:

public ByteBuffer encodeMessage(Object message) {if (message == null) {return null;}final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();writeValue(stream, message);final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());buffer.put(stream.buffer(), 0, stream.size());return buffer;}

這里writeValue的源碼:

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

下面看一下如何來使用它,以Android端為例。

Android端-

(1)不使用engine?cache預熱

如果不使用engine cache,那么在FlutterActivity的繼承類中重寫configureFlutterEngine:

class MainActivity : FlutterActivity() {var channel : BasicMessageChannel? = nulloverride fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)var channel = BasicMessageChannel<String>(flutterEngine.dartExecutor.binaryMessenger,"test" ,StringCodec.INSTANCE)channel.setMessageHandler { message, reply ->Log.e("recieve", message)}} }

注意這里第二個參數"test"是這通道(channel)的名稱,兩邊名稱一致才能進行通信。

第三個參數是消息的編解碼器,這里我們因為是簡單的示例,消息是字符串String,所以用StringCodec。

StringCodec是MessageCodec接口的實現,除了它還有BinaryCodec,JsonMessageCodec,StandardMessageCodec。另外我們還可以自己實現MessageCodec,實現它的兩個函數即可,它的源碼如下:

public interface MessageCodec<T> {/*** Encodes the specified message into binary.** @param message the T message, possibly null.* @return a ByteBuffer containing the encoding between position 0 and the current position, or* null, if message is null.*/@NullableByteBuffer encodeMessage(@Nullable T message);/*** Decodes the specified message from binary.** @param message the {@link ByteBuffer} message, possibly null.* @return a T value representation of the bytes between the given buffer's current position and* its limit, or null, if message is null.*/@NullableT decodeMessage(@Nullable ByteBuffer message); }

最后,MessageHandler用于接受從Flutter傳遞過來的消息。這里簡單的將消息打印出來。

當需要向flutter發送消息時,執行:

channel?.send("android call")

即可

(2)使用engine cache預熱

一般情況我們在Application中添加cache,如下:

class App : Application() {companion object{...lateinit var flutterEngine2 : FlutterEngine}override fun onCreate() {super.onCreate()...flutterEngine2 = FlutterEngine(this)flutterEngine2.navigationChannel.setInitialRoute("second")flutterEngine2.dartExecutor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())FlutterEngineCache.getInstance().put("second", flutterEngine2)} }

這里我們為second這個flutter頁面創建engine并加入cache進行預熱。

如果我們想使用這個engine發送消息,那么可以直接創建BasicMessageChannel

var channel = BasicMessageChannel<String>(App.flutterEngine2.dartExecutor.binaryMessenger,"test" ,StandardMessageCodec.INSTANCE as MessageCodec<String>) channel.setMessageHandler { message, reply ->Log.e("recieve", message) }

后續與上面就一樣了。

Flutter端-

步驟基本一樣,先創建

static const messageChannel = const BasicMessageChannel("test", StringCodec());

這里通道名稱保持與native一致。

設置回調:

messageChannel.setMessageHandler((message) async{print(message)});

發送消息:

messageChannel.send("flutter call");

這樣就實現了Native和Flutter的雙向消息交互。

MethodChannel

用于雙方函數的調用,使用方法與BasicMessageChannel相似,其實本質上是一樣的。我們先來看看如何使用它。

Android端=

與BasicMessageChannel一樣預熱和不預熱可以有兩種不同的處理,但是其實最終都是獲取到FlutterEngine對象,所以就不贅述了,直接使用即可。代碼如下:

//創建var channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger,"test")//回調,根據call執行native函數channel.setMethodCallHandler { call, result ->when(call.method){"flutterCall" -> {//執行我們自定義的對應函數flutterCall(call.arguments)}else -> {}}}

這里flutterCall是響應Flutter發送過來的請求,我們定義一個對應的函數來處理,如:

fun flutterCall(arguments : Object){Log.e("flutterCall", "message:" + arguments.toString())}

然后我們可以通過invokeMethod函數來執行Flutter函數,如:

//執行flutter函數channel.invokeMethod("androidCall", "android message")

Flutter端=

流程一樣,代碼如下:

//創建 static const methodChannel = const MethodChannel("test"); //回調,根據call執行flutter函數methodChannel.setMethodCallHandler((call) async {switch(call.method){case "androidCall"://執行自定義的對應函數androidCall(call.arguments);break;}}); //執行native函數 methodChannel.invokeMethod("flutterCall", "flutter message");

源碼分析=

在分析BasicMessageChannel時我們知道它的send函數其實是調用了messenger.send(...),這個messenger是BinaryMessenger,就是構造函數的第一個參數。MethodCannel也是一樣,它的invokeMethod函數源碼如下:

@UiThreadpublic void invokeMethod(String method, @Nullable Object arguments, @Nullable Result callback) {messenger.send(name,codec.encodeMethodCall(new MethodCall(method, arguments)),callback == null ? null : new IncomingResultHandler(callback));}

可以看到,最終還是調用了BinaryMessenger的send函數。只不過將invokeMethod的兩個參數(String類型的函數名method和Object類型的參數arguments)封裝到MethodCall中。

再來看回調的處理,上面invokeMethod函數中可以看到,用IncomingResultHandler將callback進行了封裝,它的關鍵源碼如下:

private final class IncomingMethodCallHandler implements BinaryMessageHandler {private final MethodCallHandler handler;IncomingMethodCallHandler(MethodCallHandler handler) {this.handler = handler;}@Override@UiThreadpublic void onMessage(ByteBuffer message, final BinaryReply reply) {final MethodCall call = codec.decodeMethodCall(message);try {handler.onMethodCall(call,new Result() {...});} catch (RuntimeException e) {...}}...}

可以看到在收到消息onMessage后先將消息解析成MethodCall在執行callback,這樣就可以直接獲取到函數名及參數了。

通過上面我們知道MethodChannel和BasicMessageChannel本質是一樣的,只不過經過了一層MethodCall的封裝,方便直接獲取函數名和參數。

EventChannel

EventChannel與上面兩個都不太一樣,它是flutter發起,native處理并返回結果,flutter再處理結果。說它是單方向通道也不是很準確,但是native無法主動發起,所以更像是一個c/s結構。

先來看看如何使用。

Android端+

同樣需要FlutterEngine對象,代碼如下:

//創建 var channel = EventChannel(flutterEngine.dartExecutor.binaryMessenger,"test") //設置處理handler channel.setStreamHandler(object : StreamHandler(), EventChannel.StreamHandler {override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {//根據arguments處理arguments?.let {...//將處理結果返回,可能成功也可能失敗events?.success("android back")//events?.error("errorcode", "errormssage", null)//如果不返回,即success和error都不執行,則需要執行endOfStream//events?.endOfStream()}}override fun onCancel(arguments: Any?) {//執行取消操作} })

上面提到Native無法主動發起,所以就沒有類似上面send或invokeMethod函數。

Flutter端+

通過receiveBroadcastStream來發送event請求,并通過linsten來監聽返回。

//創建 static const eventChannel = const EventChannel("test"); //發送arguments給native處理,并監聽結果 eventChannel.receiveBroadcastStream(["flutter event"]).listen((event) {//返回成功結果,處理print(event.toString()); }, onError: (event){//返回錯誤結果,處理 }, onDone: (){//執行完成處理 });

源碼分析+

總結

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的Flutter如何与Native(Android)进行交互的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。