一个跨平台解决方案的本质,一个为前端写的跨端引擎,本文转载请联系神光编程秘籍公众号。近年来,前端领域的跨端技术越来越多:reactnative、weex、flutter、electron、kraken等,那么多跨端方案,他们有共同的思路吗?我们能从这么多解法中找出本质原理吗?本文将尝试探讨以下问题:什么是跨平台,什么是跨平台跨端和跨平台的解决方案平台之间有什么区别前端领域的跨端解决方案有哪些跨平台和跨端的一般原则什么是跨平台我们知道,CPU有不同的架构和指令集,上层也有不同的操作系统,在另一个系统上是不可执行的。比如windows的exe文件在mac上是不能直接执行的。不同的系统是不同的运行平台。可执行文件不是跨平台的。不同平台提供的API不同,因此代码逻辑也可能不同,不同平台需要分别维护代码。这就带来了几个问题:多平台独立开发时,如何保证功能一致?他们必须单独测试吗?开发和测试的人力是多的,所以出现了一些跨平台的技术,目标是一段代码可以在任何平台上运行。我们先看看各个领域的一些跨平台方案:浏览器操作系统不同,浏览器上运行的网页代码确实是一样的。浏览器是具有悠久历史的跨平台解决方案的一个例子。网页跨平台并不意味着浏览器也是跨平台的。浏览器的可执行文件是针对各个平台单独开发编译的,但支持相同的网页解析逻辑,因此运行的网页是跨平台的。浏览器提供了一个容器,屏蔽了底层的差异,提供了统一的api(domapi),使得相同的代码可以运行在不同平台的统一容器中。这个容器叫做浏览器引擎,它由js引擎、渲染引擎等组成。dockerdocker是一种虚拟化技术,可以在操作系统之上增加一个虚拟层,在这一层之上划分一个或多个容器,然后在容器中运行系统和app,这样就可以做到软硬件分离实现,动态分配硬件资源给容器,方便app运行环境的整体迁移(保存为镜像)。Docker显然也是一种跨平台技术,同一个镜像可以运行在任何操作系统docker上。只要不同的操作系统实现了相同的容器。jvmjava是一种编译+解释语言。java源码编译成字节码,然后直接在vm上解释执行字节码。为什么java这么火?主要是因为跨平台。用c、c++等语言编写的代码需要在不同的操作系统上编译成可执行文件才能运行,而且每个平台的代码可能不一样,所以需要编写多份。因为java提供了jvm容器,只需要将源代码编译成jvm可以解释的字节码,而jdk提供了统一的API,由不同操作系统的底层API实现,这样对于java代码,不同的操作系统代码一致。jvm也通过容器技术实现了一段代码运行在多个平台,jre提供了统一的API,屏蔽了底层的差异。node、denonode、deno也是跨平台技术。通过提供一套一致的API,使得上面的js代码可以跨平台。这些API也由不同的平台实现。electronelectron内置了chromium,并注入了nodeapi和一些GUI相关的api。它是基于两大跨平台技术的跨平台解决方案。基于这些解决方案的组合,electron支持前端技术的桌面开发。跨平台方案的优缺点跨平台方案的优势很明显,就是一段代码在不同平台上运行在同一个容器中,不需要在不同平台上单独开发,这节省成本。但是跨平台的方案也有缺点:因为多了一层容器,相对于直接调用系统API,性能会有所降低。为了实现跨平台的一致性,需要提供统一的API。这个API有两个问题:API如何设计。整合不同平台的能力,选择合适的集合来实现。很难设计。Node、deno、java都抽象了操作系统的能力,提供了自己的跨平台API。部分API难以实现多平台一致性。当容器没有提供需要扩展的能力时就麻烦了,比如js引擎的bridge,jvm的jni,node的c++addon等等都是扩展这个容器的能力的方法。前端领域跨平台中的跨端解决方案是指跨操作系统,跨端是指客户端。客户端的特点是有接口,有逻辑,所以包括逻辑跨端和渲染跨端。主要客户端有web、Android、ios、iot设备等。目前主流的跨端方案有reactnative、weex、flutter、kraken、以及自研的跨端引擎。ReactNative跨端包括逻辑跨端和渲染跨端。rn的逻辑跨端是基于js引擎,通过bridge注入一些device-capableapi,而渲染跨端是使用Android和ios来实现react的虚拟dom的渲染。其中nativeapi和components(灰色画的部分)两端不一致,有时展开图中的灰色部分需要native配合。混合rn代码和自扩展代码会使代码更难管理。最著名的事件是airbnb从最大的ReactNative支持者到弃用ReactNative。weexweex也采用了类似的思路来实现跨终端,只不过其对接的上层ui框架是vue,力求做到双终端组件和api的一致性(虽然后续维护跟不上)。结构类似于上图。FlutterFlutter是近几年流行的跨终端解决方案,跨终端包括Android、ios、web等,它最大的特点是渲染不基于操作系统的组件,而是直接基于在绘图库(skia)上,实现了渲染的跨端。逻辑的跨端不是基于js引擎,而是自研的dartvm通过dart语言来写逻辑。kraken跨端包括渲染跨端和逻辑跨端两部分。有时只需要跨端渲染,有时只需要逻辑跨端,有时则需要一个完整的跨端引擎。这三种情况都有各自的适用场景。Kraken是一个跨端渲染引擎。基于flutter的绘图能力,实现CSS渲染,实现跨端渲染。自研的渲染引擎跨端引擎非常依赖底层实现的组件和API,开源的方案也要扩展这部分,所以有一定规模的团队会选择自研。自研的跨端引擎会和rn、weex不同:渲染部分不需要实现虚拟dom渲染,而是直接对接domapi,上层应用基于这些dom实现跨端渲染蜜蜂。这样理论上可以对接任何前端框架。逻辑部分也是基于js引擎,通过binding直接注入一些C++实现的API,或者在运行时通过bridge注入一些Android和iOS实现的API。自研跨端引擎的优势在于组件和API可以自行扩展,更快响应业务需求。其中,组件和API的双端一致性,以及统一API的设计是难点。跨端的一般原则是什么?其实跨端和跨平台的思路是差不多的。它们都实现了一个容器并为它提供了统一的API。这套API由不同的平台实现,以保证功能一致。具体来说,跨端分为渲染跨端和逻辑跨端。有时只需要单独的渲染跨端方案(如karen)和逻辑跨端方案,有时则需要完整的跨端引擎。weex和reactnative的渲染部分是通过实现虚拟dom的渲染来实现的,使用了Android和ios各自的渲染方式。逻辑部分使用了js引擎,通过bridge注入了一些Android和ios的API。Flutter直接使用skia绘图库进行绘制,逻辑使用跨终端的dartvm。但是无论具体的实现是什么,思路都是类似的:跨端引擎需要实现一个渲染引擎和一个vm,并基于这个架构实现各种组件和API。容器的API实现了跨端渲染和逻辑web容器。这两天web容器比较火。其实也是一种跨平台的技术。它是一个在浏览器中实现的容器,node的API是通过wasm实现的,这样在这个容器中就可以运行node代码。其实这个想法比较普遍,不过是个新场景。一个容器运行在浏览器容器之上,容器套娃。综上所述,我们讲了跨平台和跨端的区别。跨平台是指跨操作系统,而跨端是指跨客户端。跨平台技术讲了docker、browser、jvm、node、deno、electron、webcontainer等,都是跨平台(操作系统)的解决方案。跨平台有优点也有缺点。缺点是API的设计比较困难。Node、deno、java等都有自己的一层api设计;api一致性的保证也比较困难;其次,扩展方式比较复杂(jvm的jni,node的c++addon等)。跨端方案讲了reactnative,weex,flutter,kraken等,有的绑定react,vue等前端框架,直接从虚拟dom渲染,有的实现domapi,可以对接适用于任何前端框架。当然渲染或者逻辑跨端可以单独做。渲染跨端或者使用Android和ios提供的方法,或者自己画,逻辑跨端或者使用js引擎(可以对接前端框架)或者使用dartvm。希望这篇文章能帮助大家了解跨终端、跨平台容器的思路和优缺点,让大家快速了解一些新技术(比如Web容器)。
