这篇,想要介绍一下 Flutter 如何把某些功能打包给原生的 Android、Ios 写。将会介绍官方的 Sample。
https://flutter.dev/docs/development/platform-integration/platform-channels?tab=android-channel-java-tab 文件
这篇将会透过取得电池电量为范例。
图片撷取来自官网 => https://flutter.dev/assets/images/docs/PlatformChannels.png
可以看到 Flutter 和 IOS、Android,都是透过 MethodChannel 来交流、交换资料。MethodChannel 是一个沟通的桥梁。invokeMethod 则是可以让 android、ios 原生的程序码知道 flutter 要呼叫的方法是哪一个。
可以看到这边 Flutter 在 state 里面宣告了一个 MethodChannel。
class _MyHomePageState extends State<MyHomePage> {
static const platform = MethodChannel('samples.flutter.dev/battery');
// Get battery level.
}
可以看到,这边我们定义了一个 result 用来接收电量资讯,我们透过 platform(MethodChannel),去取得 invokeMethod == getBatteryLevel 的 android 原生方法。
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
Future<void> _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 = batteryLevel;
});
}
UI
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
child: Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel),
],
),
),
);
}
这边建议撰写时,另外开一个 Android Sutdio Project,这样 Android Studio 会比较好编辑。
这边我们可以宣告一个 Channel 会等於 Flutter 的 Channel。
接下来我们在初始化 MethodChannel(这边要和 flutter 写的一样),并在 configureFlutterEngine 里面设置一个 MethodCallHandler 的 interface。
这边,如果你有用另外开一个 Android 的 project,就可以很快速 import 了。
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.dev/battery";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
// Note: this method is invoked on the main thread.
// TODO
}
);
}
}
写一个读取店员资运的方法
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;
}
接着我们可以把程序码写在 (call, result) ->{} 里面,这个 call back 会有一个 call 的参数,
这个 call 的参数对应的就是 Flutter 里面的 MethodChannel.invokeMethod('call 的参数')。
result 则会有一个 success 和 error。success 的话就会回传给 flutter 正确资料。如果是 error 的话就会回传给 flutter PlatformException。
(call, result) -> {
// Note: this method is invoked on the main thread.
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();
}
}
Ios 则是透过 FlutterViewController 和 FlutterMethodChannel,并一样会有一个 setMethodCallHandler 的 interface,一样会有 call 和 result 的参数。
附上完整程序码
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
guard call.method == "getBatteryLevel" else {
result(FlutterMethodNotImplemented)
return
}
self?.receiveBatteryLevel(result: result)
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func receiveBatteryLevel(result: FlutterResult) {
let device = UIDevice.current
device.isBatteryMonitoringEnabled = true
if device.batteryState == UIDevice.BatteryState.unknown {
result(FlutterError(code: "UNAVAILABLE",
message: "Battery info unavailable",
details: nil))
} else {
result(Int(device.batteryLevel * 100))
}
}
}
既然空间有维度, 阵列也像是空间一样, 他是拥有维度的, 就让我们探索看看吧 二维阵列 就如同象棋棋...
不怎麽重要的前言 上一篇介绍了需要与if条件式结合且与回圈控制有关的语法,基本上我们已经把基础的程序...
学习任何东西,都要把基础学的扎实,基础稳了,遇到问题就能迎刃而解。 而学习程序语言的基础就是数学逻...
Hello 大家, 要放假了~ 想每天放假还是有钱XD App Store这个分类就只有两项, 先来...
“Slept, awoke, slept, awoke, miserable life.” ― f...