移动开发技术有哪些?-程序员宅基地

技术标签: ViewUI  ui  移动开发  javascript  

原生开发技术

什么是原生开发?

原生开发指的是纯原生应用程序(简称App)开发,是在Android、iOS等移动平台上利用官方提供的开发语言、开发类库以及开发工具等进行App开发。比如Android App就是指使用Java或Kotlin开发语言在Eclipse或Android Studio的开发工具上直接调用Android SDK API开发的App;而iOS App就是指通过Objective-C或Swift开发语言在Xcode的开发工具上直接调用iOS SDK API开发的App。

原生开发的优点和缺点有哪些?

原生App开发代表着较好的用户体验和更快更高的性能,但是原生App的可移植性比较差,特别是一款原生App,Android和iOS都要各自开发,同样的逻辑、界面都要写两套。

主要优点:

  • 可访问Android/iOS(平台) 提供的全部功能(如GPS、摄像头...);
  • 速度快、性能高以及可实现复杂动画及绘制和整体用户体验好。

主要缺点:

  • 平台特定、开发成本高;不同平台必须维护不同代码,人力成本随之变大;
  • 内容固定,动态化弱;大多数情况下,有新功能更新、Bug修复完时只能重新发版,用户需将App重新下载升级。

跨平台开发技术

背景

在移动互联网发展初期,业务场景并不复杂,原生开发还可以应对产品需求迭代。但近几年,随着物联网时代到来,移动互联网高歌猛进、日新月异,在很多业务场景中,传统的纯原生开发已经不能满足日益增长的业务需求。

主要表现在:

  • 动态化内容需求增大,当需求发生变化时,纯原生应用需要通过版本升级来更新内容,但应用上架、审核是需要时间周期的,这对高速变化的互联网时代来说是很难接受的,因此对应用动态化(不发版也可以更新应用内容)的需求就变的迫在眉睫。
  • 业务需求变化快,开发成本变大,由于原生开发的代码一般都要Android、iOS两个开发团队进行维护,而且版本迭代时,无论人力成本还是测试成本都会变大。

因此针对纯原生开发主要面临的动态化和开发成本这两个问题,诞生了一些跨平台的动态化框架。

H5+原生混合开发

这类框架主要原理是将App的一部分需要动态变动的内容通过H5来实现,使用原生平台的网页加载控件WebView(Android)或WKWebView(iOS)来加载。这样一来,H5部分是可以随时改变而不用发版的,而且能满足动态化需求,同时,由于H5代码只需要一次开发,就能在Android和iOS两个平台上运行,这也可以减少开发成本,也就是说H5部分功能越多,开发成本就越小,我们称这种H5+原生的开发模式为混合(Hybrid)开发,采用混合模式开发的App称之为混合应用或Hybrid App,如果一个App的大多数功能都是H5实现的话,我们称其为Web App。

目前混合开发框架的典型代表有:淘宝、Cordova和Ionic以及微信小程序等,值得一提的是微信小程序目前是在WebView中渲染的,但将来有可能会采用原生渲染。

混合开发技术点:JS代码与原生代码之间的通信

综上所述,原生开发可以访问平台全部功能,但混合开发中,H5代码是运行在WebView中,而WebView实质上就是一个浏览器内核,其JavaScript依然运行在一个权限受限的沙箱中,所以对于大多数系统的访问能力都受到了限制,如无法访问文件系统、不能使用蓝牙等。所以,对于H5不能实现的功能,都需要原生去做。而混合框架一般都会在原生代码中预先实现一些JavaScript需要访问系统能力的API,然后暴露给WebView以供JavaScript调用,这样一来,WebView就成为了JavaScript与原生API之间通信的桥梁,主要负责JavaScript与原生之间传递调用消息,而消息的传递必须遵守一个标准的协议,它规定了消息的格式与含义,我们把依赖于WebView的,用于在JavaScript与原生之间通信并实现了某种消息传输协议的工具称之为WebView JavaScript Bridge(简称JsBridge),它也是混合开发框架的核心。

示例:JavaScript调用原生API获取手机型号

