Flutter和Native的通信是通過Channel來完成的。
Flutter使用了一個靈活的系統,允許您調用特定平臺的API,無論在Android上的Java或Kotlin代碼中,還是iOS上的ObjectiveC或Swift代碼中均可用。
Flutter與原生之間的通信依賴靈活的消息傳遞方式:
- 應用的Flutter部分通過平臺通道(platform channel)將消息發送到其應用程序的所在的宿主(iOS或Android)應用(原生應用)。
- 宿主監聽平臺通道,并接收該消息。然后它會調用該平臺的API,并將響應發送回客戶端,即應用程序的Flutter部分。
Flutter通信
當在Flutter中調用原生方法時,調用信息通過平臺通道傳遞到原生,原生收到調用信息后方可執行指定的操作,如需返回數據,則原生會將數據再通過平臺通道傳遞給Flutter。值得注意的是消息傳遞是異步的,這確保了用戶界面在消息傳遞時不會被掛起。
在客戶端,MethodChannel API 可以發送與方法調用相對應的消息。 在宿主平臺上,MethodChannel
在Android API 和 FlutterMethodChannel iOS API可以接收方法調用并返回結果。這些類可以幫助我們用很少的代碼就能開發平臺插件。
創建實例
- 首先創建一個新的應用程序:
flutter create batterylevel
// 默認情況下,模板支持使用Java編寫Android代碼,或使用Objective-C編寫iOS代碼。
// 要使用Kotlin或Swift,請使用-i和/或-a標志:
flutter create -i swift -a kotlin batterylevel
- 構建通道。通過 MethodChannel 來獲取電池電量。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class _MyHomePageState extends State<MyHomePage> {
static const platform = const MethodChannel('samples.flutter.io/battery');
// Get battery level.
}
接下來,我們調用通道上的方法,指定通過字符串標識符調用方法getBatteryLevel
。 該調用可能失敗(平臺不支持平臺API,例如在模擬器中運行時),所以我們將invokeMethod調用包裝在try-catch語句中。
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
Future<Null> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
// 在setState中來更新用戶界面狀態batteryLevel。
setState(() {
_batteryLevel = batteryLevel;
});
}
最后,我們在build創建包含一個小字體顯示電池狀態和一個用于刷新值的按鈕的用戶界面。
@override
Widget build(BuildContext context) {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new RaisedButton(
child: new Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
new Text(_batteryLevel),
],
),
),
);
}
- android 端接口實現
在java目錄下打開 MainActivity.java的onCreate
里創建MethodChannel
并設置一個MethodCallHandler
。確保使用和Flutter客戶端中使用的通道名稱相同的名稱。
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.io/battery";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
});
}
}
@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() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
Flutter定義了三種不同類型的Channel:
- BasicMessageChannel:用于傳遞字符串和半結構化的信息,持續通信,收到消息后可以回復此次消息,如:Native將遍歷到的文件信息陸續傳遞到Dart,在比如:Flutter將從服務端陸陸續獲取到信息交個Native加工,Native處理完返回等;
import 'package:flutter/services.dart';
static const BasicMessageChannel _basicMessageChannel =
const BasicMessageChannel('BasicMessageChannelPlugin', StringCodec());
//使用BasicMessageChannel接受來自Native的消息,并向Native回復
_basicMessageChannel
.setMessageHandler((String message) => Future<String>(() {
setState(() {
showMessage = message;
});
return "收到Native的消息:" + message;
}));
//使用BasicMessageChannel向Native發送消息,并接受Native的回復
String response;
try {
response = await _basicMessageChannel.send(value);
} on PlatformException catch (e) {
print(e);
}
public class BasicMessageChannelPlugin implements BasicMessageChannel.MessageHandler<String>, BasicMessageChannel.Reply<String> {
private final Activity activity;
private final 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<>(flutterView, "BasicMessageChannelPlugin", StringCodec.INSTANCE);
//設置消息處理器,處理來自Dart的消息
messageChannel.setMessageHandler(this);
}
@Override
public void onMessage(String s, BasicMessageChannel.Reply<String> reply) {//處理Dart發來的消息
reply.reply("BasicMessageChannel收到:" + s);//可以通過reply進行回復
if (activity instanceof IShowMessage) {
((IShowMessage) activity).onShowMessage(s);
}
Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
}
/**
* 向Dart發送消息,并接受Dart的反饋
*
* @param message 要給Dart發送的消息內容
* @param callback 來自Dart的反饋
*/
void send(String message, BasicMessageChannel.Reply<String> callback) {
messageChannel.send(message, callback);
}
@Override
public void reply(String s) {
}
}
- MethodChannel:用于傳遞方法調用(method invocation)一次性通信:如Flutter調用Native拍照;
- EventChannel: 用于數據流(event streams)的通信,持續通信,收到消息后無法回復此次消息,通常用于Native向Dart的通信,如:手機電量變化,網絡連接變化,陀螺儀,傳感器等;
import 'package:flutter/services.dart';
...
static const EventChannel _eventChannelPlugin =
EventChannel('EventChannelPlugin');
StreamSubscription _streamSubscription;
@override
void initState() {
_streamSubscription=_eventChannelPlugin
.receiveBroadcastStream()
.listen(_onToDart, onError: _onToDartError);
super.initState();
}
@override
void dispose() {
if (_streamSubscription != null) {
_streamSubscription.cancel();
_streamSubscription = null;
}
super.dispose();
}
void _onToDart(message) {
setState(() {
showMessage = message;
});
}
void _onToDartError(error) {
print(error);
}
public interface StreamHandler {
void onListen(Object args, EventChannel.EventSink eventSink);
void onCancel(Object o);
}
public class EventChannelPlugin implements EventChannel.StreamHandler {
private List<EventChannel.EventSink> eventSinks = new ArrayList<>();
static EventChannelPlugin registerWith(FlutterView flutterView) {
EventChannelPlugin plugin = new EventChannelPlugin();
new EventChannel(flutterView, "EventChannelPlugin").setStreamHandler(plugin);
return plugin;
}
void sendEvent(Object params) {
for (EventChannel.EventSink eventSink : eventSinks) {
eventSink.success(params);
}
}
@Override
public void onListen(Object args, EventChannel.EventSink eventSink) {
eventSinks.add(eventSink);
}
@Override
public void onCancel(Object o) {
}
}
這三種類型的類型的Channel都是全雙工通信,即A <=> B,Dart可以主動發送消息給platform端,并且platform接收到消息后可以做出回應,同樣,platform端可以主動發送消息給Dart端,dart端接收數后返回給platform端。