一. flutter与iOS的消息传递
Flutter
和原生交互主要通过channel
进行通信,主要包括三类(以flutter开头的类均是原生端类)
Flutter | iOS |
---|---|
BasicMessageChannel |
FlutterBasicMessageChannel |
MethodChannel |
FlutterMethodChannel |
EventChannel |
FlutterEventChannel |
下面以MethodChannel
和FlutterMethodChannel
为例进行说明
1. flutter端
//1.初始化channel
final platform = const MethodChannel('samples.flutter.io/test');
//2.设置回调方法
void initState() {
super.initState();
platform.setMethodCallHandler(invokeFlutterMethod);
}
Future< Null > invokeFlutterMethod(MethodCall call) async{
setState(() {
content = call.arguments['text'];
});
}
//3.在合适的地方(按钮点击事件),调用iOS方法
Future _invokeIOSMethod() async {
try {
await platform.invokeMethod('invokeIOSMethod',{'text':'flutter传过来的参数'});
} on PlatformException catch (e) { }
}
2.iOS端
//1.初始化FlutterViewController页面(官方推荐方式)
FlutterEngine *flutterEngine =
((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
FlutterViewController *flutterVC =
[[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
flutterVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:flutterVC animated:YES completion:nil];
//2.初始化channel
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"samples.flutter.io/test"
binaryMessenger:flutterVC.binaryMessenger];
//3.调用Flutter方法
[channel invokeMethod:@"invokeFlutterMethod" arguments:@{@"text":@"ios传给flutter的参数"}];
//4.设置回调(等待Flutter调用)
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([call.method isEqualToString:@"invokeIOSMethod"]) {
[flutterVC dismissViewControllerAnimated:YES completion:nil];
}
}];
二.在iOS端切换flutter页面
❌闪退?返回控制器不销毁?内存泄漏?
✅解决方案:
官方人员(Dan Field)给出了答案
通过验证官方的例子,现总结如下:
1. 使用setInitialRoute
设置flutter
页面
自己的理解:重新初始化FlutterViewController
内部会重新创建FlutterEngine
,导致flutter的代码重新加载main
函数,然后通过window.defaultRouteName
获取新的路由值(这里路由值为full
),根据路由值加载对应页面
//FullScreenViewController继承自FlutterViewController
FullScreenViewController *flutterViewController =
[[FullScreenViewController alloc] init];
[flutterViewController setInitialRoute:@"full"];
//在交互的过程中,官方代码动画过度都设置的NO,说是有问题,猜测是过渡不自然,
[self.navigationController
pushViewController:flutterViewController
animated:NO];
2.使用全局的FlutterEngine
设置flutter
页面
实现过程:使用一个全局的channel
来管理页面切换,iOS
通过发送channel
回调来改变flutter
页面,如:[[self reloadMessageChannel] sendMessage:@"full"];
,具体看官方代码
自己的理解:下面第一行代码这种设置路由纯属多余,虽然路由值设置成功了(这里只能说是路由值,具体的路由页面可不一定切换成功了),因为用的是全局FlutterEngine
获取的FlutterViewController
,此时是不加载flutter
的main
函数的。这种情况要想切换页面必须通过channel
进行回调flutter
端切换路由页面的方法。所以我觉得下面的第一行代码纯属多余,即使注释掉也不影响。暂且把它当作通过FlutterEngine
设置路由值的一种方法吧。
[[self engine].navigationChannel invokeMethod:@"setInitialRoute"
arguments:@"full"];
[[self reloadMessageChannel] sendMessage:@"full"];
FullScreenViewController *flutterViewController =
[[FullScreenViewController alloc] initWithEngine:[self engine]
nibName:nil
bundle:nil];
[self.navigationController
pushViewController:flutterViewController
animated:NO]; // Animating this is problematic.
⚠️直接使用 FlutterViewController
,在连续返回然后进入的操作下可能会闪退,建议在 FlutterViewController
消失的情况下执行以下代码
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController) {
// Note that if we were doing things that might cause the VC
// to disappear (like using the image_picker plugin)
// we shouldn't do this. But in this case we know we're
// just going back to the navigation controller.
// If we needed Flutter to tell us when we could actually go away,
// we'd need to communicate over a method channel with it.
[self.engine setViewController:nil];
}
}
-
附加知识点
- 常量构造函数的作用?
理解:const
修饰的构造函数,要求成员变量必须都是final
的,并且在构造函数中要初始化
在类内部修饰const
如果修饰成员变量,必须和static
配合使用
class Hello {
const Hello(this.name,this.age);
final String name;
final int age;
}