flutter 与 Android/iOS 混编避免不了两者之间的通信, flutter 提供了 Platform-Channel.
Platform-Channel 的信息传递如图:
信息的传递是异步的, 为了防止 UI 卡顿.
通过 Channel,flutter 可以调用 Android/iOS 的代码, Android/iOS 也可以调用 flutter 的代码.
不同语言之间的相互调用, 类型首先要有映射, 如下:
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, if 32 bits not enough | java.lang.Long | NSNumber numberWithLong: |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] FlutterStandardTypedData | typedDataWithBytes: |
Int32List | int[] FlutterStandardTypedData | typedDataWithInt32: |
Int64List | long[] FlutterStandardTypedData | typedDataWithInt64: |
Float64List | double[] FlutterStandardTypedData | typedDataWithFloat64: |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
示例一: Flutter 调用 Android/iOS 的方法
1,dart 里调用
首先 dart 定义一个 MethodChannel 对象
传入名称'samples.flutter.io/battery', 这个名称需要全局唯一.
点击按钮后, 调用_getBatteryLevel(),_getBatteryLevel() 是异步的, 函数体通过 channel.invokeMethod 调用 Android/iOS 的 getBatteryLevel 方法. 如果 Android/iOS 没有定义, 则会抛出异常, 所以先价格 try-catch.
- 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.
- 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;
- });
- }
- @override
- Widget build(BuildContext context) {
- return Material(
- child: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- RaisedButton(
- child: Text('Get Battery Level'),
- onPressed: _getBatteryLevel,
- ),
- Text(_batteryLevel),
- ],
- ),
- ),
- );
- }
- }
2,Android 注册方法
传入的名称 samples.flutter.io/battery 要保持一致, onMethodCall 里去判断方法名, 然后去调用对应的方法.
- private int getBatteryLevel() {
- int batteryLevel = -1;
- if (Build.VERSION.SDK_INT>= Build.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;
- }
- @Override
- protected void onResume() {
- super.onResume();
- FlutterView flutterView = (FlutterView) fragment.getView();
- // 或者直接通过 Flutter.createView 获取 flutterView
- new MethodChannel(flutterView, CHANNEL).setMethodCallHandler(
- new MethodChannel.MethodCallHandler() {
- @Override
- public void onMethodCall(MethodCall call, MethodChannel.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();
- }
- }
- });
- }
3,iOS 注册方法
往 flutterViewController 里注册方法
flutterViewControlle 哪里来? 见 [flutter 第 1 回] 混编 http://ie8384.com/blog/index.php/archives/1607/
- FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.io/battery"
- binaryMessenger:flutterViewController];
- __weak typeof(self) weakSelf = self;
- [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
- if ([@"getBatteryLevel" isEqualToString:call.method]) {
- int batteryLevel = [weakSelf getBatteryLevel];
- if (batteryLevel == -1) {
- result([FlutterError errorWithCode:@"UNAVAILABLE"
- message:@"Battery info unavailable"
- details:nil]);
- } else {
- result(@(batteryLevel));
- }
- } else {
- result(FlutterMethodNotImplemented);
- }
- }];
定义方法 getBatteryLevel
- - (int)getBatteryLevel {
- UIDevice* device = UIDevice.currentDevice;
- device.batteryMonitoringEnabled = YES;
- if (device.batteryState == UIDeviceBatteryStateUnknown) {
- return -1;
- } else {
- return (int)(device.batteryLevel * 100);
- }
- }
示例二: Android/iOS 调用 flutter 的方法
channel 是允许双向通信的, Android /iOS 和 flutter 的角色互换一下.
以下就是关键的代码了.
1,Dart 里注册方法
- Channel.setMethodCallHandler((MethodCall call) async {
- assert(call.method == 'launch');
- handler(call.arguments);
- });
2,Android 里调用
channel.invokeMethod("launch", type);
3,iOS 里调用
[self.channel invokeMethod:@"launch" arguments:shortcutItem.type];
来源: https://juejin.im/entry/5c0e8e546fb9a049d81bb06c