在使用Flutter開發app時,會遇到跟Android原生系統API交互的情況,
通常可以使用Flutter來寫頁面,複用原來已有的Android的邏輯(如自己的或者第三方的SDK),來加快開發進度。
可以使用插件來解決,官網關於插件的開發介紹:
撰寫雙端平臺代碼(插件編寫實現)
文中列出了一個完整的demo:
注意:可在 /examples/platform_channel/ 中獲得使用 Java 實現的 Android 及使用 Objective-C 實現的 iOS 的該示例完整可運行的代碼。對於用 Swift 實現的 iOS 代碼,請參閱 /examples/platform_channel_swift/。
Channel
Flutter定義了三種不同類型的Channel,它們分別是
- BasicMessageChannel:用於傳遞字符串和半結構化的信息,可以雙向的請求數據。
- MethodChannel:用於傳遞方法調用(method invocation,即Flutter端可以調用Platform端的方法並通過Result接口回調結果數據。
- EventChannel: 用於數據流(event streams)的通信,即Flutter端監聽Platform端的實時消息,一旦Platform端產生了數據,立即回調到Flutter端。
⚠️注意:在Android和iOS平臺上,Platform Task Runner跑在主線程上。因此,不應該在Platform端的Handler中處理耗時操作。
先看一下MethodChannel和EventChannel的使用
main.dart文件如下:
class PlatformChannel extends StatefulWidget {
@override
_PlatformChannelState createState() => _PlatformChannelState();
}
class _PlatformChannelState extends State<PlatformChannel> {
static const MethodChannel methodChannel =
MethodChannel('samples.flutter.io/battery');
static const EventChannel eventChannel =
EventChannel('samples.flutter.io/charging');
String _batteryLevel = 'Battery level: unknown.';
String _chargingStatus = 'Battery status: unknown.';
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;
});
}
@override
void initState() {
super.initState();
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
void _onEvent(Object event) {
setState(() {
_chargingStatus =
"Battery status: ${event == 'charging' ? '' : 'dis'}charging.";
});
}
void _onError(Object error) {
setState(() {
_chargingStatus = 'Battery status: unknown.';
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_batteryLevel, key: const Key('Battery level label')),
Padding(
padding: const EdgeInsets.all(16.0),
child: RaisedButton(
child: const Text('Refresh'),
onPressed: _getBatteryLevel,
),
),
],
),
Text(_chargingStatus),
],
),
);
}
}
void main() {
runApp(MaterialApp(home: PlatformChannel()));
}
1. 使用MethodChannel步驟
- 其中定義了一個
MethodChannel
對象,使用methodChannel
的invokeMethod('getBatteryLevel')
方法可以調用到Android原生的方法, - 在Android定義MethodChannel對象,並調用其setMethodCallHandler方法,在回調接口MethodCallHandler中實現onMethodCall方法,通過Result對象回傳值到Flutter端。
private static final String BATTERY_CHANNEL = "samples.flutter.io/battery";
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();
}
}
}
);
在該MethodCallHandler
回調中處理Flutter部分發來的方法調用請求,並通過result.success(batteryLevel)
傳遞迴數據。
這是直接能獲取到Android端立即返回值的情況,但是通常Android端是異步操作,並在接口回調中返回值,那這時如何將值再傳遞到Flutter端呢?這時就可以使用EventChannel
了。
2. 使用EventChannel步驟
- 在Android端定義EventChannel對象,並調用setStreamHandler()方法,在匿名內部類StreamHandler裏實現onListen和onCancel方法,通過EventSink對象來回傳數據到Flutter端,
- Flutter端通過
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
來定義_onEvent
函數和_onError
函數處理傳回的值。
new EventChannel(getFlutterView(), CHARGING_CHANNEL).setStreamHandler(
new StreamHandler() {
private BroadcastReceiver chargingStateChangeReceiver;
@Override
public void onListen(Object arguments, EventSink events) {
chargingStateChangeReceiver = createChargingStateChangeReceiver(events);
registerReceiver(
chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object arguments) {
unregisterReceiver(chargingStateChangeReceiver);
chargingStateChangeReceiver = null;
}
}
);
3. 使用BasicMessageChannel步驟
Android端:
dart端: