所谓“平台特定”或“特定平台”,平台指的就是原生Android或IOS,本文主要讲原生和Flutter之间如何通信、如何进行功能互调。
Flutter使用了一个灵活的系统,允许您调用特定平台的API,无论在Android上的Java或Kotlin代码中,还是iOS上的ObjectiveC或Swift代码中均可用。
Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:
应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)。
宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言) - 并将响应发送回客户端,即应用程序的Flutter部分。
使用平台通道在客户端(Flutter UI)和宿主(平台)之间传递消息,如下图所示:
消息和响应是异步传递的,以确保用户界面保持响应(不会挂起)。
在客户端,MethodChannel
(API)可以发送与方法调用相对应的消息。 在宿主平台上,MethodChannel
在Android((API) 和 FlutterMethodChannel iOS (API) 可以接收方法调用并返回结果。这些类允许您用很少的“脚手架”代码开发平台插件。
注意: 如果需要,方法调用也可以反向发送,宿主作为客户端调用Dart中实现的API。
标准平台通道使用标准消息编解码器,以支持简单的类似JSON值的高效二进制序列化,例如 booleans,numbers, Strings, byte buffers, List, Maps(请参阅StandardMessageCodec
了解详细信息)。 当您发送和接收值时,这些值在消息中的序列化和反序列化会自动进行。
如果您希望在多个Flutter应用程序中使用特定于平台的代码,将代码分离为位于主应用程序之外的目录中,做一个平台插件会很有用。
如果您希望与Flutter生态系统中的其他开发人员分享您的特定平台的代码,请参阅发[发布 packages](/developing-packages/#publish以了解详细信息。
除了上面提到的MethodChannel
,你还可以使用BasicMessageChannel
,它支持使用自定义消息编解码器进行基本的异步消息传递。 此外,您可以使用专门的BinaryCodec
,StringCodec
和 JSONMessageCodec
类,或创建自己的编解码器。
代码示例:
1.Flutter代码:
//使用平台通道编写平台特定的代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main(){
runApp(MaterialApp(
home: PlatformChannel(),
));
}
class PlatformChannel extends StatefulWidget {
@override
_PlatformChannelState createState() => _PlatformChannelState();
}
class _PlatformChannelState extends State {
static const MethodChannel methodChannel = MethodChannel('yinlei/battery');
static const EventChannel eventChannel = EventChannel('yinlei/charging');
String _batteryLevel = '当前电量: 未知.';
String _chargingStatus = '电量状态: 未知.';
Future _getBatteryLevel() async{
String batteryLevel;
try{
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = '当前电量: $result%.';
} on PlatformException{
batteryLevel = '获取当前电量失败。';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
@override
void initState() {
super.initState();
eventChannel.receiveBroadcastStream().listen(_onEvent,onError: _onError);
}
void _onEvent(Object event){
setState(() {
_chargingStatus = '当前电量状态: ${event == 'charging' ? '正在' : '未在'}充电.';
});
}
void _onError(Object error){
setState(() {
_chargingStatus = '电量状态未知出错。';
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_batteryLevel,key: const Key('当前电量'),),
Padding(
padding: const EdgeInsets.all(16.0),
child: RaisedButton(
child: const Text('刷新'),
onPressed: _getBatteryLevel,
),
),
],
),
Text(_chargingStatus),
],
),
);
}
}
2.android代码:
package com.example.flutter_batterylevel;
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;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private static final String BATTERY_CHANNEL = "yinlei/battery";
private static final String CHARGING_CHANNEL = "yinlei/charging";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new EventChannel(getFlutterView(),CHARGING_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {
private BroadcastReceiver chargingStateChangeReceiver;
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
chargingStateChangeReceiver = createChargingStateChangeReceiver(eventSink);
registerReceiver(chargingStateChangeReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object o) {
unregisterReceiver(chargingStateChangeReceiver);
chargingStateChangeReceiver = null;
}
});
new MethodChannel(getFlutterView(),BATTERY_CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if(methodCall.method.equals("getBatteryLevel")){
int batteryLevel = getBatteryLevel();
if(batteryLevel != -1){
result.success(batteryLevel);
}else {
result.error("不可依赖。","当前电量等级不可依赖。",null);
}
}else {
result.notImplemented();
}
}
});
}
private BroadcastReceiver createChargingStateChangeReceiver(final EventChannel.EventSink eventSink){
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,-1);
if(status == BatteryManager.BATTERY_STATUS_UNKNOWN){
eventSink.error("不可依赖的","充电状态是不可依赖的。",null);
}else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
eventSink.success(isCharging ? "正在充电" : "未在充电");
}
}
};
}
private int getBatteryLevel(){
if(Build.VERSION.SDK_INT >= Build.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);
}
}
}
3.权限:
运行结果: