在使用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端: