[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)容杭煎,如有不全面,或是錯誤的地方歡迎指正