下面我们以Android为例,实现一个获取手机型号的原生API供JavaScript调用。在这个示例中将展示JavaScript调用原生API的流程,读者可以直观的感受一下调用流程。我们选用Github上开源的dsBridge(Android版iOS版)来进行通信。dsBridge是一个支持同步调用的跨平台的JsBridge,此示例中只使用其同步调用功能。

1.首先在原生中实现获取手机型号的API

class JSAPI{
  @JavascriptInterface
  public Object getPhoneModel(Object msg) {
    return Build.MODEL;
  }
}
复制代码

2.将原生API通过WebView注册到JsBridge中

import wendu.dsbridge.DWebView
...
//DWebView继承自WebView,由dsBridge提供  
DWebView dwebView= (DWebView) findViewById(R.id.dwebview);
//注册原生API到JsBridge
dwebView.addJavascriptObject(new JSAPI(), null);
复制代码

3.在JavaScript中调用原生API

var dsBridge=require("dsbridge")
//直接调用原生API `getPhoneModel`方法
var model=dsBridge.call("getPhoneModel");
//打印机型
console.log(model);
复制代码

上面示例演示了JavaScript调用原生API的过程,同样的,一般来说优秀的JsBridge也支持原生调用JavaScript,dsBridge也是支持的,如果您感兴趣,可以去Github dsBridge(Android版iOS版)项目主页查看。

总结

混合应用的优点是动态内容是H5,新功能增加、Bug的修复完无需让App再次发版,Web技术栈、社区及资源丰富,缺点就是性能不好,对于复杂用户界面或动画,WebView不堪重任。

JavaScript开发+原生渲染

目前市面上流行的JavaScript开发+原生渲染的跨平台框架有快应用、WeexReact Native(简称RN)。

由于RN和React原理相通,并且Flutter也是受React启发,很多思想也都是相通的,万丈高楼平地起,我们有必要深入了解一下React原理,React是一个响应式的Web框架,我么先了解两个重要的概念:DOM树与响应式编程。

DOM树

文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口,一种独立于平台和语言的方式访问和修改一个文档的内容和结构。换句话说,这是表示和处理一个HTML或XML文档的标准接口。简单来说,DOM就是文档树,与用户界面控件树对应,在前端开发中通常指HTML对应的渲染树,但广义的DOM也可以指Android中的XML布局文件对应的控件树,而术语DOM操作就是指直接来操作渲染树(或控件树),因此,可以看到其实DOM树和控件树是等价的概念,只不过前者常用于Web开发中,而后者常用于原生开发中。

响应式编程

React中提出一个重要思想:状态改变则UI随之自动改变,而React框架本身就是响应用户状态改变的事件而执行重新构建用户界面的工作,这就是典型的响应式编程方式,下面我们总结一下React中响应式原理:

  • 开发者只需关注状态转移(数据),当状态发生变化,React框架会自动根据新的状态重新构建UI。
  • React框架在接收到用户状态改变通知后,会根据当前渲染树,结合最新的状态改变,通过Diff算法,计算出树中变化的部分,然后只更新变化的部分(DOM操作),从而避免整棵树重构,提高性能。

值得注意的是,在上述第二步中,状态变化后React框架并不会立即去计算并渲染DOM树的变化部分,相反,React会在DOM的基础上建立一个抽象层,即虚拟DOM树,对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM中,最后再批量同步到真实DOM中,而不是每次改变都去操作一下DOM。为什么不能每次改变都直接去操作DOM树?这是因为在浏览器中每一次DOM操作都有可能引起浏览器的重绘或回流:

  • 如果DOM只是外观风格发生变化,如颜色变化,会导致浏览器重绘界面;
  • 如果DOM树的结构发生变化,如尺寸、布局以及节点隐藏等,会导致浏览器回流及重新排版布局。

而浏览器的重绘和回流都是比较昂贵的操作,如果每一次改变都直接对DOM进行操作,这会带来性能问题,而批量操作只会触发一次DOM更新。

JavaScript开发+原生渲染的跨平台框架
RN

RN是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架React在原生移动应用平台的衍生产物,目前支持iOS和Android两个平台。RN使用JavaScript语言,类似于HTML的JSX(即JavaScript XML——一种在React组建内部构建标签的类XML语法),以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

