21
头图

跨平台技术发展的三个阶段

  • 第一阶段是混合开发的web容器时代

    • 为了解决原生开发的高成本、低效率,出现了Hybrid混合开发
    • 原生中嵌入依托于浏览器的WebView
    • Web浏览器中可以实现的需求在WebView中基本都可以实现
    • 但是Web最大的问题是,它的性能和体验与原生开发存在肉眼可感知的差异
    • 因此并不适用于对性能和用户体验要求较高的场景
  • 第二阶段是以RN和Weex为代表的泛web容器时代

    • RN对Web标准进行了功能裁剪
    • 用户体验更接近于原生了
    • 由于进行了功能裁剪,所以RN对业务的支持能力还不到浏览器的5%
    • 因此仅适用于中低复杂度的低交互类页面。面对稍微复杂一点儿的交互和动画需求,都需要通过调用原生代码去扩展才能实现
  • 第三阶段是以Flutter为代表的自绘引擎时代

    • Flutter是构建Google物联网操作系统Fuchsia的SDK
    • 它使用Dart语言开发APP
    • 一套代码可以同时运行在iOS和Android平台上
    • Flutter采用自带的Native渲染引擎渲染视图,它是自己完成了组件渲染的闭环
    • 而RN、Weex之类的框架,只是通过JavaScript虚拟机扩展调用系统组件,最后是由Android或者iOS系统来完成组件的渲染

下面来看一下几类型的混合开发APP:

Web APP框架

ionic

Ionic框架是基于Web技术应用HTML、CSS以及Java技术进行智能设备APP开发的框架,Ionic框架是用来开发混合模式的移动APP开发框架;

优势

  • 全套的UI组件
    Ionic框架很注重外观的体验,所以它提供了很多UI组件帮助开发者开发APP,比如:下拉刷新、标签等。界面美观,开发者能够很快的上手,开发的APP都很实用。
  • 代码容易维护
    Ionic框架是基于AngularJS,也就支持AngularJS的特点,遵循标准的代码,维护代码就很容易,能够完美融合AngularJS
  • 支持跨平台
    可以在主流的Android操作系统和ios操作系统上运行,或者其他的操作系统也可以支持
  • 很多强大的命令行
  • 强大的社区、框架适用范围广
    能够编译成各个平台的应用程序

劣势

  • 内存占用高
  • 不适合做游戏类型app
  • web技术无法解决一切问题,对于比较耗性能的地方无法利用native的思维实现优势互补,如高体验的交互,动画等

Cordova

Cordova提供了一组设备相关的API;通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头、麦克风等;Cordova还提供了一组统一的JavaScript类库,以及为这些类库所用的设备相关的原生后台代码;Cordova支持如下移动操作系统:iOS, Android,ubuntu phone os, Blackberry, Windows Phone, Palm WebOS, Bada 和 Symbian。

通信

  • 通信原理

    1. 保存Cordova_plugin.js的 插件文件名字和地址
    2. 插件的API呼出时,通过调用Cordova的exec模块将API的参数保存在CommandQueue的队列中。 CALLBACK则保存在JS侧的callbacks map里面
    3. 添加一个空的iframe,iframe的src则指向gap://ready
    4. 3的iframe的src设置以后,NATIVE侧UIWebviewDelegate#shouldStartLoadWithRequest则被呼出来
    5. Webview的Delegatet判断gap://ready的情况下,则执行commandDelegate的处理
    6. commandDelegate则从JS侧取出API的参数,内部实现则是通过 UIWebview#stringByEvaluatingJavaScriptFromString的返回值 取得CommandQueue里面的参数转换成JSON数据
    7. 根据6的插件,执行NATIVE定义的插件实例
    8. 插件中,有CALLBACK的情况下,成功失败的结果通过UIWebview#stringByEvaluatingJavaScriptFromString执行JS,JS端则根据传过来的CALLBACKID,从callbacks map取出回调函数并执行
  • 通信方式

    • iframe的方法(默认)
    • xmlHttpRequest的方法(iOS5.x版本因为 -webkit-scroll的IFRAME有BUG,则推荐使用)
  • 插件导入流程

    • Native

      - APP启动,MainViewController初始化之时,queue和command的DELEGATE初期化
      - config.xml文件解析,插件名设置到数组,插件文件和插件名设置到pluginMap,属性设置到setting
      - 在Webview类里面,加载index.html,index.html里面加载cordova.js、开始初期化
      
    • JS

      - 加载cordova.js时、内部的事件设置模块,NATIVE交互模块,初期化模块,插件加载
      - 插件模块是cordova_plugins.js文件定义的插件文件地址,文件名保存的MAP
      - deviceready事件发布后,插件的API可以使用了
      - 插件API执行后,模块MAP将插件文件加载,执行exec函数
      - 在index.html里面添加一个空的iframe、指定src=gap://ready,通知到Nativie
      

优势

  • iOS和Android基本上可以共用代码;
  • 纯web思维,开发速度快, 简单方便,一次编码,到处运行;
  • 如果熟悉web开发,文档很全, 系统级支持封装较好,所有UI组件都是有html模拟,可以统一 使用;
  • 可实现在线更新,允许动态加载web js;
  • 文档多,开发者多,遇到问题容易解决,技术成熟;

劣势

  • 占用内存高一些;
  • 不适合做游戏类型app;
  • web技术午无法解决一 切问题,对于比较耗能的地方无法利用native的思维实现优势互 补,如高体验的交互,动画等。

Hybrid APP(Webview)

利用 安卓和 iOS 上的 webview 容器,APP 能够执行 html、css 和 js 脚本,展示 web 页面。如果需要原生功能就添加 bridge 供 java 调用。具有开发效率高、跨平台、支持动态发布等特点,它是目前应用最广泛最成熟的一种方案;

Webview通信

  • 假跳转的请求拦截(不建议)

    • 假跳转的请求拦截 就是由网页发出一条新的跳转请求,跳转的目的地是一个非法的压根就不存在的地址
    • 比如:wbcst://testhost/action?params=xxx
    • 模拟http协议网络请求 scheme://host/action?params
    • 客户端会无差别拦截所有请求,真正的url地址应该照常放过,只有协议域名匹配的url地址才应该被客户端拦截
    • JS调用方式

      1. a标签跳转
      2. location.href跳转
      3. iframe跳转
    • 不建议使用,android系统对url参数做了字节限制,无法进行大数据的通信
  • 弹窗拦截(不建议)

    • alert

      • 弹出个提示框,只能点确认无回调
    • confirm

      • 弹出个确认框(确认,取消),可以回调
    • prompt

      • 弹出个输入框,让用户输入东西,可以回调
    • 不建议使用,会无差别的拦截所有前端的window弹窗
  • JS上下文注入(推荐)

    • iOS

      • WKWebView scriptMessageHandler注入
    • android

      • addJavascriptInterface注入
    • 特点

      • 不通过任何拦截的办法,而是直接将一个native对象(or函数)注入到JS里面,可以由web的js代码直接调用,直接操作

WebView 渲染引擎设计的上的缺陷

  • JS Execute,Layout, Paint 都在MainThread ,无法并行化。
  • JS 的性能赶不上 Native Tookit 的 Java Dart Object-C 等编译型语言,执行复杂逻辑时会卡顿。
  • 渲染流水线非常长,导致浏览器对合成器动画和非合成器动画区分对待,非合成器动画性能不佳。
  • OpenGL 设计上是推荐单线程模型,一个 Context 同时只能运行一个线程使用。 GPU Thread 运行在单独 GPU 进程, Render 进程无法访问 GPU 进程的 OpenGL Context ,两个进程无法 Texture 共享资源。 Render 进程只能输出 Bitmap/Command Buffer 通过 IPC 传递给 GPU 进程,无法直接在 GPU 进程的 Open GL Context 做直接光栅化,难以充分发挥现代 GPU 的性能。
  • 光栅化是异步进行的,进行惯性滚动时,会出现白屏,这个是 Webview 始终无法避免的问题。
  • 设备平台众多,需要兼容CPU渲染,无法进行 All In GPU 的设计。

优势

  • 跨平台
  • 开发周期短、成本低
  • 用户体验良好
  • 可以即时修复bug、动态发版

劣势

  • 仿原生iOS效果复杂
  • 机型兼容性

ReactNative/Weex跨平台技术

这种技术最大化的复用前端的生态和 Native 的生态体系,把 Native View 的高性能组件积累输出给前端的技术体系。此方案和浏览器的最大区别在于 Script 的执行和 Native View 渲染体系。

ReactNative

img

通信流程(OC)

  • ①js调用OC模块暴露出来的方法
  • ②把调用方法分解为ModuleName、MethodName、arguments,在丢给MessageQueue处理
  • ③把js的callback函数缓存在MessageQueue的一个成员变量里面,同时生成一个CallbackID来代表callback;在通过保存在MessageQueue的模块配置表把ModuleName、MethodName转成ModuleID、MethodID
  • ④把ModuleID、MethodID、CallbackID和其他参数传给OC(JavaScriptCore)
  • ⑤OC接到消息,通过模块配置表拿到对于的模块和方法
  • ⑥RCTModuleMethod对js传过来的参数进行处理
  • ⑦OC模块方法执行完,执行block回调
  • ⑧调用第6步中RCTModuleMethod生成的block
  • ⑨block带着CallbackID和block传过来的参数去掉用js里的MessageQueue方法invokeCallbackAndReturnFlushedQueue
  • ⑩MessageQueue通过CallbackID找到相应的js的callback方法
  • ⑪调用callback方法,并把OC带过来的参数一起传过去完成回调

