先来个图
1. Flutter调原生方法并返回结果给Flutter
先添加一个交互事件
RaisedButton(
onPressed: invokeNativeGetResult,
child: Text('Invoke Native function get callback result'),
),
flutter调用方法
static const platform = const MethodChannel('qd.flutter.io/qd_present'); // 交互通道
String nativeBackString = 'Not Return';
Future<void> invokeNativeGetResult() async {
String backString;
try {
// 调用原生方法并传参,以及等待原生返回结果数据
var result = await platform.invokeMethod(
'getNativeResult', {"key1": "value1", "key2": "value2"});
backString = 'Native return $result';
} on PlatformException catch (e) {
backString = "Failed to get native return: '${e.message}'.";
}
setState(() {
nativeBackString = backString;
});
}
iOS接收事件
self.flutterPresentVC = [[FlutterViewController alloc] init];
[self.flutterPresentVC setInitialRoute:@"presentPage"];
[self presentViewController:self.flutterPresentVC animated:false completion:nil];
FlutterMethodChannel *presentChannel = [FlutterMethodChannel methodChannelWithName:@"qd.flutter.io/qd_present" binaryMessenger:self.flutterPresentVC];
__weak typeof(self) weakSelf = self;
__weak typeof(presentChannel) wsChannel = presentChannel;
// 注册方法等待flutter页面调用
[presentChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
NSLog(@"%@", call.method);
NSLog(@"%@", result);
if ([call.method isEqualToString:@"getNativeResult"]) {
NSString *name = [weakSelf getDeiveName];
if (name == nil) {
FlutterError *error = [FlutterError errorWithCode:@"UNAVAILABLE" message:@"Device info unavailable" details:nil];
result(error);
} else {
// 通过result返回给Flutter回调结果
result(name);
}
// 下面是原生又调用了Flutter方法
// 原生调用Flutter方法,带参数, 接收回传结果并弹窗
[wsChannel invokeMethod:@"flutterMedia" arguments:@{@"key1": @"value1"} result:^(id _Nullable result) {
NSLog(@"%@", result);
[weakSelf showAlert:result];
}];
} else if ([call.method isEqualToString:@"dismiss"]) {
[weakSelf.flutterPresentVC dismissViewControllerAnimated:YES completion:nil];
} else if ([call.method isEqualToString:@"presentNativeSecondPage"]) {
NativeSecondVC *secondVC = [[NativeSecondVC alloc] init];
[self.flutterPresentVC presentViewController:secondVC animated:YES completion:nil];
}
else {
result(FlutterMethodNotImplemented);
}
}];
- (NSString *)getDeiveName {
UIDevice *device = UIDevice.currentDevice;
return device.name;
}
2. 原生调用Flutter方法并返回结果给原生
我新建了一个VC继承FlutterViewController
NativeFlutterVC.h
#import <Flutter/Flutter.h>
@interface NativeFlutterVC : FlutterViewController
- (void)gotoBack;
@end
NativeFlutterVC.m
#import "NativeFlutterVC.h"
#import <Flutter/Flutter.h>
#import "NativeSecondVC.h"
@interface NativeFlutterVC ()
@property (nonatomic, strong) FlutterMethodChannel *pushChannel;
@end
@implementation NativeFlutterVC
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(gotoBack)];
if (self.navigationController != nil) {
self.navigationItem.leftBarButtonItem = backItem;
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.pushChannel) {
return;
}
__weak typeof(self) ws = self;
self.pushChannel = [FlutterMethodChannel methodChannelWithName:@"qd.flutter.io/qd_push_main" binaryMessenger:ws];
[self.pushChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
NSLog(@"%@", call.method);
NSLog(@"%@", result);
[ws handleFlutterMethod:call result:result];
}];
}
- (void)handleFlutterMethod:(FlutterMethodCall *)call result:(FlutterResult )result {
if ([call.method isEqualToString:@"pushNativePage"]) {
NativeSecondVC *secondVC = [[NativeSecondVC alloc] init];
[self.navigationController pushViewController:secondVC animated:YES];
}
}
- (void)gotoBack {
if (self.navigationController != nil) {
[self.pushChannel invokeMethod:@"goback" arguments:@{@"number": @"1"} result:^(id _Nullable result) {
NSLog(@"%@", result);
if ([result isEqualToString:@"gobackError"]) {
[self.navigationController popViewControllerAnimated:YES];
}
}];
}else {
[self dismissViewControllerAnimated:YES completion:nil];
}
}
@end
里面注册了FlutterMethodChannel,通过Channel来调用Flutter中的方法。并接收返回结果。
注意:原生调flutter方法时,flutter返回给原生结果的方式,和flutter调原生,原生返回给flutter结果的方式不一样。
在NativeFlutterVC.m中,我们重写了返回按钮,我们需要点击原生返回键的时候通知Flutter回退页面,如果Flutter已经不能回退页面,说明Flutter已到根页面,就需要返回信息给原生,让原生pop来回退页面。
如果不重写FlutterViewController的返回按钮,就会导致我在FlutterViewController(flutter页面)页面中push了好几层之后,点击原生返回按钮,会把所有flutter页面关闭掉。
原生通过Channel调用了goback方法,看看flutter里面怎么监听
// 我在class外面生成了Channel
const pushMainPlatform = const MethodChannel('qd.flutter.io/qd_push_main');
class PushFirstPageState extends State<PushFirstPage> {
// static const pushMainPlatform = const MethodChannel('qd.flutter.io/qd_push_main');
// Native调用原生监听
Future<dynamic> handelPushCall(MethodCall methodCall) {
print(methodCall.toString());
String backResult = "gobackSuccess";
if (methodCall.method == "goback"){
if (Navigator.of(this.context).canPop()) {
Navigator.of(this.context).pop();
}else {
backResult = "gobackError";
}
}
return Future.value(backResult);
}
void pushNativePage() {
pushMainPlatform.invokeMethod('pushNativePage', {'key1':'value1'});
}
@override
Widget build(BuildContext context) {
pushMainPlatform.setMethodCallHandler(handelPushCall);
return Scaffold(
// push 过来的页面,原生没隐藏导航栏,所以把flutter页面的导航栏隐藏
// appBar: new AppBar(
// title: Text('First'),
// ),
body: Center (
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text('First Page Content'),
new RaisedButton(
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PushSecondPage(),
),
);
},
child: Text('Go to Flutter Second Page'),
),
new RaisedButton(
onPressed: (){
SystemNavigator.pop();
},
child: Text('Close Flutter Page'),
),
new RaisedButton(
onPressed: (){
pushNativePage();
},
child: Text('Go to Native Page'),
),
],
),
)
);
}
}
只看需要的就行了。在 build
中我们设置了监听方法 handelPushCall
。
判断 methodCall.method == 'goback'
来调用 Navigator.of(this.context).pop();
重点:通过调用 Future.value(backResult)
来返回原生结果。
原生再根据返回的结果做具体处理。
3. 原生跳转Flutter页面
根据Flutter文档。
4. Flutter页面跳转原生
Flutter页面跳转原生,原理还是Flutter和Native交互达到的。
比如我在Flutter页面中添加一个按钮和方法,通过Channel调用传递到原生。
new RaisedButton(
onPressed: (){
pushNativePage();
},
child: Text('Go to Native Page'),
),
void pushNativePage() {
pushMainPlatform.invokeMethod('pushNativePage', {'key1':'value1'});
}
原生添加监听方法
__weak typeof(self) ws = self;
self.pushChannel = [FlutterMethodChannel methodChannelWithName:@"qd.flutter.io/qd_push_main" binaryMessenger:ws];
[self.pushChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
NSLog(@"%@", call.method);
NSLog(@"%@", result);
[ws handleFlutterMethod:call result:result];
}];
添加判断执行方法:
- (void)handleFlutterMethod:(FlutterMethodCall *)call result:(FlutterResult )result {
if ([call.method isEqualToString:@"pushNativePage"]) {
NativeSecondVC *secondVC = [[NativeSecondVC alloc] init];
[self.navigationController pushViewController:secondVC animated:YES];
}
}
iOS工程和Flutter页面:取用