本篇是此系列的第二篇,重点介绍如何让Flutter能够开发,实现业务需求。这部分包括:混合栈的管理,混合下的能力补齐和包管理。
混合栈的管理
引入Flutter之后,我们首要面临的问题便是混合栈的管理。如我们首先实践的是商品详情页,则有一个常见的应用场景:首页->详情页->详情页(猜你喜欢点击)->会话页->详情页(会话顶部点击)。如何去解决这种Native 与Flutter任意嵌套的问题呢?
解决方案应具有以下特点:
a.每一个页面都有一个VC(Activity),保证所有基于VC(Activity)生命周期的逻辑(如埋点等)照常工作
b.不同的Flutter页面之间可以正常通信,共享数据
c.Native可以调起任意的Flutter页面,无论是首次打开还是之后
d.资源占用尽可能少,性能尽可能好
e.用户体验要同之前无差异
为了解决这些问题,设计如下:
a.所有的Flutter页面公用一个Flutter实例(FlutterViewController for iOS&FlutterNativeView for Android)
其中iOS可以透过addChildViewController和removeFromParentViewController,直接在FlutterViewController层面复用。
Android由于activity不能add/remove,因此抽取并复用了FlutterNativeView(相对应的FlutterView也是单例),在不同的Activity上复用。
这种Flutter单例的实现带来的好处显而易见。一方面,单个Flutter实例因为位于相同的Isolate,其数据通信和共享将很容易。另一方面,引擎的默认实现中,每一个Flutter实例会新启动三个线程(IO,GPU和UI),带来了额外的资源使用,单实例可以避免这个问题。
当然单例的实现也带来了额外的管理复杂度,但这个相关的复杂度我已经通过插件的方式支持了。
访问下方链接查看混合栈管理插件:
https://pub.dartlang.org/packages/hybrid_stack_manager
b.每一个Flutter页面不仅是一个FlutterPage,也有一个对应的NativeVC(或Activity)与之相对应
通过唯一的id将其关联,可以方便地使Flutter/Native页面保持同步。如Native页面退到Idx时,可以通过Flutter内部的栈回退到对应idx的Flutter页面。
c.Native和Flutter都基于openUrl来管理页面跳转
统一的路由机制可以统一管理所有页面跳转相关逻辑,对业务侧提供标准一致的服务。
d.所有的页面跳转和动画都通过Native实现
因为原生(iOS/Android)自带跳转动画,而Flutter内部跳转也自带动画,为了用户体验,禁止Flutter内部跳转(push/pop)相关动画,统一由Native接管,这样用户就感受不到差异。
e.使用一个空白Widget作为RootWidget
以便保证Flutter页面完整退出时(如回到首页),可以释放所有的Flutter详情页等资源
架构图如下:
效果图如下
待优化部分
1.目前为了保证页面跳转时的正常显示,前一个页面是截图,后一个页面是真正的Flutter页面,也就是说每一个FlutterWrapperVC(Activity)都保留了一张截图,带来了额外的内存消耗。
复用Native组件
当前闲鱼Flutter业务全页面采用Flutter实现,但也有一些Native组件的复用。
通过Channel调用部分中间件
如埋点,网络请求与解析等只能调用已有的二方中间件,这种情况下基于Platform Channels去调用。
使用Dart重写部分中间件
对于一些有标准协议支持(如http)的中间件,如阿里云提供的基于http的文件上传服务,可以通过dart重写的方式去实现。
通过新Window方式,盖上已有的Native组件
如下图所示的浮层和键盘上的输入框,均为直接复用Native组件。
视频的实现
Flutter引擎通过Texture的方式,由Native侧提供相应的渲染内容(解码视频文件获得帧Buffer等)的方式来提供对于视频的支持。
Flutter的渲染流程略图
iOS上Flutter视频渲染逻辑:
Android上Flutter视频渲染逻辑:
包管理
构建和发布插件(包)
1.使用下面命令创建插件:
flutter create --template=plugin hybrid_stack_manager
2.开发插件并在example中测试通过 3.完善README.md, CHANGELOG.md,pubspec.yaml,podspec.json,LICENSE等相关文件 4.使用命令验证并发布
cd root-path-to-your-flutter-package
pub publish
如果出现一个连接需要验证身份,拷贝到浏览器访问即可。
我们可以将实现的插件(如网络请求,混合栈管理等)包,Dart包(阿里云上传组件等),以多种形式引入。下面以上文中的混合栈管理插件hybridstackmanager为例说明下各种包管理方式:
包名+版本
实现后可发布到https://pub.dartlang.org,再在pubspec.yaml中基于名称+版本号引入。
此部分包下载后路径位于:~/.pub-cache/hosted/pub.dartlang.org/hybridstackmanager-0.0.2
包名+git信息
也可以将代码包上传到可访问到的git地址,通过git地址+ref的方式引入。
此部分包下载后路径位于:~/.pub-cache/git/hybridstackmanager-d9f6bdf169683fd8642168ec37c5820940ed344a
包名+路径
也可以将代码放在某一文件夹(建议当前Flutter工程根目录之下),通过路径引入。