首页 体育 教育 财经 社会 娱乐 军事 国内 科技 互联网 房产 国际 女人 汽车 游戏

跨平台技术趋势及字节跳动 Flutter 架构实践

2020-05-21

咱们下午好!今日跟咱们同享的主题是《跨渠道技能趋势及字节跳动 Flutter 架构实践》。

我是本年参加字节跳动,现在在移动渠道部担任 Flutter 架构优化作业,在此之前我在小米做了 3 年安卓手机体系的底层优化与研制作业。平常作业之余喜爱写写博客,从 16 年开端,坚持写了 4 年,发生 200 余篇原创技能华章,与此期间也受邀到会业界的一些安卓相关的技能大会。

在正式同享之前问咱们一个问题: 面临层出不穷的新技能,你是挑选持续深耕原有技能,仍是会测验新技能 ? 咱们不要考虑,你直观形象会挑选什么?

但其实面临这个问题的时分,许多人想的是:我是不是要测验新技能了?就像上面这个比方,许多人会想到,我假如不断换新技能,是不是毕竟一无所得?我假如坚持一个方向,毕竟我能取得我想要的东西、能够有所作用,我就不要去测验新技能了。但其实这儿面有个误区:

榜首,假如你在一个范畴做得满足长期,3 年、5 年、10 年,那么你有或许会有所收成,这时分你就会进入技能疲乏期,有或许就不乐意再去应战新的东西了,有或许觉得生长空间受到限制,这个时分假如你乐意跳出技能舒适区,去看一看周边新的技能,会拓展你的常识面。以我个人为例,我在此前做过安卓手机驱动层的开发,我又做过上面安卓 Framework 层,来到字节跳动又开端做 Flutter,在我不断挑选新方向时,这何曾不是一种深耕呢?把你的技能栈打通。

第二,假如你挑选学习更多新技能时,能够看到下面有许多钻石,你要挑选找到一颗最大的钻石,怎样找?要看趋势,一个好的趋势不必定帮你找到最大钻石,可是必定能够帮你更高概率找到更大的钻石。

第三,怎样找到一个新的主意,是不是每次作业时都像左面那个人从头开端?其实这也是一个误区。有经历的人都知道,你在一个范畴深耕时,再学习一个新的范畴绝非从零开端,到必定程度你会横向开展、横向打通,而不是回到零点,你的学习本钱时刻不会那么长,由于技能是相通的。

所以咱们在寻求技能进程中,怎样找到更大的钻石?便是看技能趋势。怎样收成更多钻石?不要拘泥于一个方向,当然,也不主张咱们频频的切换,但能够在多个范畴收成。怎样更高效的找到钻石?咱们的技能是相通的,当你在学习新技能时,要你把原有的技能联通、打通,融通你的的任督六脉。

为了处理这几个问题,咱们以移动跨渠道为例。首要,咱们先看看移动端技能开展趋势;再则看看 Flutter 引擎究竟有哪些中心技能,怎样跟原有技能相通的;毕竟介绍一下字节跳动在 Flutter 新技能范畴有哪些技能开展与落地实践,看看在新范畴是怎样做到快速深耕。

以上,是跨渠道技能计划好坏最为重视的几个要素。

咱们在 2011 年时,以 WebView 技能做跨端,这个跨端有比较大的局限性,功用很差、功用受限,不能做杂乱场景。到了 2015 年 Facebook 出了 React Native,它是以 JS 言语,经过中心层转化,毕竟烘托调到 Native 层,功用相对更好一些。接下来阿里推出了 Weex,也是经过 JS 言语调到原生烘托。2018 年 Google 出了 Flutter,它有自自己的引擎、自烘托机制,它的功用比较好。这便是大约的演进。

跨端技能分为几类:

不论跨端技能怎样演化,首要便是分这三大类。

咱们来看高一起性,上面是 Flutter 写的一个 Demo,在安卓和 iOS 简直相同。UI 小姐姐规划 UI 时往往期望多端体会一起,它能够做到高度一起。

咱们再讲讲它的高功用,为什么常说它是高功用?以安卓为例,安卓原生结构 APP 调到咱们了解的安卓 Framework,Flutter 再调到 Skia,Skia 再毕竟烘托调到 GPU。

