移动端跨平台技术演变漫谈

作为原生前端的两大巨头,andorid和ios已经共存了十年,在可见的未来,还会一直存在下去.这给了所谓”跨平台”技术巨大的成长空间,毕竟成本分分钟降低一半,哪家公司不喜欢呢对不对?

作者2010年入行移动端开发,经历了历代跨平台技术的演进,总结下来,近十年的技术演变可分为三代.下面依次说说.

第一代:web方式

其实这个严格上来说算不得什么跨平台,仅仅是依赖android和ios的framework中都具备的webview相关组件来实现的.

Webview也好,UIWebview也好,既然你都支持html+css+js那一套.那我就用这一套写呗,写完顺便还能发布h5版本.

然而web页面毕竟运行在web容器上,移动设备的很多特性都没有办法使用,例如摄像头,震动,打电话等等,又或者某些性能要求高的功能必须用原生方式做,因此当时的很多app都是原生和h5混着用,最不济也是要套个原生壳子,俗称混合开发.

h5页面和原生页面的通信,h5页面和设备原生功能的交互,成了混合开发最核心的问题.

在此基础上,衍生了很多成熟的跨平台框架,比如PhoneGap,现在应该叫做Cordova了.

PhoneGap 被 Adobe 收购了,但是剥离了核心代码贡献给 Apache Software Foundation,Apache 将这个项目命名为Cordova ,也就是说 PhoneGap 是基于 Cordova 的.

PhoneGap是什么?是一个采用HTML,CSS和JavaScript的技术,创建移动跨平台移动应用程序的快速开发平台.简而言之就是一个能加载h5页面的壳子,但这个壳子与原生平台的webview组件不同的是,它帮你做了很多的原生功能交互,包括但不限于以下:

  • 加速计
  • 摄像头
  • 罗盘
  • 通讯录
  • 文档
  • 地理定位
  • 媒体
  • 网络
  • 通知(警告、声音和振动)
  • 存储

如果有更多的需求,还可以自己开发插件.

然而这种方式终究还是走的web渲染方式,由于其运行机制和代码冗余的原因,在加载体验和交互体验上比不过原生,因此当时也仅作为一些活动页面的展现方式,来弥补原生页面修改不够灵活的缺点.

第二代:RN/Weex方式.

既然web渲染机制存在性能上的问题,那能不能继续使用原生渲染方式呢?

基于第一代跨平台技术存在的缺点,Fackbook想到了一种名为ReactNative的解决方案:我用js写页面,但是在不同平台上转换成对应的原生控件.

不得不说这种想法真的很棒,既照顾了开发效率,又满足了性能要求,仅仅需要为两个端各开发一套转化框架就行了,这个工作是一次性的!

自2015年发布以来,Facebook不遗余力的投入对ReactNative的建设.逐渐有了越来越多的公司开始采用这一方案.随后2016年阿里也发布了Weex框架,开始有了一批阿里系的使用者.

看似很完美的方案,但截至2020年,已经有越来越多的公司放弃RN,回归原生技术栈.原因是RN的一些缺点:

  • 无法完全跨平台,简而言之,只要遇到同一类型控件在两个平台有差异的就要区别对待.
  • 性能问题一直存在.比如臭名昭著的android平台列表item内存释放.
  • 扩展性依然不够,相对于原生控件的各种api,支持得不够彻底.
  • 用作页面级开发时,回退栈和tab处理依然不够完美.比如android中的启动模式.

第三代:Flutter方式

一套代码,运行时转化成多个端的原生控件,机制上行得通,但是里面的坑已经被大家摸得差不多了.在这个过程中,有人放弃,有人坚持,不可否认的是:这依然是一个不完美的方案.

2018年12月,Google正式发布Flutter.这个就nb了,直接操作底层的2D绘图引擎进行绘制.

什么控件转换,不存在的,我直接画出来!

Android系统上默认的2d绘图使用的是skia引擎.Flutter使用dart语言来写界面,最后直接操作skia引擎进行绘制,完全绕过原生自带的那一套ViewGroup机制,运行起来就是一个大大的View.

ios怎么办呢?简单粗暴,直接打包一个skia引擎上去…(所以目前ios上的安装包大小和性能都被人吐槽.)

直接操作渲染引擎,从根本入手,在我看来这是当之无愧的第三代跨平台技术了.时至今日,Flutter版本在不断的优化和bug修复中已经更新到了1.22,也有了一些大厂的背书,最典型是闲鱼团队(据说某个开发人员在Flutter上提交的PR比Flutter自身的开发人员还多.).近几年的各种开发者大会,移动端会场也是动辄Flutter.

除了Flutter for ios,还有Flutter for web,主要基于HTML+CSS+Canvas的方式,实现传统web页的展示.

一切看起来都在向好的方向发展,在这个看起来大一统的技术下,整个大前端终于要统一了么?

泼冷水

1.Flutter并不是什么高科技.类似的理念在游戏开发中已经有了.

游戏开发用什么技术?3d用Cocos2d-x,3d用Unity3D.为什么一套技术能在android和ios上都跑起来呢?无非就是底层用的都是OpenGL ES.

OpenGL ES(OpenGL for Embedded Systems)是三维图形应用程序接口OpenGL的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。

Android 支持多版 OpenGL ES API:

  • OpenGL ES 1.0 和 1.1 - 此 API 规范受 Android 1.0 及更高版本的支持.
  • OpenGL ES 2.0 - 此 API 规范受 Android 2.2(API 级别 8)及更高版本的支持.
  • OpenGL ES 3.0 - 此 API 规范受 Android 4.3(API 级别 18)及更高版本的支持.
  • OpenGL ES 3.1 - 此 API 规范受 Android 5.0(API 级别 21)及更高版本的支持.

ios中的OpenGL ES框架则提供了OpenGL ES规范的1.1、2.0和3.0版本的实现.

是不是很熟悉?同样是利用手机内置的渲染引擎,google非常机智的使用dart framework做了一层封装,对接android上自带的skia.

也许dart framework提供了更丰富的api,对上层开发者来说更加友好,也许dart语法比c++写起来更舒服.甚至skia在绘制2d图像上性能比opengl更好.但无论如何,这种思想是一样的:放弃各自平台的framework api,直接绘制.

2.Dart语法需要重新学习,且缩进层级太深,可读性不佳.

Dart作为一种新兴语言,综合了java,js,python等各种语言的优点.是好是坏暂不评价,但是毫无疑问:是有一些上手门槛的.

在Flutter中,UI界面不再使用xml或者xib方式,而是使用Dart语言来书写.然而页面是有层级的,Dart中如何展示层级?

使用缩进.

用缩进来控制代码格式,并不新鲜,例如python.但是一旦页面层级太多…

先感受一下吧,这是一个非常简单的页面,仅显示了一个多选框和一个文本:

虽然可以通过各种控件封装来降低单个代码中的嵌套层数.但界面和业务逻辑混杂在一起仍然无法避免.

StateFulWidget很有效的实现MVVM思想,解决了性能问题,但无法解决语法层面上的代码耦合.

3.在android以外的平台上,没有太多优势.

除了android自带skia,可以无缝接入Flutter,在web上需要调用canvas进行绘制,存在兼容性问题,在ios上则要将整个skia打包,将面对Apple应用商店对于安装包大小的限制.

目前据我所知,在ios平台上试水flutter的工程大大低于android平台,web上则几乎没有.
如果只在一个平台上使用flutter,那所谓的跨平台还有何意义?

结尾

最终,很多公司最终还是选择了原生+h5的方式.毕竟老技术已知优缺点,经得起考验.
在此基础上诞生了各种各样的小程序,同时对于web容器的深度技术挖掘也一直在进行中.

同时基于第二代技术的轻量化方案也慢慢出现在大众的视野:

使用内部统一描述语言对页面进行描述,由各平台转化成原生控件,整个解析和渲染方案按照公司内部约定执行,慢慢扩展新功能.

可以参考另一篇文章:动态渲染技术.

总而言之:跨平台技术还有很长的路要走,技术终究是实现业务发展的平台,没有优劣之分,慢慢观望吧.


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!