本节内容转载于[Flutter中文网](https://flutterchina.club/)
[TOC]
# 原生开发
原生开发指开发某一个应用平台(如Android或iOS)所特有的应用,使用相应平台支持的开发工具和语言,并直接调用系统提供的SDK API。
原生开发的优势:
* 可访问平台全部功能(GPS、摄像头)
* 速度快、性能高、可实现复杂动画及绘制
* 用户体验好
原生开发缺点:
* 平台特定,开发成本高,不同平台需要维护不同代码,人力成本随之增大
* 内容固定,动态化弱,新功能需发版才能更新
目前业务场景中的两个需求:
1、动态化内容需求增大
2、业务需求变化快,人力开发成本变大
针对这两个问题,诞生了一些跨平台的动态化框架。
# 跨平台开发
时至今日,已经有很多跨平台框架,根据其原理,主要分为三类:
* H5+原生混合开发(Cordova、Ionic、微信小程序)
* JavaScript开发+原生渲染 (React Native、Weex、快应用)
* 自绘UI+原生(QT for mobile、Flutter)
## H5+原生混合开发
框架:Cordova、Ionic、微信小程序等
混合开发的原理是将APP的一部分需要动态变动的内容通过H5来实现,通过原生的网页加载控件WebView (Android)或WKWebView(iOS)来加载。H5部分是可以随时改变而不用发版,动态化需求能满足;同时由于H5代码只需要一次开发,就能同时在Android和iOS两个平台运行,可以减小开发成本。
混合开发中H5代码运行在WebView中,而WebView本质是一个浏览器内核,其JavaScript运行在一个权限受限的沙箱中,所以对于大多数系统能力没有访问权限,如无法访问文件系统、不能使用蓝牙等。
对于H5不能实现的功能,都需要原生去做。混合框架一般都会在原生代码中预先实现一些访问系统能力的API, 暴露给WebView以供JavaScript调用。
WebView就成了JavaScript与原生API之间通信的桥梁,主要负责JavaScript与原生之间传递调用消息。消息的传递必须遵守一个标准的协议,来规定消息的格式与含义,我们把依赖于WebView的用于在JavaScript与原生之间通信并实现了某种消息传输协议的工具称之为**WebView JavaScript Bridge**, 简称**JsBridge**,JsBridge是混合开发框架的核心。
### 优点与缺点
优点:
1、H5加载,可以实现动态化,无需发版即可更新内容
2、一套代码开发,开发成本低
缺点:
1、性能不好,无法高效渲染复杂的用户界面或动画
2、无法直接访问部分系统能力(如文件系统、蓝牙等)
## JavaScript开发+原生渲染
框架:Reactive Native、Weex及快应用
### 响应式编程
React中有一个重要思想:状态改变则UI随之自动改变。React框架的工作就是响应用户状态改变的事件,重新构建用户界面,React是典型的**响应式**编程。
React中响应式原理如下:
* 1、开发者只需关注状态转移,当状态发生变化时,React框架会自动根据新的状态重新构建UI。
* 2、React框架在接收到用户状态改变的通知后,根据当前渲染树,结合最新的状态改变,通过Diff算法,计算出树中变化的部分,然后只更新变化的部分(DOM操作),从而避免整棵树重构,提高性能。
需要注意的是,第二步中状态变化后,React框架并不会立即去计算并渲染DOM树的变化部分。相反,React会在DOM的基础上建立一个抽象层,即**虚拟DOM**树,对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到真实DOM中,而不是每次改变都去操作一下DOM。因为在浏览器中每一次DOM操作都有可能引起浏览器的重绘或回流,浏览器的重绘和回流都是比较昂贵的操作,如每一次改变都直接对DOM进行操作,会带来性能问题,而批量操作只会触发一次DOM更新。
### Reactive Native原理
Reactive Native是React在原生移动应用平台的衍生产物,两者的主要区别在于:React中虚拟DOM最终会映射为浏览器DOM树,而Reactive Native中虚拟DOM会通过JavaScripCore映射为原生控件树。
JavaScriptCore是一个JavaScript解释器,在ReactiveNative中主要有两个作用:
* 为JavaScript提供运行环境
* 是JavaScript与原生应用间的通信桥梁,作用和JsBridge一样(在iOS中,很多JsBridge的实现都是基于JavaScriptCore)
在ReactiveNative中将虚拟DOM映射称为原生控件需要两步:
* 布局消息传递: 将虚拟DOM布局信息传递给原生
* 原生根据布局信息通过对应的原生控件渲染控件树
### Weex与快应用
Weex思想及原理与ReactiveNative类似,不同的是语法层面,Weex支持Vue语法和Rax语法。
快应用是华为、小米、OPPO、魅族等国内9大主流手机厂商共同制定的轻量级应用标准,目标直指微信小程序,它也是采用JavaScript语言开发,原生控件渲染,与React Native和Weex相比主要有两点不同:
* 快应用自身不支持Vue或React语法,其采用原生JavaScript开发(开发框架和微信小程序很像,值得一提的是小程序目前已经可以使用Vue语法开发(mpvue))
* React Native和Weex的渲染/排版引擎是集成到框架中的,每一个APP都需要打包一份,安装包体积较大;而快应用渲染/排版引擎是集成到ROM中的,应用中无需打包,安装包体积小,正因如此,快应用才能在保证性能的同时做到快速分发。
### 优点与缺点
优点:
1、原生控件渲染,性能比混合应用中的H5提高很多
2、使用Web开发技术栈,只需要维护一份代码,开发成本相对较低
3、动态化较好,支持热更新
缺点:
1、渲染时需要JavaScript与原生之间进行通信,某些场景可能因通信频繁导致卡顿
2、JavaScript为脚本语言,执行时需要JIT(Just In Time),执行效率和AOT(Ahead Of Time)代码仍有差距
3、渲染依赖原生控件,不同平台控件需要单独维护,系统更新时,社区控件可能会滞后。除此之外,控件系统也会受到原生UI系统限制,比如解决手势冲突问题。
## 自绘UI+原生
通过在不同平台实现一个统一接口的渲染引擎来绘制UI,而不依赖系统原生控件,所以可以做到不同平台UI的一致性。自绘引擎解决的是UI的跨平台问题,涉及其它系统能力调用,依然要使用原生开发。
### 优点与缺点
优点:
1、直接调用系统API来绘制UI,性能好
2、UI渲染不依赖原生控件,不需要根据不同平台的控件单独维护一套组件库,代码易维护
3、组件库是同一套代码、同一个渲染引擎,在不同平台组件上,显示外观可以做到高保真和高一致性;
4、不依赖原生控件,布局系统更加灵活
缺点:
动态性不足,自绘UI系统一般采用AOT模式编译其发布包,不能像使用JIT开发语言框架那样动态下发代码
### QT Mobile
Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。2008年,Qt Company科技被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具。2012年,Qt被Digia收购。
2014年4月,跨平台集成开发环境Qt Creator 3.1.0正式发布,实现了对于iOS的完全支持,新增WinRT、Beautifier等插件,废弃了无Python接口的GDB调试支持,集成了基于Clang的C/C++代码模块,并对Android支持做出了调整,至此实现了全面支持iOS、Android、WP,它提供给应用程序开发者构建图形用户界面所需的所有功能。
QT没有流行起来的原因所在:
* QT移动开发社区太小,学习资料不足,生态不好
* 官方推广不利,支持不够
* 移动端发力较晚,市场已被其它动态化框架占领(Hybrid和RN)
* 在移动开发中,C++开发和Web开发栈相比有着先天的劣势,直接结果就是QT开发效率太低
### Flutter
Flutter是Google发布的一个用于创建跨平台、高性能移动应用的框架。Flutter和QT mobile一样,都没有使用原生控件,相反都实现了一个自绘引擎,使用自身的布局、绘制系统。
## 总结
| 技术类型 | UI渲染方式 | 性能 | 开发效率 | 动态化 | 框架代表 |
| --- | --- | --- | --- | --- | --- |
| H5+原生 | WebView渲染 | 一般 | 高 | 支持 | Cordova、Ionic |
| JavaScript+原生渲染 | 原生控件渲染 | 好 | 中 | 支持 | RN、Weex |
| 自绘UI+原生 | 调用系统API渲染 | 好 | Flutter高, QT低 | 默认不支持 | QT、Flutter |
Flutter的Release包默认是使用Dart AOT模式编译的,所以不支持动态化,但Dart还有JIT或snapshot运行方式,这些模式都是支持动态化的。
- 导读
- Java知识
- Java基本程序设计结构
- 【基础知识】Java基础
- 【源码分析】Okio
- 【源码分析】深入理解i++和++i
- 【专题分析】JVM与GC
- 【面试清单】Java基本程序设计结构
- 对象与类
- 【基础知识】对象与类
- 【专题分析】Java类加载过程
- 【面试清单】对象与类
- 泛型
- 【基础知识】泛型
- 【面试清单】泛型
- 集合
- 【基础知识】集合
- 【源码分析】SparseArray
- 【面试清单】集合
- 多线程
- 【基础知识】多线程
- 【源码分析】ThreadPoolExecutor源码分析
- 【专题分析】volatile关键字
- 【面试清单】多线程
- Java新特性
- 【专题分析】Lambda表达式
- 【专题分析】注解
- 【面试清单】Java新特性
- Effective Java笔记
- Android知识
- Activity
- 【基础知识】Activity
- 【专题分析】运行时权限
- 【专题分析】使用Intent打开三方应用
- 【源码分析】Activity的工作过程
- 【面试清单】Activity
- 架构组件
- 【专题分析】MVC、MVP与MVVM
- 【专题分析】数据绑定
- 【面试清单】架构组件
- 界面
- 【专题分析】自定义View
- 【专题分析】ImageView的ScaleType属性
- 【专题分析】ConstraintLayout 使用
- 【专题分析】搞懂点九图
- 【专题分析】Adapter
- 【源码分析】LayoutInflater
- 【源码分析】ViewStub
- 【源码分析】View三大流程
- 【源码分析】触摸事件分发机制
- 【源码分析】按键事件分发机制
- 【源码分析】Android窗口机制
- 【面试清单】界面
- 动画和过渡
- 【基础知识】动画和过渡
- 【面试清单】动画和过渡
- 图片和图形
- 【专题分析】图片加载
- 【面试清单】图片和图形
- 后台任务
- 应用数据和文件
- 基于网络的内容
- 多线程与多进程
- 【基础知识】多线程与多进程
- 【源码分析】Handler
- 【源码分析】AsyncTask
- 【专题分析】Service
- 【源码分析】Parcelable
- 【专题分析】Binder
- 【源码分析】Messenger
- 【面试清单】多线程与多进程
- 应用优化
- 【专题分析】布局优化
- 【专题分析】绘制优化
- 【专题分析】内存优化
- 【专题分析】启动优化
- 【专题分析】电池优化
- 【专题分析】包大小优化
- 【面试清单】应用优化
- Android新特性
- 【专题分析】状态栏、ActionBar和导航栏
- 【专题分析】应用图标、通知栏适配
- 【专题分析】Android新版本重要变更
- 【专题分析】唯一标识符的最佳做法
- 开源库源码分析
- 【源码分析】BaseRecyclerViewAdapterHelper
- 【源码分析】ButterKnife
- 【源码分析】Dagger2
- 【源码分析】EventBus3(一)
- 【源码分析】EventBus3(二)
- 【源码分析】Glide
- 【源码分析】OkHttp
- 【源码分析】Retrofit
- 其他知识
- Flutter
- 原生开发与跨平台开发
- 整体归纳
- 状态及状态管理
- 零碎知识点
- 添加Flutter到现有应用
- Git知识
- Git命令
- .gitignore文件
- 设计模式
- 创建型模式
- 结构型模式
- 行为型模式
- RxJava
- 基础
- Linux知识
- 环境变量
- Linux命令
- ADB命令
- 算法
- 常见数据结构及实现
- 数组
- 排序算法
- 链表
- 二叉树
- 栈和队列
- 算法时间复杂度
- 常见算法思想
- 其他技术
- 正则表达式
- 编码格式
- HTTP与HTTPS
- 【面试清单】其他知识
- 开发归纳
- Android零碎问题
- 其他零碎问题
- 开发思路