右边一般惯例结构原生烘托怎样做的?它有一个转化层,经过转化,毕竟安卓调安卓烘托,iOS 调 iOS 烘托机制,中心多了一个层。

关于 Flutter 中心调的是一个 Dart Framework,再调到 Skia,用 Flutter 渠道和原生很挨近,Flutter 是上限很高的技能,假如你优化满足好,它能够比美原生。当然,现在 Flutter 作为一个重生婴儿或许有些方面有所缺乏,可是不断开展,它毕竟能够做得更好。

业界公司能够直接做 Flutter,BAT、字节跳动等或多或少在它们事务上有落地,这是一个趋势。

除此之外,Google 还有一个内部做的体系叫 Fusicha,它最上层也是用的 Flutter 和 Dart,这个体系未来怎样?在 5G 和 IoT 商场不断开展,很有或许这个体系也做得不错,假如它有不错的作用,你提早入局 Flutter,或许多了一次弯道超车的时机。

咱们来看看 Flutter 技能栈。上面是用 Dart 写的 APP,下面有 DartFramework,Framework 里有安卓和 iOS 的主体,里边有许多动画等等。再往下会调到引擎,引擎里有音讯、PlatformChannel、Dart VM 等,引擎层再到渠道,咱们看的是渠道、安卓仍是 Web,这是咱们惯例的一个架构。

可是咱们看待一个体系必定要从动态视角去看待,什么叫动态视角?这个 Flutter 是怎样创立的?它的生命周期看它毕竟是怎样起来的?

上图仍然是以安卓为例,安卓有 Application 和 Activity,用 Dart 写的 APP 毕竟也要这样去跟原生连接起来,Flutter 有 Flutter 的 Application 和 Flutter 的 Activity。在 Flutter Application 中就会把 Dart 写的代码生成一个产品,把它加载起来,咱们的 Flutter Activity 进程中会拉起咱们的引擎。

到了引擎层这块,Flutter 里四个中心线程:渠道线程、UI 线程、GPU 线程、IO 线程,它们各有分工:这个渠道线程关于安卓和 iOS 来说便是常说的主线程,这儿的 UI 线程面临安卓自身的主线程,便是一个独立的线程;GPU 线程指的是跑在 CPU 上的线程,它做的首要是 Skia 相关作业。IO 线程比方图片解码、编解码,首要做 IO 相关的作业。这儿已然有几个线程,必定触及线程之间的通讯,就回到技能的相通,假如你了解安卓、iOS 就知道线程怎样通讯,一瞬间看看它们两个的差异。

右边有一个 Dart 虚拟机,这儿有一个 Isolate 的概念,这是 Flutter 里才有的概念,从姓名也能够看出来,“孤立的”,孤立的是什么意思?两个内存之间不会孤立、不会不同享。再看右上角,就到了 Dart 层,会有 UI 制作。

接下来顺次讲一下这四块。

榜首个图,先看看 Flutter 用 Dart 写的代码毕竟编译的东西长什么样,最开端 Dart 代码最立刻用前端编译器编译,左面绿色的是安卓,右边蓝色的是 iOS,依据不同的渠道会发生不同的产品。左面组成了一个 APK,右边在咱们的 iOS 上是 Runner APP。最下面引擎代码经过编译发生在安卓和 iOS 有所不同,两部分凑集起来成为相应不同渠道的 APK。发现用 Dart 写的代码在不同渠道会编译成习惯不同渠道的运用,这是毕竟编译出来的产品。Flutter 能够把这个产品加载起来运转。

第二个图,悲天悯人线程通讯,仍然以安卓为例,咱们十分了解安卓,咱们是怎样通讯的呢?这儿面有许多音讯,简略来说是把一个音讯放到音讯行列里去了,这是一个安卓的技能。咱们来看一下右边 Flutter,会发现十分奇特,技能便是这样的相通。Flutter 仍然有一个 Looper 线程,关于主线程复用了本来的 Native 的,关于别的三个线程创立一个独立的 Looper,不同的是它有两个音讯行列,仍然是跑音讯的办法,经过 Task Runner 就比方安卓的 Handle,经过 PostTask 就比方把一个音讯放在一个音讯行列里去。相同在 Dart 里常常用 Furture 和异步的办法,中心仍是用咱们的 Task Runner 发一个音讯。

