大家好,我是考100分的小小码 ,祝大家学习进步,加薪顺利呀。今天说一说FlutterBoost管理混合栈iOS实践「建议收藏」,希望您对编程的造诣更进一步.
官方混合方案多引擎的弊端
- 官方方案在Native和Flutter页面交叉跳转时于Flutter Engine数量会线性增加导致内存暴增(这里指图片缓存等比较消耗内存的对象)。
- 多个FlutterViewController,插件的注册和通信将会变得混乱难以维护,消息的传递的源头和目标也变得不可控。
- Flutter页面和Native页面差异化,一些统一操作增加复杂度。
- Flutter应用中全局变量在各独立页面不能共享的问题。
- iOS平台内存泄露的问题。
官方目前就共享同一个引擎做混合开发没有很好的支持。
混合栈管理问题
混合开发(RN,Flutter,Native)导致的混合栈的管理一直是个比较烦的问题,iOS端的表现主要包括对导航栈的一些特殊处理(增删改之类),之前做RN和Native混合开发就遇见过类似的问题。本身Native有自己的一套导航栈,RN自己也有一套Navigation
的管理(我们这里使用社区维护的React Navigation
),每次Native打开RN是打开一个新的VC,但RN页面通过React Navigation
打开一个或多个RN页面时实际上是在同一个VC中,这就导致RN和Native交叉跳转多次后混合栈变得混乱,Native并不知道栈里面实际有多少个页面,想要直接返回到这些交叉页面的某一个页面(可能是Native或者RN)也变得困难,所以我们在处理RN和Native混合栈跳转实践过程添加了很多特殊处理,包括什么时候使用新开VC的push
,什么时候使用不新开VC的push
,以及手势返回什么时候使用Native响应,什么时候使用RN响应,跨多个页面pop
如何计算要pop
几个等一系列问题,让开发和维护都变得复杂。
当然Flutter和Native混合开发也要面对类似的问题,再加上之前的RN,导航栈的管理就更加棘手了。
FlutterBoost
官方介绍:
The philosophy of FlutterBoost is to use Flutter as easy as using a WebView
趟过坑的大厂(阿里巴巴-闲鱼技术)很明显已经走在了前面,开源了名为FlutterBoost的插件。它采用共享引擎的模式实现,解决的多引擎的很多弊端。统一管理Flutter页面映射和跳转,让push
和pop
的导航栈操作和Native保持一致,在我们在开发过程中就无须关心Native和Flutter导航栈交叉跳转所带来的各种问题。
目前FlutterBoost支持稳定版本的flutter v1.9.1-hotfixes
,最新的1.12
正在适配中。
集成
- 在Flutter模块的
pubspec.yaml
添加依赖:
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '0.1.63'
- Flutter模块下执行
flutter pub get
更新依赖资源。 - 在Native工程下执行
pod install
将Flutter相关产物依赖带到Native。
这里需要注意每次更改pubspec.yaml文件重新做flutter pub get
后,都要做pod install
重新依赖产物。不然产物有变更而Native没有同步更新导致报错运行不起来。
在Flutter模块中使用
- 在
runApp()
函数传入的RootWidget
中注册所有的Flutter页面。
@override
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'account/about': (pageName, params, _) => AboutWidget(),
'account/feedback': (pageName, params, _) => FeedbackWidget(),
});
}
- 在
RootWidget
的build
方法中初始化FlutterBoost
。
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: FlutterBoost.init(),
}
- 在Flutter模块中打开和关闭页面
FlutterBoost.singleton.open('account/feedback');
FlutterBoost.singleton.open('native', urlParams: {'id': '123456'});
FlutterBoost.singleton.open('native', urlParams: {'id': '123456'}, exts: {});
FlutterBoost.singleton.close('account/feedback', result: {}, exts: {});
FlutterBoost.singleton.closeCurrent(result: {}, exts: {});
根据页面需求调用方法即可,还有一些更细节的用法如Native和Flutter间回传值等,有需要的可以去FlutterBoost的example里面了解。
在Native中使用
使用之前我们先了解两个类和一个协议:
FlutterBoostPlugin
(共享引擎的管理,打开和关闭页面)FLBFlutterViewContainer
(在官方的FlutterViewController
上做了一层封装)FLBPlatform
(实现此协议后统一处理FlutterBoostPlugin
开关页面的回调)
具体使用:
- 工程启动时候做
FlutterBoostPlugin
的初始化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
PlatformRouterImp *router = [PlatformRouterImp new];
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router onStart:^(FlutterEngine *engine) { }];
}
其中PlatformRouterImp
主要是实现FLBPlatform
协议,让使用FlutterBoostPlugin
打开和关闭页面时能够统一处理。
@protocol FLBPlatform;
@interface PlatformRouterImp : NSObject<FLBPlatform>
@property (nonatomic,strong) UINavigationController *navigationController;
@end
@implementation PlatformRouterImp
- (void)open:(NSString *)name urlParams:(NSDictionary *)params exts:(NSDictionary *)exts completion:(void (^)(BOOL))completion {
BOOL animated = [exts[@"animated"] boolValue];
MyFlutterViewController *vc = [[MyFlutterViewController alloc] init];
[vc setName:name params:params];
[self.navigationController pushViewController:vc animated:animated];
- (void)present:(NSString *)name urlParams:(NSDictionary *)params exts:(NSDictionary *)exts completion:(void (^)(BOOL))completion {
BOOL animated = [exts[@"animated"] boolValue];
MyFlutterViewController *vc = [[MyFlutterViewController alloc] init];
[vc setName:name params:params];
[self.navigationController presentViewController:vc animated:animated completion:^{ if (completion) completion(YES); }];
}
- (void)close:(NSString *)uid result:(NSDictionary *)result exts:(NSDictionary *)exts completion:(void (^)(BOOL))completion {
BOOL animated = [exts[@"animated"] boolValue];
MyFlutterViewController *vc = (id)self.navigationController.presentedViewController;
if ([vc isKindOfClass:MyFlutterViewController.class] && [vc.uniqueIDString isEqual: uid]) {
[vc dismissViewControllerAnimated:animated completion:^{}];
} else {
[self.navigationController popViewControllerAnimated:animated];
}
}
@end
之后每次使用FlutterBoostPlugin
打开和关闭页面都会回调给实现了FLBPlatform
协议的PlatformRouterImp
。
[FlutterBoostPlugin open:@"account/Feedback" urlParams:nil exts:nil onPageFinished:^(NSDictionary *params) {
} completion:^(BOOL isComplete) {
}];
MyFlutterViewController
继承自FLBFlutterViewContainer
,目前主要用来处理Native页面和Flutter页面交叉跳转时Native导航条是否展示的问题,混合开发虽然Flutter页面外层也是一个VC,但我们并不希望导航条UI样式也使用Native的,Flutter页面应该有自己的导航条样式和逻辑,这样也更利于日后的维护和拓展。
混合踩坑
- Native页面手势返回到Flutter页面会跳一下(只有真机会出现模拟器没问题)。
这个问题本来最初一直以为是FlutterBoost
的问题,定位了好久才发现锅在Native。我们Native工程每次跳到下一个页面会把上一个页面的截图保存在内存中,然后在每次手势返回时展示此截图。问题就出在截图的代码。
使用renderInContext
方法截图
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
UIGraphicsBeginImageContextWithOptions(window.bounds.size, window.opaque, 0);
[appdelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
使用drawViewHierarchyInRect
方法截图
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
UIGraphicsBeginImageContextWithOptions(window.bounds.size, window.opaque, 0);
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:NO];
UIImage *snapshotImage=UIGraphicsGetImageFromCurrentImageContext();
renderInContext
是对view
的layer
渲染到当前的上下文中。drawViewHierarchyInRect
是对view
进行一个快照,然后将快照渲染到当前的上下文中。
在Flutter页面使用renderInContext
这种方式截图会导致截图不完整,只截取了一部分(每次手势返回会先展示不完整的截图再展示页面,所以会有跳动的感觉),具体原因猜测跟Flutter的渲染方式有关系,若有明白的大神还望指点~
- Flutter页面的
ListView
滚动很卡顿
这个问题最初出现在模拟器,发现也有很多人遇见类似卡顿的问题,说Debug
模式的Flutter性能不高,有卡顿也正常,当时还在想布局这么简单的List
也能卡成这样,叹气~,然后果断真机跑一下,What?还有同样的问题,定位良久发现是手势处理的锅。
这个问题是由于为了响应Native的手势返回在处理手势时将RRDFlutterViewController
的手势给拦截了,导致ListView
的滑动刚被触发就取消了,这就造成了类似很卡的效果。
解决方式将触摸事件传递给FlutterView。
gestureRecognizer.cancelsTouchesInView = NO;
总结
FlutterBoost初步使用感觉还是不错的,帮助我们解决了很多官方的坑,阿里巴巴-闲鱼技术也确实投入了不少人力在支持,目前来看是跟着Flutter的稳定版本不断做更新的。
后续有坑和总结还会在本文中作补充。
友情提示:如果你也在用FlutterBoost,遇见问题多去看看官方Demo和issue,相信大部分都会有觉解方案。
相关链接
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13526.html