RN是React在原生移动应用平台的衍生产物,那两者主要的区别是什么呢?其实,主要的区别在于虚拟DOM映射的对象是什么?React中虚拟DOM最终会映射为浏览器DOM树,而RN中虚拟DOM会通过JavaScriptCore映射为原生控件树。

1、JavaScriptCore是一个JavaScript解释器,它在RN中主要有两个作用:

①、为JavaScript提供运行环境;

②、是JavaScript与原生之间通信的桥梁,作用和JsBridge一样,事实上,在iOS中,很多JsBridge的实现都是基于JavaScriptCore。

2、RN中通过JavaScriptCore将虚拟DOM映射为原生控件的过程分为两步:

①、布局消息传递,将虚拟DOM布局信息传递给原生;

②、原生根据布局信息通过对应的原生控件渲染控件树。

至此,RN便实现了跨平台,相对于混合应用,因为RN是原生控件渲染,所以性能会比混合应用中的H5好很多,同时RN是Web开发技术栈,也只需维护一份代码,即可在多个平台上使用。

Weex

Weex是阿里巴巴于2016年发布的跨平台移动应用开发框架,思想及原理和RN类似,最大的不同是语法层面,RN只支持JSX语法,而Weex支持Vue语法和Rax语法,Rax的DSL语法是基于React JSX语法而创造的,与React不同,在Rax中JSX是必选的,它不支持通过其他方式创建组件,所以学习JSX是使用Rax的必要基础。

快应用

快应用是华为、小米和OPPO以及魅族等国内9大主流手机厂商共同制定的轻量级应用标准,目标直指小程序。它也是采用JavaScript语言开发,原生控件渲染,与RN和Weex相比主要有两点不同:

  • 快应用自身不支持Vue或React语法,其采用原生JavaScript开发,开发框架和微信小程序很像,值得一提的是小程序目前已经可以使用Vue语法开发(mpvue),从原理上来讲,Vue的语法也可以移植到快应用上。
  • RN和Weex的渲染/排版引擎是集成到框架中的,每一个App都需要打包一份,安装包体积较大;而快应用渲染/排版引擎是集成到ROM中的,应用中无需打包,安装包体积小,正因如此,快应用才能在保证性能的同时做到快速分发。
总结

JavaScript开发+原生渲染的方式主要优点如下:

  • 采用Web开发技术栈、社区庞大和上手快以及开发成本相对较低;
  • 原生渲染,性能相比H5提高很多;
  • 动态化较好,支持热更新。

JavaScript开发+原生渲染的方式主要缺点如下:

  • 渲染时需要JavaScript和原生之间通信,在有些场景,如拖动可能会因为通信频繁导致卡顿;
  • JavaScript为脚本语言,执行时需要JIT(即时编译),执行效率和AOT(提前编译)代码仍有差距;
  • 由于渲染依赖原生控件,不同平台的控件需要单独维护,并且当系统更新时,社区控件可能会滞后;除此之外,其控件系统也会受到原生UI系统限制,例如,在Android中,手势冲突消歧规则是固定的,这在使用不同人写的控件嵌套时,手势冲突问题将会变得非常棘手。

自绘UI+原生

自绘UI+原生是一种跨平台技术,这种技术的思路是:通过在不同平台实现一个统一接口的渲染引擎来绘制UI,而不依赖系统原生控件,所以可以做到不同平台UI的一致性。注意,自绘引擎解决的是UI跨平台问题,如果涉及其他系统能力调用,依然要依赖原生开发。

自绘UI+原生的优点如下:

  • 性能高;因为自绘引擎是直接调用系统API来绘制UI,所以性能和原生控件接近。
  • 灵活、组件库易维护以及UI外观保真度和一致性高;因为UI渲染不依赖原生控件,也就不需要根据不同平台的控件单独维护一套组件库,所以代码容易维护;由于组件库是同一套代码、同一个渲染引擎,所以在不同平台,组件显示外观可以做到高保真和高一致性;另外,由于不依赖原生控件,也就不会受原生布局系统的限制,这样布局系统会非常灵活。

