美文网首页
flutter_boost 实现原理,源码解读

flutter_boost 实现原理,源码解读

作者: 564a | 来源:发表于2020-08-11 10:43 被阅读0次

    [TOC]

    序言

    在学习flutter之后,大多数的情况都是混合编程,在原生中使用flutter以页面或模块为单位介入(最小介入单元界面iOS中称为viewcontroller)。

    在以界面为单位介入flutter是遇到一个问题,就是无法替换flutter module中的root界面,哪怕设置了initialRoute属性也没有用(
    不管是在原生中设置:

        flutterViewController.setInitialRoute("/test_page/aa"),
    

    还是在flutter中设置

        initialRoute: "/test_page",
    

    )都不生效。

    让人很头疼,单也不是没办法解决,使用
    flutterViewController.pushRoute("/test_page/sss")
    直接显示自己的界面,跟页面就不管他就行了,如果要用到flutter的导航控制器的话需要手动管理一下,不然会退到跟页面显示很不友好

    flutter boost 使用

    之后看到flutter boost 很好的解决了跟页面的问题,就下载下来使用

    // flutter_boost 依赖配置
    flutter_boost:
      git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'v1.17.1-hotfixes'
    

    配置好后开始使用,如下:

    @override
    Widget build(BuildContext context) {
      return StoreProvider<AppState>(
        store: store,
        child: MaterialApp(
          theme: ThemeData(highlightColor: Color.fromRGBO(0, 0, 0, 0), splashColor: Color.fromRGBO(0, 0, 0, 0)),
          title: 'CHERY',
          builder: FlutterBoost.init(postPush: _onRoutePushed),
          home: Home(),
        ),
      );
    }
    
    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        ScreenUtil.init(context, width: 750, height: 1334);
        return Container(
          color: Color.fromARGB(255, 255, 0, 253),
          child: Center(
            child: Text("root page"),
          ),
        );
      }
    }
    

    Home效果图,后面有用
    Screen Shot 2020-08-11 at 9.42.13 AM.png

    想测试一下flutter boost 实现是不是也是用的push的方法,并没有真正的改变跟页面,做如下测试:
    在页面展示后加定时器pop出这个页面,代码如下:

    Timer timer = new Timer(new Duration(seconds: 5), () {
      print("time up pop -------");
      Navigator.pop(context);
    });
    

    运行后页面并没有推出到跟页面。

    flutter源码阅读

    很好奇他是怎么做到改变跟页面的,于是去读flutter boost 的源码

    结合原生代码,viewcontroller的生命周期发现如下代码

    flutter boost 内 iOS原生的生命周期消息发送

    - (void)viewWillDisappear:(BOOL)animated
    {
        [BoostMessageChannel willDisappearPageContainer:^(NSNumber *result) {}
                                                     pageName:_name
                                                       params:_params
                                                     uniqueId:self.uniqueIDString];
        [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
        [super viewWillDisappear:animated];
    }
    
    //BoostMessageChannel 文件代码
     + (void)willShowPageContainer:(void (^)(NSNumber *))result pageName:(NSString *)pageName params:(NSDictionary *)params uniqueId:(NSString *)uniqueId
     {
         if ([pageName isEqualToString:kIgnoreMessageWithName]) {
             return;
         }
         
         NSMutableDictionary *tmp = [NSMutableDictionary dictionary];
         if(pageName) tmp[@"pageName"] = pageName;
         if(params) tmp[@"params"] = params;
         if(uniqueId) tmp[@"uniqueId"] = uniqueId;
         [self.methodChannel invokeMethod:@"willShowPageContainer" arguments:tmp result:^(id tTesult) {
             if (result) {
                 result(tTesult);
             }
         }];
     }
    

    是以channel通信的方式将原生的生命周期嫁接到flutter端来处理

    flutter boost flutter 内接受iOS原生生命周期的方法

    //ios view controller 生命周期
      Future<dynamic> _onMethodCall(MethodCall call) {
        Logger.log('onMetohdCall ${call.method}');
    
        final String pageName = call.arguments['pageName'] as String;
        final Map<String, dynamic> params =
            (call.arguments['params'] as Map<dynamic, dynamic>)
                ?.cast<String, dynamic>();
        final String uniqueId = call.arguments['uniqueId'] as String;
    
        switch (call.method) {
          case 'didInitPageContainer':
            _nativeContainerDidInit(pageName, params, uniqueId);
            break;
          case 'willShowPageContainer':
            _nativeContainerWillShow(pageName, params, uniqueId);
            break;
          case 'didShowPageContainer':
            nativeContainerDidShow(pageName, params, uniqueId);
            break;
          case 'willDisappearPageContainer':
            _nativeContainerWillDisappear(pageName, params, uniqueId);
            break;
          case 'didDisappearPageContainer':
            _nativeContainerDidDisappear(pageName, params, uniqueId);
            break;
          case 'willDeallocPageContainer':
            _nativeContainerWillDealloc(pageName, params, uniqueId);
            break;
          case 'onNativePageResult':
            break;
        }
    
        return Future<dynamic>(() {});
      }
    

    flutter 内 iOS 生命周期中的viewwillappear的方法实现

    bool _nativeContainerWillShow(
        String name,
        Map<String, dynamic> params,
        String pageId,
    ) {
        print("_nativeContainerWillShow--------");
        if (FlutterBoost.containerManager?.containsContainer(pageId) != true) {
          print("_nativeContainerWillShow--------");
          FlutterBoost.containerManager?.pushContainer(
            _createContainerSettings(name, params, pageId),
          );
        }
    
        // TODO(unknown): 需要验证android代码是否也可以移到这里
        if (Platform.isIOS) {
          try {
            final SemanticsOwner owner =
                WidgetsBinding.instance.pipelineOwner?.semanticsOwner;
            final SemanticsNode root = owner?.rootSemanticsNode;
            root?.detach();
            root?.attach(owner);
          } catch (e) {
            assert(false, e.toString());
          }
        }
        return true;
    }
    

    看到了push的字眼,我又回到了,我以前的想法(跟页面还在,push了新的页面?),抱着这个想法想继续看代码

    发现重写了导航控制器,如下:

    //重写的navigatir 文件名boost_container.dart
    class ContainerNavigatorObserver extends NavigatorObserver {
      
      @override
      void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
        print("didPush--------");
        for (final NavigatorObserver observer in boostObservers) {
          observer.didPush(route, previousRoute);
        }
      }
    
      @override
      void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
        print("didPop--------");
        for (final NavigatorObserver observer in boostObservers) {
          observer.didPop(route, previousRoute);
        }
      }
    
      @override
      void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
        print("didRemove--------");
        for (final NavigatorObserver observer in boostObservers) {
          observer.didRemove(route, previousRoute);
        }
      }
    
      @override
      void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
        print("didReplace--------");
        for (final NavigatorObserver observer in boostObservers) {
          observer.didReplace(newRoute: newRoute, oldRoute: oldRoute);
        }
      }
    }
    

    为了验证到底是不是push的方法改变页面的,我添加了一些日志(后面带“--------”)运行后发现

    确实走了push方法

    又添加了一些代码来验证,把上面的系统的导航控制器换成boost的导航控制器方法,试了一下

    Timer timer = new Timer(new Duration(seconds: 5), () {
      print("time up pop -------");
      FlutterBoost.containerManager?.pop();
    });
    

    出现了我在上面的设置的跟页面的效果,

    运行日志如下:

    //log
    2020-08-11 09:11:14.681256+0800 Exeed[1657:2435378] flutter: FlutterBoost#onMetohdCall didShowPageContainer
    2020-08-11 09:11:14.684337+0800 Exeed[1657:2435378] flutter: pushContainer--------
    2020-08-11 09:11:14.685383+0800 Exeed[1657:2435378] flutter: FlutterBoost#_refreshOverlayEntries in setState
    2020-08-11 09:11:14.686330+0800 Exeed[1657:2435378] flutter: FlutterBoost#ContainerObserver#2 didPush
    2020-08-11 09:11:14.686927+0800 Exeed[1657:2435378] flutter: FlutterBoost#BoostContainerLifeCycleObservercontainer:flutter://lion.com?pageName=homeContainerlifeCycle:ContainerLifeCycle.Appear
    2020-08-11 09:11:14.688237+0800 Exeed[1657:2435378] flutter: FlutterBoost#native containner did show-flutter://lion.com?pageName=homeContainer,
      {uniqueId=0,name=flutter://lion.com?pageName=homeContainer}
    2020-08-11 09:11:14.758341+0800 Exeed[1657:2435378] flutter: didPush--------
    ...
    2020-08-11 09:17:23.008669+0800 Exeed[1665:2437360] flutter: time up pop -------
    2020-08-11 09:17:23.010918+0800 Exeed[1665:2437360] flutter: FlutterBoost#_refreshOverlayEntries in setState
    2020-08-11 09:17:23.012686+0800 Exeed[1665:2437360] flutter: FlutterBoost#ContainerObserver#2 didPop
    2020-08-11 09:17:23.074269+0800 Exeed[1665:2437360] flutter: FlutterBoost#onShownContainerChanged old:0 now:default
    

    总结

    到此可以判定flutter boost 也是使用的push的方法,而且是重写的后的导航控制器的方法,flutter原来的方法无效

    根据flutter 不难发现他是在iOS的生命周期viewwillappear中发送信息给 flutter 来push想要的界面

    以上内容,如有不全面,或是错误的地方欢迎指正

    相关文章

      网友评论

          本文标题:flutter_boost 实现原理,源码解读

          本文链接:https://www.haomeiwen.com/subject/qlpedktx.html