概要
在前一篇文章中我们提到,iOS跳转到Flutter工程指定页面时(多个),Flutter只有单例,设置setInitialRouter 无效,如下
let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)! flutterViewController.setInitialRoute("test1")
基于不是很甘心,一直想实现完美的解决方案,所以最近几天又看了下解决各方面的解决方案,最终还是有了可行方案,步骤如下
1、设置delegate 代码
这里代码 多了 ‘FlutterBasicMessageChannel’ 设置,其中_kReloadChannelName要和 flutter上的代码保持一致
let _kReloadChannelName = "reload" @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate ,FlutterAppLifeCycleProvider{ static var shared: AppDelegate? var window: UIWindow? var _lifeCycleDelegate = FlutterPluginAppLifeCycleDelegate() var flutterEngine : FlutterEngine! var flutterViewController : RKFlutterViewController! var reloadMessageChannel : FlutterBasicMessageChannel! func addApplicationLifeCycleDelegate(_ delegate: FlutterPlugin) { _lifeCycleDelegate.add(delegate) } func flutterSetup(){ flutterEngine = FlutterEngine(name: "rokid.flutter", project: nil) flutterEngine.run(withEntrypoint: nil) //全局引擎(解决启动加载时候m,无法处理和native交互问题) flutterViewController = RKFlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)! GeneratedPluginRegistrant.register(with: flutterEngine) //实现App 路由跳转 reloadMessageChannel = FlutterBasicMessageChannel(name: _kReloadChannelName, binaryMessenger: flutterEngine, codec: FlutterStringCodec.sharedInstance()) } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { ... flutterSetup() ... }
2、iOS App 跳转指定路由
@objc func handleButtonAction() { self.engine().navigationChannel.invokeMethod("setInitialRoute", arguments: "test") self.reloadMessageChannel().sendMessage("test") let flutterViewController = FlutterViewController(engine: self.engine(), nibName: nil, bundle: nil)! self.navigationController?.pushViewController(flutterViewController, animated: true) } func engine() -> FlutterEngine { return (UIApplication.shared.delegate! as! AppDelegate).flutterEngine } func reloadMessageChannel() -> FlutterBasicMessageChannel { return (UIApplication.shared.delegate! as! AppDelegate).reloadMessageChannel }
3、flutter路由代码如下
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:ui' as ui; import 'src/pages/playground/PlaygroundPage.dart'; /// Channel used to let the Flutter app know to reset the app to a specific /// route. See the [run] method. /// /// Note that we shouldn't use the `setInitialRoute` method on the system /// navigation channel, as that never gets propagated back to Flutter after the /// initial call. const String _kReloadChannelName = 'reload'; const BasicMessageChannel<String> _kReloadChannel = BasicMessageChannel<String>(_kReloadChannelName, StringCodec()); void main(){ // Start listening immediately for messages from the iOS side. ObjC calls // will be made to let us know when we should be changing the app state. _kReloadChannel.setMessageHandler(run); // Start off with whatever the initial route is supposed to be. run(ui.window.defaultRouteName); } Future<String> run(String name) async{ // The platform-specific component will call [setInitialRoute] on the Flutter // view (or view controller for iOS) to set [ui.window.defaultRouteName]. // We then dispatch based on the route names to show different Flutter // widgets. // Since we don't really care about Flutter-side navigation in this app, we're // not using a regular routes map. switch (name) { case "test": runApp(appRouter(title: "我是路由测试test00",)); break; case "test1": runApp(appRouter(title: "我是路由测试test01",)); break; case "test2": runApp(appRouter(title: "我是路由测试test02",)); break; default: runApp(MyApp()); break; } return ''; } class appRouter extends StatelessWidget { appRouter({this.title}); final String title; // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter rokid', debugShowCheckedModeBanner: false,// 显示和隐藏 theme: ThemeData( primarySwatch: Colors.blue, ), home: PlaygroundPage(title: '$title'), ); } } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter rokid', debugShowCheckedModeBanner: false,// 显示和隐藏 theme: ThemeData( // This is the theme of your application. // // Try running your application with "flutter run". You'll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // "hot reload" (press "r" in the console where you ran "flutter run", // or press Run > Flutter Hot Reload in a Flutter IDE). Notice that the // counter didn't reset back to zero; the application is not restarted. primarySwatch: Colors.blue, ), home: PlaygroundPage(title: '若琪实验室'), routes: <String ,WidgetBuilder>{ "router1": (_) => new PlaygroundPage(title: "我是内部路由测试test00",), "router2": (_) => new PlaygroundPage(title: "我是内部路由测试test01",) }, ); } }
思考和总结
上面代码可以实现:native -> 任意 flutter ,但是flutter Engine是单例子,能否实现 native->flutter ->native->flutter呢?
功能和交互如何去选择呢???
参考资料
https://github.com/flutter/flutter/issues/27882