自绘UI+原生的缺点如下:

  • 动态性不足;因为为了保证UI绘制性能,自绘UI系统一般都会采用AOT(提前编译)模式编译其发布包,所以应用发布后,不能像Hybrid和RN那些使用JavaScript(JIT,即时编译)作为开发语言的框架那样动态下发代码。

也许你已经猜到Flutter就属于这一类跨平台技术,没错,Flutter实现了一套自绘引擎,并拥有一套自己的UI布局系统。不过,自绘引擎的思路并不是什么新概念,Flutter也并不是第一个尝试这么做的,在它之前就有一个典型的代表——QT。

QT

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虽然在PC端获得了巨大成功,备受社区追捧,然而其在移动端却表现不佳,在近几年,虽然偶尔能听到QT的声音,但一直很弱,无论QT本身技术如何、设计思想如何,但事实上终究是败了,究其原因,笔者认为主要有四:

  • QT移动开发社区太小,学习资料不足,生态不好;
  • 官方推广不利,支持不够;
  • 移动端发力较晚,市场已被其它动态化框架占领(Hybrid和RN);
  • 在移动开发中,C++开发和Web开发栈相比有着先天的劣势,直接结果就是QT开发效率太低。

基于此四点,尽管QT是移动端开发跨平台自绘引擎的先驱,但却成为了烈士。

Flutter

Flutter是Google推出并开源的移动应用程序(App)开发框架,主打跨平台、高保真、高性能。其采用Dart语言作为开发语言,开发者可以通过Dart语言开发Flutter App,一套代码可同时运行在iOS和Android平台上。Flutter提供了丰富的组件、接口,开发者可以很快地为Flutter添加原生扩展。

Flutter与其他用于构建App的大多数框架不同,因为Flutter既不使用WebView,也不使用平台(Android、iOS等)的原生控件。相反,Flutter使用自己的高性能渲染引擎来绘制Widget。这样不仅可以保证在Android和iOS平台上UI的一致性,而且也可以避免对原生控件依赖而带来的限制及高昂的维护成本。

Flutter使用Skia作为其2D渲染引擎,Skia是Google的一个2D图形处理函数库,包含字型、坐标转换以及点阵图都有高效能且简洁的表现,Skia是跨平台的,并提供了非常友好的API,目前Google Chrome浏览器和Android均采用Skia作为其绘图引擎,值得一提的是,由于Android系统已经内置了Skia,所以Flutter在打包APK(Android应用安装包)时,不需要再将Skia打入APK中,但iOS系统并未内置Skia,所以构建iPA时,也必须将Skia一起打包,这也是为什么Flutter APP的Android应用安装包比iOS应用安装包小的主要原因。

但是Flutter也有不足之处,不支持动态下发代码和热更新。

请戳一戳了解更多Flutter

本章总结

本章主要介绍了目前移动开发中三种跨平台开发技术和原生开发技术,现在我们从框架角度对比一下三种跨平台开发技术:

技术类型 UI渲染方式 性能 开发效率 动态化 框架代表
H5+原生 WebView渲染 一般 Cordova、Ionic
JavaScript+原生渲染 原生控件渲染 RN、Weex
自绘UI+原生 调用系统API渲染 Flutter高,QT低 默认不支持 QT、Flutter

上表中动态化主要指是否支持动态下发代码和是否支持热更新。值得注意的是Flutter的Release包默认是使用Dart AOT(提前编译)模式编译的,所以不支持动态化,但Dart还有JIT(即时编译)或snapshot运行方式,这些模式都是支持动态化的,后续会介绍。

此文章整理于:book.flutterchina.club/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34204057/article/details/91361835

智能推荐

Vue + ElementUI 项目中使用vue-pdf 实现简单预览_vue+elementui使用vue-pdf实现预览功能-程序员宅基地

文章浏览阅读6k次。Vue + ElementUI 项目中使用vue-pdf 实现简单预览1、安装 vue-pdfnpm install --save vue-pdf2、在vue页面中导入对应的组件我这是通过点击 预览 按钮 获取id打开一个dialog来实现<!--PDF 预览--> <el-dialog :title="PDF 预览" ..._vue+elementui使用vue-pdf实现预览功能

C语言指针及占据内存空间_c语言 指针占用空间-程序员宅基地

