Flutter使用了一個靈活的系統,允許您調用特定平臺的API,Flutter平臺特定的API支持不依賴于代碼生成,而是依賴于靈活的消息傳遞的方式:
應用的Flutter部分通過平臺通道(platform channel)將消息發送到其應用程序的所在的宿主(iOS或Android)。
宿主監聽的平臺通道,并接收該消息。然后它會調用特定于該平臺的API(使用原生編程語言) - 并將響應發送回客戶端,即應用程序的Flutter部分。
平臺通道(platform channel)
既然Flutter是通過平臺通道(platform channel)實現Flutter和原生端的數據傳遞的。那么先看下官網的架構圖
由圖一可以看出,在客戶端,MethodChannel (API)可以發送與方法調用相對應的消息。 在宿主平臺上MethodChannel 在Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法調用并返回結果。
Flutter中定義了幾種不同的channel:
根據圖二可以看出幾種channel 之間的區別
BasicMessageChannel:
通過異步傳遞message與平臺進行通信
/// A named channel for communicating with platform plugins using asynchronous
/// message passing.
EventChannel:
通過流的方式與平臺進行通信
/// A named channel for communicating with platform plugins using event streams.
MethodChannel:
通過異步方法調用的方式與平臺進行通信
/// A named channel for communicating with platform plugins using asynchronous
/// method calls.
OptionalMethodChannel:
繼承于MethodChannel 忽略了平臺
/// A [MethodChannel] that ignores missing platform plugins.
暫時拿MethodChannel進行深入分析
根據MethodChannel構造方法知道,MethodChannel對象的創建需要兩個參數 name跟MethodCodec。
name是MethodChannel的唯一標識,可以理解成channel名字。
codec是用于方法調用和封裝結果的編解碼器,決定了我們能傳遞什么類型的數據。
標準的編解碼器有如下規則:
接下來先學習下MethodChannel的使用,邊用邊分析,Flutter和native間的通信,分為 Flutter主動發送 和 native主動發送 兩種情況。
Flutter主動發送給原生
官網例子:https://github.com/flutter/flutter/tree/master/examples/platform_channel
在dart文件中的實現:
```
static const MethodChannel methodChannel =
? MethodChannel('samples.flutter.io/battery');
? Future<void> _getBatteryLevel() async {
? ? String batteryLevel;
? ? try {
? ? ? final int result = await methodChannel.invokeMethod('getBatteryLevel');
? ? ? batteryLevel = 'Battery level: $result%.';
? ? } on PlatformException {
? ? ? batteryLevel = 'Failed to get battery level.';
? ? }
? ? setState(() {
? ? ? _batteryLevel = batteryLevel;
? ? });
? }
```
```
package com.example.platformchannel;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
? private static final String BATTERY_CHANNEL = "samples.flutter.io/battery";
? private static final String CHARGING_CHANNEL = "samples.flutter.io/charging";
? @Override
? public void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? GeneratedPluginRegistrant.registerWith(this);
? ? new MethodChannel(getFlutterView(), BATTERY_CHANNEL).setMethodCallHandler(
? ? ? ? new MethodCallHandler() {
? ? ? ? ? @Override
? ? ? ? ? public void onMethodCall(MethodCall call, Result result) {
? ? ? ? ? ? if (call.method.equals("getBatteryLevel")) {
? ? ? ? ? ? ? int batteryLevel = getBatteryLevel();
? ? ? ? ? ? ? if (batteryLevel != -1) {
? ? ? ? ? ? ? ? result.success(batteryLevel);
? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? result.error("UNAVAILABLE", "Battery level not available.", null);
? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? result.notImplemented();
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? }
? ? );
? }
? private int getBatteryLevel() {
? ? if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
? ? ? BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
? ? ? return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
? ? } else {
? ? ? Intent intent = new ContextWrapper(getApplicationContext()).
? ? ? ? ? registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
? ? ? return (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
? ? ? ? ? intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
? ? }
? }
}
```
以上就是從Flutter端主動發起與native端的通信,dart通過await methodChannel.invokeMethod(‘getBatteryLevel’)發送消息,native端通過MethodChannel中MethodCallHandler的onMethodCall進行接收flutter的通信,并通過result.success進行回傳信息。
有幾點需要注意
dart中methodChannel 聲明的時候的 name要保證與native端的一致,且唯一。
dart中methodChannel.invokeMethod(‘getBatteryLevel’),在native端要進行判斷,只有方法名匹配才給予響應, if (call.method.equals(“getBatteryLevel”))。
這里flutter通過 invokeMethod與native進行通信
查看invokeMethod()方法, method為 MethodCall的標識, arguments為參數,注意這里的參數必須要遵守上面的規則(默認情況下不能直接傳自定義類,但是我們可以將其轉為Json之后再傳遞,也可以去改造 MethodCode,以此進行復雜數據結構的傳遞)。
注:可以看到,其是一個 async標記的方法,返回值為Future。那么我們在接受這個方法的返回值的時候,就必須要使用 await進行修飾。要調用使用 await,必須在有 async標記的函數中運行。具體調用和使用的方式可以看官網的例子。在這我們先繼續深入。
BinaryMessages.send()
接下來_sendPlatformMessage()——window.sendPlatformMessage()
最終調用native方法與原生進行通信的。
在flutter engine中查看源碼
看最關鍵的方法: dart_state->window()->client()->HandlePlatformMessage()
一步一步跟下來 到了 這里g_handle_platform_message_method
接下來就是 在FlutterJNI 與 FlutterNativeView 之間進行綁定了
這里就可以通過JNI調用Android 端了。
原生主動發送給Flutter
```
/**
? ? * native data to? dart
? ? */
? ? private void native2Dart() {
? ? ? ? /**
? ? ? ? * 數據流的通信(event streams)
? ? ? ? */
? ? ? ? EventChannel eventChannel = new EventChannel(getFlutterView(), EVENT_CHANNEL);
? ? ? ? EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onListen(Object arguments, EventSink eventSink) {
? ? ? ? ? ? ? ? Log.e("plateform_channel", "arguments: " + arguments.toString());
? ? ? ? ? ? ? ? eventSink.success(data);
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onCancel(Object arguments) {
? ? ? ? ? ? ? ? Log.e("plateform_channel", "arguments: " + arguments.toString());
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? eventChannel.setStreamHandler(streamHandler);
? ? }
```
Flutter端:
```
static const EventChannel eventChannel =
? EventChannel(FlutterChannel.CHANNEL_RECEIVE_DATA);
? @override
? void initState() {
? ? super.initState();
? ? eventChannel.receiveBroadcastStream(['arg1', 'arg2']).listen(_onEvent,
? ? ? ? onError: _onError);
? }
? void _onEvent(Object event) {
? ? var animal = json.decode(event);
? ? print(AnimalsRoot.fromJson(animal).animals.cat.name);
? ? setState(() {
? ? ? _receive_data = '$event';
? ? });
? }
? void _onError(Object error) {
? ? setState(() {
? ? ? _receive_data = 'Receive? failed';
? ? });
? }
```
用圖表示其中的關聯就是