flutter_boost 實現(xiàn)原理洞渤,源碼解讀

[TOC]

序言

在學習flutter之后,大多數(shù)的情況都是混合編程彭羹,在原生中使用flutter以頁面或模塊為單位介入(最小介入單元界面iOS中稱為viewcontroller)笑撞。

在以界面為單位介入flutter是遇到一個問題岛啸,就是無法替換flutter module中的root界面,哪怕設(shè)置了initialRoute屬性也沒有用(
不管是在原生中設(shè)置:

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

還是在flutter中設(shè)置

    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 實現(xiàn)是不是也是用的push的方法,并沒有真正的改變跟頁面胜宇,做如下測試:
在頁面展示后加定時器pop出這個頁面耀怜,代碼如下:

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

運行后頁面并沒有推出到跟頁面恢着。

flutter源碼閱讀

很好奇他是怎么做到改變跟頁面的,于是去讀flutter boost 的源碼

結(jié)合原生代碼财破,viewcontroller的生命周期發(fā)現(xiàn)如下代碼

flutter boost 內(nèi) iOS原生的生命周期消息發(fā)送

- (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 內(nèi)接受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 內(nèi) iOS 生命周期中的viewwillappear的方法實現(xiàn)

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了新的頁面靡羡?),抱著這個想法想繼續(xù)看代碼

發(fā)現(xiàn)重寫了導航控制器俊性,如下:

//重寫的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的方法改變頁面的略步,我添加了一些日志(后面帶“--------”)運行后發(fā)現(xiàn)

確實走了push方法

又添加了一些代碼來驗證,把上面的系統(tǒng)的導航控制器換成boost的導航控制器方法定页,試了一下

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

出現(xiàn)了我在上面的設(shè)置的跟頁面的效果趟薄,

運行日志如下:

//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

總結(jié)

到此可以判定flutter boost 也是使用的push的方法,而且是重寫的后的導航控制器的方法典徊,flutter原來的方法無效

根據(jù)flutter 不難發(fā)現(xiàn)他是在iOS的生命周期viewwillappear中發(fā)送信息給 flutter 來push想要的界面

以上內(nèi)容杭煎,如有不全面,或是錯誤的地方歡迎指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卒落,一起剝皮案震驚了整個濱河市羡铲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌导绷,老刑警劉巖犀勒,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異妥曲,居然都是意外死亡贾费,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門檐盟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褂萧,“玉大人,你說我怎么就攤上這事葵萎〉加蹋” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵羡忘,是天一觀的道長谎痢。 經(jīng)常有香客問我,道長卷雕,這世上最難降的妖魔是什么节猿? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上滨嘱,老公的妹妹穿的比我還像新娘峰鄙。我一直安慰自己,他們只是感情好太雨,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布吟榴。 她就那樣靜靜地躺著,像睡著了一般囊扳。 火紅的嫁衣襯著肌膚如雪吩翻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天宪拥,我揣著相機與錄音仿野,去河邊找鬼。 笑死她君,一個胖子當著我的面吹牛脚作,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缔刹,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼球涛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了校镐?” 一聲冷哼從身側(cè)響起亿扁,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸟廓,沒想到半個月后从祝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡引谜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年牍陌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片员咽。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毒涧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贝室,到底是詐尸還是另有隱情契讲,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布滑频,位于F島的核電站捡偏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏峡迷。R本人自食惡果不足惜霹琼,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枣申,春花似錦、人聲如沸看杭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽楼雹。三九已至模孩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贮缅,已是汗流浹背榨咐。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谴供,地道東北人块茁。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像桂肌,于是被迫代替她去往敵國和親数焊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354