Flutter笔记 02:iOS调用多个flutter界面

需求

flutter需要调用多个Flutter界面,且需要传输数据到flutter

问题

由于最开始的与iOS的混编,是只调用一个界面,而现在需要调用多个。所以这里我们是通过FlutterEngine初始化FlutterViewController,并通过设置setInitialRoute设置初始化路由,以下是交互的代码

<!--OC代码-->
//通过engine创建flutter界面
FlutterEngine flutterEngine = [[FlutterEngine alloc] initWithName:@"flutter engine"];
[flutterEngine run];
FlutterViewController *flutterVC = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];

//设置路由
[flutterVC setInitialRoute:@"message"];

//消息传递通道,native传递到flutter
FlutterMethodChannel *flutterChannel = [FlutterMethodChannel methodChannelWithName:@"nativeToFluuter" binaryMessenger:flutterVC.binaryMessenger];
[flutterChannel invokeMethod:@"message" arguments:@{@"message":@"hello world"}];

[self.navigationController pushViewController:flutterVC animated:YES];

<!--Flutter代码-->
void main() => runApp(_widgetForRoute(ui.window.defaultRouteName));

Widget _widgetForRoute(String route){
  switch (route){
    case 'message':
      return MyApp();
    case 'other':
      return OtherPage();
    default:
      return DefaultPage();
  }
}

但是通过实测发现,setInitialRoute设置的路由并不生效,在flutter端通过 window.defaultRouteName拿到的route永远是/根符号。这个是Flutter SDK的一个bug

解决办法有以下几种

方式1 -

如果必须使用setInitialRoute来区分不同的flutter界面,那么就不能通过FlutterEngine初始化FlutterViewController,需要直接使用 alloc+init 或者 new 的方式初始化FlutterViewController

注:这种方式有一个问题,每次渲染会有启动页一闪而过的效果,且这种方式初始化的FlutterViewController在关闭时是无法释放内存

改进后的代码如下所示

<!--OC代码-->
//通过alloc+init创建flutter界面
FlutterViewController *flutterVC = [[FlutterViewController alloc] init];

//设置路由
[flutterVC setInitialRoute:@"message"];

//消息传递通道,native传递到flutter
FlutterMethodChannel *flutterChannel = [FlutterMethodChannel methodChannelWithName:@"nativeToFluuter" binaryMessenger:flutterVC.binaryMessenger];
[flutterChannel invokeMethod:@"message" arguments:@{@"message":@"hello world"}];

[self.navigationController pushViewController:flutterVC animated:YES];

<!--Flutter代码-->
void main() => runApp(_widgetForRoute(ui.window.defaultRouteName));

Widget _widgetForRoute(String route){
  switch (route){
    case 'message':
      return MyApp();
    case 'other':
      return OtherPage();
    default:
      return DefaultPage();
  }
}

方式2

通过FlutterMethodChannel传入的method进行区分,以下是代码逻辑

<!--OC代码-->
//通过alloc+init创建flutter界面
FlutterViewController *flutterVC = [[FlutterViewController alloc] init];

//消息传递通道,native传递到flutter
FlutterMethodChannel *flutterChannel = [FlutterMethodChannel methodChannelWithName:@"nativeToFluuter" binaryMessenger:flutterVC.binaryMessenger];
[flutterChannel invokeMethod:@"message" arguments:@{@"message":@"hello world"}];

[self.navigationController pushViewController:flutterVC animated:YES];

<!--Flutter代码-->
void main() => runApp(MyApp());

class MyApp extends StatefulWidget {

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  //用于区分不同界面
  String pageRoute;
  dynamic arguments;

  @override
  void initState() {
    super.initState();

ConstantsUtil.nativeToFlutterChannel.setMethodCallHandler((call) {
      setState(() {
        pageRoute = call.method;
        arguments = call.arguments;
      });
      return null;
    });

  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: rootPage(pageRoute),
    );
  }
  
  rootPage(String route){
    switch (route){
      case 'message':
        return MessagePage(title: 'Message', arguments: arguments,);
      case 'other':
        return OtherPage(title: 'Other', arguments: arguments,);
      default:
        return DefaultPage();
    }
  }
}

推荐阅读更多精彩内容