flutter_boost 实现原理,源码解读
[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想要的界面
以上内容,如有不全面,或是错误的地方欢迎指正