概要
在前一篇文章中我們提到,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