咱们要看到技能的相通,也要看到技能的不同,这儿面不同的是什么?不同的是在于咱们这儿有一个 MessageQueue,这儿有两个行列,它怎样处理呢?先处理微型使命,微型使命处理完了再处理一般使命,所以在 Flutter 里叫 Task,在安卓里叫 Message,技能奇特的相似。咱们不必忧虑,学习新技能本钱十分高,把技能把握透了,学习新技能会发现本钱很低,很好去了解。

再看看 Isolate,同一个进程里能够有许多 Isolate,两个 Isolate 的堆是不能同享的,但它们也要交互。怎样交互?在 Dart 虚拟机里边也有一个特别 Isolate,是运转在 UI 线程中,和 Root Isolate 是运转在一个线程的。当两个 Isolate 要通讯,会找一个一起的可拜访的内存,安卓听到十分多的概念是“进程间通讯”,它毕竟怎样通讯?用户态进程不能同享,可是内核态能够同享,这就找到一个能够同享的当地,把通讯数据在内核态放进对方的行列里,别的一边就能够拿到了。

相同,Isolate 也是相似的逻辑,Isolate1 和 Isolate2 怎样通讯?在 Isolate2 里创一个 ReceivePort,在 Isolate1 中调用其对应的 SendPort 的 send 办法,在引擎 PortMap 里边有映射表,每一个 port 端口对应一个相应 Isolate 的 MessageHandler,该 Handler 里边有两个行列,一个是一般的音讯行列,一个是 OOB 高优先级音讯,依据优先级把它放到相应音讯行列。再把这个作业封装成一个 MessageTask,抛到别的一个 Isolate 里去,咱们一般创立一个 Isolate,它里边是一个 worker 线程,worker 线程放入一个新的 Task,它就会毕竟去履行这个 Task,毕竟会解分出这个音讯,你会发现技能再一次相通了。

咱们再往上走,到了 UI 层是 Widget,在整个 Flutter 里有许多 Widget。Widget 能够是一行文本、一张图片、一个色彩,一切都是 Widget。最大有两类,一个是无状况的 Widget,一个是有状况的。无状况望文生义是一类 StatelessWidget,一旦创立状况是不行改动的;第二类 StatefulWidget 是状况能够改动的。这触及状况是跟安卓不同的当地,已然有了状况,运用越写越杂乱时就触及状况办理,怎样去办理状况。

对应 Widget 创立 Widget 树,它是 Element 的装备,假如两个 Widget 之间做了改变它会做差分,比较一下究竟哪部分做了改变,只把改变更新到 Element 里去,以最小粒度做更新。到了 Element 里构建烘托进程中会创立 Render 目标,创立烘托的进程。

烘托来了一个信号,UI 线程更新动画,动画完了做一个树立,树立进程中生成 Render,再往下布局、制作巨细等作业。这个完结今后会生成一个 Layer Tree,也跨两个线程,UI 和 GPU 线程。到了 GPU 线程之后会调用 Skia 做烘托。

为什么用渠道的 Channel?咱们常说,Flutter 是一个美丽的 UI 东西,有时真的需求 Native 才能怎样办?比方调用相机的特性需求写 Native 代码,所以 Flutter 供给一套 Channel 机制,橙色部分代码,写相应渠道安卓或许 iOS 定制代码,中心有一套机制帮你完成封装好,你写 Dart 代码直接能够调到安卓或许 iOS 代码,这个进程是异步的。

咱们大约看了 Flutter 引擎中心的技能,不光是 UI 层的,以及引擎层的机制。我进程中屡次说到一点,技能是相通的,你在一个范畴深耕,新的范畴仍然能够做到持续深耕。

字节跳动有超越 20 个运用在用 Flutter,头条、西瓜视频等都在用 Flutter,内部许多运用都现已选用 Flutter 落地了,这不是纸上工程,在许多事务上都现已落地了。

咱们移动渠道部在 Flutter 上做了哪些作业?

上层为了支撑咱们这些运用,首要在运用结构层在工程化做了许多尽力,用容器化思维,怎样让事务接起来更快;有混合工程的常识,让事务快速接入 Flutter;咱们的状况办理,在状况混了的情况下怎样高效的接入;也为了咱们事务更好的接入,咱们有许多技能组件的开发,供给了许多丰厚的库。