优势

虽然不能做到一次编码到处运行,但是基本上即使是两套代码, 也是相同的jsx语法, 使用js进行开发。用户体验高于html, 开发效率较高

Flexbox布局据说比native的自适应布局更加简单高效

劣势

对开发人员要求较高,不是懂点web技术就行的,当官方封装的 控件、API无法满足需 求时就必然需要懂一些native的东西去 扩展,扩展性仍然远远不如web,也远远不如直 接写Native Code。

Weex

img

实现原理

Weex 对外通过 Rax 和 Vue 前端框架进行功能输出,前端框架下有一层 JS Framework 来实现 dom 的功能。 WeexCore 负责基础的 Flex Layout ,然后通过 Component 分别对接到 Android/iOS 的 Platform Native View 体系。

优势

  • Android Native 采用更轻量级的渲染流水线,能更快更高效的的响应事件;
  • RenderThread 直接操作 OpenGLContext ,进行 Direct GPU Raster ,充分发挥现代 GPU 的特性,提供高性能渲染和流畅的体验;
  • 部分耗时操作,如 Bitmap 上传 Texture , TextureThread 上传到 Share Open GL Context 中, Texture 完成后通知主线程进行绘制,通过 Share Open GL Context 与主线程共享 Texture 等资源。 WebView 只能在 Render Process 内部进行 Texture 的共享, RenderProcess 无法与 GPU Process 共享 Texture 等资源;
  • Android Native 有 RecycleView ViewPager 等高级组件,每个高级组件都做了性能的最佳实践;浏览器上的高级组件只能通过 JS 模拟实现,优化定制效率低;
  • 浏览器流水线设计复杂,需要考虑到 PC 、手机、嵌入式设备等多种复杂的环境,不少设备上木有 GPU ,只能进行 CPU 渲染。无法像 Android Native 体系一样进行 All In GPU 的体系设计,全面发挥现代 GPU 的性能。

劣势

Weex 体系充分将 Native 的 View 体系输出到前端体系中,在进行 Android/iOS Native View 的封装过程中,存在不少难以逾越的障碍

Flutter自绘引擎

Flutter是Google发布的一个用于创建跨平台、高性能移动应用的框架。Flutter和QT mobile一样,都没有使用原生控件,相反都实现了一个自绘引擎,使用自身的布局、绘制系统

框架

图1-1

基础架构主要分为三个部分:

  • Framework

    • 纯 Dart实现的 SDK,类似于 React在 JavaScript中的作用
    • 它实现了一套基础库, 用于处理动画、绘图和手势
    • 基于绘图封装了一套 UI组件库
    • 根据 Material 和Cupertino两种视觉风格区分开来
  • Engine

    • 纯 C++实现的 SDK
    • 包括

      • Skia引擎
      • Dart运行时
      • 文字排版引擎等
    • 它是 Dart的一个运行时,它可以以 JIT 或者 AOT的模式运行 Dart代码
    • 这个运行时还控制着 VSync信号的传递、GPU数据的填充等,并且还负责把客户端的事件传递到运行时中的代码
  • Embedder

    • Embedder是操作系统适配层
    • 实现了

      • 渲染Surface设置
      • 线程设置
      • 平台插件等平台相关特性的适配

渲染流程

image-20210126154129830

  • GPU的VSync信号同步给到UI线程
  • UI线程使用Dart来构建抽象的视图结构(这里是Framework层的工作)
  • 绘制好的抽象视图数据结构在GPU线程中进行图层合成(在Flutter Engine层的工作)
  • 然后提供给Skia引擎渲染为GPU数据,最后通过OpenGL或者 Vulkan提供给 GPU

优势

高生产效率。一套代码可以开发出Android和iOS应用;Dart语 言优越性,使得同样的 功能只需要很少的代码;迭代更加方便, hot reload功能;

创建优雅的、高度可定制的用户界面。Flutter内置了对Material Design和Cupertino(iOS-favor)的UI组件库;提供了可定制 的UI组件,不再受制于OEM控件的限制;

借助可移植的GPU加速的渲染引擎以及高性能本地ARM代码运行 时以达到跨平台的高质量用户体验。

劣势

Flutter采用Dart语言开发,属于小众语言,需要一切都要重新 学习。

横向对比

对比内容ReactNativeweexFlutterHybrid
平台实现JavaScriptJavaScript原生编码H5
引擎JSCoreJS V8Flutter EngineWebview
核心语言ReactVueDartJavaScript
打包bundle文件默认单一文件比较大(可拆包)较小,多页面多文件不需要前端JS、CSS一般CDN引用
跨平台中上
热更新暂无方案
性能中上

兰俊秋雨
5.1k 声望3.5k 粉丝

基于大前端端技术的一些探索反思总结及讨论