zoukankan      html  css  js  c++  java
  • iOS 工程实现native 跳转指定的Flutter 页面

    概要

    前一篇文章中我们提到,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

    https://github.com/flutter/flutter/blob/master/dev/integration_tests/ios_add2app/ios_add2app/MainViewController.m

    https://github.com/flutter/flutter/blob/master/dev/integration_tests/ios_add2app/flutterapp/lib/main.dart

  • 相关阅读:
    python note 19 异常处理
    python note 18 序列化模块
    python note 17 random、time、sys、os模块
    python note 16 re模块的使用
    python note 15 正则表达式
    python note 13 内置函数
    python note 12 生成器、推导式
    C++ int型负数除法取余问题
    Leetcode162. 寻找峰值
    Leetcode450. 删除二叉搜索树中的节点
  • 原文地址:https://www.cnblogs.com/kingbo/p/11269026.html
Copyright © 2011-2022 走看看