除此之外,为了监控 Flutter,有许多功用高可用渠道,有稳定性测验等等。

引擎层也做了许多优化,尽管声称 Flutter 高功用,可是事务运用中仍是要做到优化。首要,咱们许多工程师刚开端写 Dart 不知道怎样写出更高功率的 Flutter 代码,所以事务能够优化,其次,引擎能够做许多优化,以及多端一体化的测验,以及编译、黑科技的,咱们在每个范畴都花了许多投入。

简略看看咱们的容器化,为事务支撑,有许多 APP,供给容器化扩展接口。比方要调图片,图片调到咱们的协议层,会调一个图片的协议,里边有一个默许的适配,还有一个用户能够自定义的,能够不做任何定制,咱们会帮你供给常用技能组成。下面跟安卓、iOS 的交互都能够疏忽,写代码很便利,许多库都有,这便是容器化的思维,帮你封闭了底层差异性,让你接入起来愈加方便。

再说说监控体系,看过咱们 Flutter 发现引擎自身有咱们的监控,上面是 GPU 线程,下面是 UI 线程,这是一个比较粗糙的功用计算办法。为什么粗糙?有几点做不到位的当地:榜首,把功用分红 UI 和 GPU 线程,明显咱们看参数时期望看一个参数,第二,它的算法很粗糙,它计算每一帧耗时,做物理均匀,毕竟再将均匀耗时依据 16.6ms 对应 60fps,来归一化处理。

业界不少公司做了改善,都怎样改善的?一般的办法在结构层去计算出 UI 线程的耗时时刻,看它跨了多长期,看它有多少帧是丢帧的,这个计划有什么缺点?咱们能够看这个图,了解这个烘托的进程,来了一个信号,你把这个音讯 post 到 UI,里边再做 Handle,再把这个作业 Post 到咱们的 GPU 线程。这个计划的缺点是:榜首,线程 Post 到 UI 线程中心有一个音讯传递进程,有或许在 Post 进程中要等候的这段时刻没有考虑进去。第二,假如你只计算 UI 线程有什么缺点?咱们举个比方,UI 线程十分快,可是 GPU 线程十分慢,UI 线程每次或许一两毫秒就完结了,可是 GPU 线程每非必须一两百毫秒,尽管看到功用十分好,可是实在体会发现卡爆了,简直刷不动,为什么?由于 UI 线程向 GPU 线程跑音讯时最多 Post 两个音讯,这时分 GPU 线程仍然处理不过来,UI 线程就不会 Post 音讯,可是 UI 线程表现不出来,所以这也是业界计划的缺点。

咱们做了高精度无侵入功用监控计划:

在多端一体化也做过测验,内部写一个运用能够一起运转在 iOS、安卓端、Web,把一些内部组件串起来,做一个多端一体化的测验。多端一体化的中心就在于惯例有一个 Flutter 引擎,右边多一个 Flutter Web,调用 Dart2JS,这样就把咱们 Web 容纳进来了。

Flutter Turbo,做了功用进步的计划,怎样在有限资源情况下把咱们的功用发挥到极致?这个中心思维便是我要找到中心场景做有用的资源调度,比方用户在界面滑动这个场景十分重要,你能否把一些资源有用操控?比方音讯调度能否优先调度呼应我的初次,这时分我在用户十分重要的场景能否把 GC 按捺了,封闭能够封闭的特效,有一系列手法,为了进步咱们的功用,内部有一个 Benchmark 跑分,这些计划都能够带来进步。

现有图片怎样传?惯例 Dart 里要上网络中去下载一张图片会调 Image.network,然后把这张图片加载之后,要把数据传到 Dart 层,能够传一个途径等等之类的,Dart 层会再调用引擎层解码。外界纹路也很不错,但它有一些问题,没有在这个基础上改造,而是做了自己的一套透存的计划。

图中右边是咱们在 Dart 层调引擎的暗示,引擎加载图片时咱们调到里边加载,它生成一个 Bitmap,尽管引擎是 Dart 虚拟机,但两者之间咱们做了一个 Bitmap 的同享,你不需求把数据传过来,咱们是同享的办法,咱们再转成 Pixel buffer,对功用相同会大大进步。