文章浏览阅读1.7k次,点赞12次,收藏30次。目录:第一、了解内存空间第二、理解指针第三、指针运算问题正文:第一、了解内存空间本文章文字有点多,会有点枯燥,配合图文一起看可以缓解枯燥,耐心阅读哦!!!先了解内存地址,才更好的理解指针!我们可以把内存想象为成一列很长很长的货运火车,有很多大小相同的车厢,而每个车厢正好相当于在内存中表示一个字节。这些车厢装着不同的货物,就像我们的内存要存着各式..._c语言 指针占用空间

C++ 实时显示7z压缩与解压缩的进度_c++实时获取解压进度-程序员宅基地

文章浏览阅读3.5k次。一、7zip下载地址:https://www.7-zip.org/sdk.html二、nmake编译下载完后,进入文件夹:使用VS的命令行工具(nmake)进行编译(命令:nmake /f makefile),在当前目录下生成x86文件夹,里面有本次编译的成果文件:7zra.dll三、转换示例工程(dsw转vs08)打开client7z工程,下载下来的是由dsw格式(N年前的格式,真是不懂得与时俱进),将其用vs08打开(vs17版本打开,会转换失败)四、修改示例代码打开client_c++实时获取解压进度

2021CCPC广州 H. Three Integers-程序员宅基地

文章浏览阅读2k次。题目链接You are given three non-negative integers aaa, bbb, and ccc. Find three positive integers xxx, yyy, and zzz that satisfy x mod y=ax\bmod y=axmody=a, y mod z=by\bmod z=bymodz=b, and z mod x=cz\bmod x=czmodx=c.InputThe first line contains an integer t_h. three integers

docker-compose up -d使用遇到问题no configuration file provided: not found-程序员宅基地

文章浏览阅读660次,点赞9次,收藏7次。docker-compose使用问题_no configuration file provided: not found

增加product项目_product增加-程序员宅基地

文章浏览阅读1.2k次。增加一个新的项目chunge7inch,类似smdkv210,需要做如下步骤:1. cp -rf device/samsung/smdkv210 device/samsung/chunge7inch 将device/samsung/chunge7inch目录下含有“smdkv210”字样的全部改成"chunge7inch"2. cp -rf vendor/samsung/smdk_product增加

随便推点

vue图片视频预览_vue 页面预览视频-程序员宅基地

文章浏览阅读552次。vue图片预览_vue 页面预览视频

学习好并用好大模型-程序员宅基地

文章浏览阅读842次,点赞20次,收藏12次。大模型是个好东西,学好并用好益处多多~

[UEFI开发] Linux Ubuntu EDK2环境搭建_ubuntu edk2 uefi-程序员宅基地

文章浏览阅读2.9k次,点赞4次,收藏18次。[UEFI开发]配置EDK2开发环境 (Ubuntu X86_64)_ubuntu edk2 uefi

HTML基础(一)-程序员宅基地

文章浏览阅读977次。更新中~~文章目录常用浏览器以及内核常用浏览器以及内核

JS:Uint8Array 数组类型、arraybuffer对象类型与十六进制字符串互转-程序员宅基地

文章浏览阅读2.3w次,点赞7次,收藏36次。最近,在做区块链浏览器,调用合约与链上进行数据通信的时候,需要将对象转化成十六进制字符串,看看下 javascript 关于 ArrayBuffer 类型的api文档,新的如下:arraybuffer类型转16进制字符串function buf2hex(buffer) { return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).j._uint8array

write.wait_for_active_shards参数和 refresh参数实现elasticsearch同步写入_wait_for_active_shards=0-程序员宅基地

文章浏览阅读2.9w次,点赞3次,收藏3次。  elasticsearch一般称为近实时的大数据处理引擎,为什么是近实时呢?原因是当我们提交索引数据时,实际上只是写到了Buffer里面,并不是立即可搜索的,最多需要等1秒才可搜索(index.refresh_interval由这个参数控制,可以通过动态API自定义设置,或在建索引时在settings里面设置),还有一点,当存在副本时,只保证主分片写入成功写入请求就会返回,此时搜索请求如果分配..._wait_for_active_shards=0