Faraday: github.com/gfaraday/g_…
话不多说,开始之前先看一组图
flutter -> native | native->flutter | flutter in tab |
---|---|---|
一个全新的flutter
混合开发框架, 用于解决在混合开发会遇到的各种
问题。为什么不使用社区现有的(flutter_boost、d_stack、flutter_thrio )几个解决方案,而是选择自己再造轮子呢?在回答这个问题之前,我们先来看看一个合格的混合栈框架应该具备哪些基础能力
需求
互跳
一直说混合、混合,那混合的是什么呢?这里的混合是指路由栈的混合,即flutter
页面可以自由跳转到native
页面,native
页面可以跳转到flutter
页面。路由切换的过程中需要处理不同页面堆栈切换时的黑屏、白屏、闪屏问题,还需要支持自定义路由切换动画,支持不同类型页面间回调传参
入口
即将flutter页面作为整个app的入口页面。作为入口页面需要解决的问题主要是从启动图到flutter页面的切换动画问题。另外还需要处理从其他业务线中直接跳回主页的场景
tab
tab架构在app中非常常见,ios中有UITabViewController
安卓中使用Fragment
也可以轻易的实现tab布局。这里需要注意的是在需要支持多个flutter tab
多个native tab
混合的情况。同时还需要考虑从tab跳转到其他native或者flutter页面的情况
弹出层
app的模态页面必不可少,这种弹出页面逻辑一般都比较独立,很适合用flutter实现,所以也需要必要的支持。弹出层的核心在于混合栈需要支持flutter的容器背景透明,以及支持自定义弹出动画,或者禁用/启用原生动画
定位到任意页面
现在的app都越来越复杂,业务流程越来越长很容出现跨很多层级的页面跳转。因此支持跳转到任意定位的页面也显得极其重要
iOS navigation bar
这是一个ios特有的场景。flutter的容器viewController肯定是需要隐藏掉navigation bar的,但是容器的前一个页面或者后一个页面都有可能需要隐藏或者显示navigation bar所以混合堆栈最好也能把这个问题处理了
Android 物理返回键
对于Android物理返回键的处理在混合栈中比较特殊,flutter提供了原生的WillPopScope
来处理这个问题。混合栈最好能完美兼容此widget,避免再去创造更多的概念来解决此问题
动画
混合栈中涉及到原生容器与flutter页面之间的跳转,如果不能很方便的自定义页面跳转动画看起来会有很大的割裂感。所以支持自定义转场动画,看起来也是刚需
了
与其他社区框架配合
flutter社区有很多优秀的框架比如路由管理框架fluro
,状态管理provider
、mobx
等等,还有比如最近超火的getx
。为了能使用这些优秀的社区框架,混合栈管理框架的api一定要设计的足够巧妙,同时在iOS和原生端的也有大量的第三方库可供我们选择。因此需要对原生的入侵尽可能的小
其他 (非必需)
- 通知
打通flutter与native之间的通知壁垒
- 网络
将flutter的网络请求代理到native实现
- 原生通信
封装MethodChannel方便与原生通信
到这里上面那个问题的答案就显而易见了,现有的几个框架都不能完美的解决以上问题。因此我们设计开发了g_faraday
来满足以上需求。接下来我们看看faraday
的基础架构。
架构
要设计一个混合栈框架,第一个问题就是
单引擎 OR 多引擎
这个问题目前来看似乎已经没有讨论的价值了。相比于单引擎,多引擎方案的优点并不明显,而且内容占用略大。因此我们很容易确定了采用单引擎
模式
下一个问题,混合框架必然会涉及到三端(ios,android,flutter),他们之间有很多相似但是不相同概念,包括但不限于页面,页面生命周期等等,我们以那一端的概念为主呢?
页面概念
集成混合框架以后,我们大部分的开发工作应该都聚焦在flutter层,因此肯定需要以flutter widget的概念为主,避免将UIViewController
、Activity
及其生命周期相关的一些概念引入flutter
接下来我们看以下打开页面的操作
NativePage(N00) --> FlutterPage(F00) --> FlutterPage(F01) --> NativePage(N10) --> FlutterPage(F10) --> FlutterPage(F11) --> FlutterPage(F12)
此时我们直接套入flutter_boost的设计理念来看一下,如果我们严格看照boost的设计逻辑使用,那么native侧会分别为F00
、F01
、F10
、F11
生成4个对应的容器, 这个时候我们可以看到对内存会有比较大的压力,而且如果这几个F
页面如果有弹出的模态页面那么会和原生交互产生混乱。 因此我们从这个地方切入,我们不再为每一个F
页面生成一个对应的容器。对于一组连续的F
页面(比如 F00-F01
, F10-F11-F12
)只生成一个容器。这样对于上述场景我们只需要生成2个容器即可。
与容器交互
native容器有自己的返回逻辑(ios滑动返回,android物理返回键), 而由于我们每一个容器都有可能容纳N个flutter页面,因此我们必须根据相应的状态对容器的返回事件做出响应。为了能精确的管理每个页面,因此我们每个容器都为他赋予一个navigator,我们通过navigator的observer就可以精确的控制容器返回事件,具体逻辑如下:
- iOS FaradayViewController
如果容器内有多于一个
flutter
页面,或者widget
树中存在一个或者多个WillPopScope
那么禁用容器本身的滑动返回手势,反之启用
- Android FaradayActivity OR FaradayFragment
如果容器内有多于一个
flutter
页面,或者widget
树中存在一个或者多个WillPopScope
那么优先pop flutter page
或者执行WillPopScope call
, 反之直接pop
容器
设计原则
从上面的基础架构可以看出我们的整体逻辑非常简单,因此我们最终实现出来的框架对三端的入侵都非常非常的小,尤其是flutter层,你甚至可以忘了faraday,一切就像开发纯flutter应用那样,使用第三方框架,处理路由,等等。。。
- 对原有平台最小侵入
- 对现有代码最小改动
- API尽量保持和原有平台一致
总结
这里对faraday进行了一个粗略的介绍,具体内容大家可以移步github, 欢迎大家试用,反馈。欢迎各类 issue
, pr
。
关于我们
我们是寓小二(长租公寓系统·创导者)技术团队,我们正在寻找志同道合的伙伴加入我们。