发动速度优化咱们做得比较早,刚开端它发动速度也很慢,咱们在引擎层里也做了许多修正,发现它的发动速度简直进步了 1 倍。

包体积是咱们十分重视的一个点,为什么重视包体积?会决议用户乐意不乐意去下载这个运用,所以咱们在包体积方面做了许多作业,做了很大尽力。

一系列计划下来,咱们的包体积会挨近 50% 的优化。

以上是咱们字节跳动在 Flutter 里做了许多实践中的部分重点作业。

榜首,同享了 Flutter 的技能趋势,Flutter 是咱们争相寻找的技能。

第二,跟咱们介绍了 Flutter 引擎,发现里边的技能是相通的,音讯通讯跟安卓的 Handle 机制简直相同;可是它也有它的差异,技能也有不同之处。

第三,字节跳动布了一个新的范畴,发现咱们做了许多技能深耕。回到最开端问的问题,面临一个新技能,你是乐意持续挑选深耕老的技能,仍是乐意测验新的技能?发现在做新技能时并没有咱们幻想的那么难,并且在进程中你会收成许多。

第四,已然选趋势,你怎样知道你挑选的便是那颗最大的钻石?毕竟有一句话送给咱们:

谢谢咱们!

发问:我是一位安卓开发者,自己常常了解 Flutter,很有疑问是关于代码搬迁,许多运用开发许多年了,代码量是很大的,迁到 Flutter 上,您这边在项目上有什么经历呢?或许有什么主张呢?便是在代码量很大的这种场景下。

答复:这是一个很好的问题。Flutter 有两块,榜首,新事务是一个比较好的挑选,直接从零开端。第二,已有事务怎样改造?主张刚开端先测验挑选页面相对简略的页面,只能逐渐切,先找相对轻量的页面测验把路跑通,各方面数据目标都能合格,再测验更多,按部就班把更多切进去。不要想到工程这么大一次悉数规划好全切过去,这个危险十分高,不光是技能问题,还触及到商业问题。

发问:Native 和引擎之间 Bitmap 怎样做同享的?

答复:很简略,它们都在一个进程里,为什么不能通讯呢?不是物理阻隔,而是逻辑阻隔,什么叫逻辑阻隔?写代码咱们在引擎层,引擎许多东西都能够直接去把地址传过来,假如你在运用层或许做不到,可是 Flutter 能够了解为一个小型体系,比方就像你能够改安卓的 Framework 和底层的东西,那么什么东西改不了呢?

发问:咱们现在一个项目两个渠道,您是怎样处理作为项目傍边的一个 Model,可是 Flutter 引用在原生傍边,怎样处理两个渠道的嵌入问题、接入问题?

答复:你问的其实是混合工程的问题。关于老事务改造必定离不开混合工程。混合工程问题,咱们也有东西叫 FlutterW,把混合工程一键化快速接入,比方我方才提的容器化都是让混合工程快速接入的进程。

发问:我有一个比较有意思的问题,我看到 PPT 里有说你们用了 Web 的东西。我比较猎奇的是,这个东西处于一个 Build 的阶段,之前说这个东西比较倾向做手机端的运用,由于它是比较倾向于做跟移动端相同的体会,所以我想知道你们关于用 FlutterWseb 是什么规划?比方是做成 H5 降级计划吗?

答复:这个问题问得很好,首要 Flutter for Web 是一个预览状况,字节跳动即便是预览版,也会跟进。方才展现的是技能跟进,除此之外内地也有一些内部项目落地 Flutter for Web,这是一个技能测验。也能够用 Flutter for Web 作为 Fallback 计划,也是一种不错的备选计划。跟着 Flutter 的开展,信任下一年 for Web 会更好。现在首要是安卓、iOS,Web 这个版也要补齐,现在它的确不方便老练,从内部数据来看现在 Flutter for Web 的功用补 H5 还会差,尽管有一些优化,但还比 H5 差。假如真实用到线上大型运用的话,主张你们调查一段时刻,假如你们团队人力比较多的话,也能够现在接入去做相应改造。

袁辉辉,字节跳动移动渠道部 Flutter 架构师。

https://mp.weixin.qq.com/s/IZ6rUfg3_-zvopc7jZZobg

热门文章

随机推荐

推荐文章