移动端跨平台技术总结

概述

之前你们觉得在手机上可以像桌面那样经过 Web 技术来实现跨平台开发,却因为性能或其余问题而放弃。不得不针对不一样平台开发多个版本号。php

这也违背了跨平台开发的初衷。而React Native让跨平台移动端开发在次回到人们的视野中,其成功的缘由除了他“一次编写到处执行”,还因为它相比h5等前端技术,有了更接近原生的体验。
为了方便理解。笔者将跨平台技术分为4大流派:css

  • Web 流:也被称为 Hybrid 技术。它基于 Web 相关技术来实现界面及功能
  • 代码转换流:将某个语言转成 Objective-C、Java 或 C#,而后使用不一样平台下的官方工具来开发
  • 编译流:将某个语言编译为二进制文件,生成动态库或打包成 apk/ipa/xap 文件
  • 虚拟机流:经过将某个语言的虚拟机移植到不一样平台上来执行

web流

Web 流,如你们熟知的PhoneGap/Cordova等技术。它将原生的接口封装后暴露给 JavaScript。而后经过系统自带的 WebView 执行。也可以视野本身内嵌Chrome内核。
Web 流最常被吐槽的就是性能差,渲染速度慢。现在说到 Web 性能差主要说的是 Android 下比較差,在 iOS 下已经很是流畅了。
说到性能差,主要缘由是在Android和ios的早期设备中。因为没有实现GPU加速,因此形成每次重绘界面的卡顿。
而形成渲染慢的第二个缘由是:css过于复杂。因为从实现原理上看 Chrome 和 Android View 并无本质上的差异,但过于复杂的css会加剧gpu的负担。前端

那是否是可以经过简化 CSS 来解决?实际上还真有人这么尝试了,比方 Famo.us,它最大的特点就是不让你写 CSS,仅仅能使用固定的几种布局方法,全然靠 JavaScript 来写界面,因此它能有效避免写出低效的 CSS,从而提高性能。
形成绘制缓慢的第三个缘由是,业务需求的复杂。如要实现超长的 ListView商品展现。java

因为 DOM 是一个很是上层的 API,使得 JavaScript 没法作到像 Native 那样细粒度的控制内存及线程,因此难以进行优化。则在硬件较差的机器上会比較明显
上面三个问题现在都很差解决。事实上除了性能以外,Web 流更严重的问题是功能缺失。react

比方 iOS 8 就新增 4000+ API。而 Web 标准需要漫长的编写和评审过程。而等到web审核经过,即使是Cordova这样的框架本身封装也是忙只是来的。因此为了更好地使用系统新功能,Native是最快的选择。android


尽管前面提到 HTML/CSS 过于复杂致使性能问题,但事实上这正是 Web 最大的优点所在,因为 Web 最初的目的就是显示文档,假设你想显示丰富的图文排版。尽管 iOS/Android 都有富文本组件。但比起 CSS 差太远了,因此在很是多 Native 应用中是不可避免要嵌 Web 的。ios

代码转换流

不一样平台下的官方语言不同,而且平台对官方语言的支持最好,这就致使相同的逻辑,咱们需要写多套代码。比方Android平台用Java。ios用oc或者swift。因而就有人想到了经过代码转换的方式来下降反复的工做量,这就是因此的代码转换流。
这样的方式尽管听起来不是很是靠谱。但它倒是成本和风险都最小的。因为代码转换后就可以用官方提供的各类工具了。和普通开发差异不大。而且转换后。可以利用原生的优势,这也可以下降兼容的问题。
眼下存在的几种代码转换方式:程序员

将 Java 转成 Objective-C

j2objc 能将 Java 代码转成 Objective-C。听说 Google 内部就是使用它来下降跨平台开发成本的。比方 Google Inbox 项目就号称经过它共用了 70% 的代码,效果很是显著。
可能有人会认为奇怪,为什么 Google 要专门开发一个帮助你们写 Objective-C 的工具?还有媒体说 Google 作了件好事。事实上吧,我认为 Google 这算盘打得不错。因为基本上重要的应用都会同一时候开发 Android 和 iOS 版本号,有了这个工具就意味着。你可以先开发 Android 版本号,而后再开发 iOS 版本号。web

。。objective-c


既然都有成功案例了,这个方法确实值得尝试,而且关键是会 Java 的人多啊,可以经过它来高速移植代码到 Objective-C 中。

将 Objective-C 转成 Java

除了有 Java 转成 Objective-C,还有 Objective-C 转成 Java 的方案,那就是 MyAppConverter,比起前面的 j2objc,这个工具更有野心。它还打算将 UI 部分也包括进来。从它已转换的列表中可以看到还有 UIKit、CoreGraphics 等组件,使得有些应用可以不改代码就能转成功,只是这点我并不看好,对于大部分应用来讲并不现实。


因为眼下是收费项目,我没有尝试过,对技术细节也不了解。因此这里不作评价。

将 Java 转成 C

Mono 提供了一个将 Java 代码转成 C# 的工具 Sharpen。只是彷佛用的人很少,Star 才 118,因此看起来不靠谱。
还有 JUniversal 这个工具可以将 Java 转成 C#,但眼下它并无公布公开版本号。因此详细状况还待了解,它的一个特点是自带了简单的跨平台库,里面包括文件处理、JSON、HTTP、OAuth 组件。可以基于它来开发可复用的业务逻辑。
比起转成 Objective-C 和 Java 的工具,转成 C# 的这两个工具看起来都很是不成熟。预计是用 Windows Phone 的人少。

XMLVM

除了前面提到的源代码到源代码的转换,还有 XMLVM 这样的不同凡响的方式。它首先将字节码转成一种基于 XML 的中间格式。而后再经过 XSL 来生成不一样语言,眼下支持生成 C、Objective-C、JavaScript、C#、Python 和 Java。
尽管基于一个中间字节码可以方便支持多语言。然而它也致使生成代码不可读,因为很是多语言中的语法糖会在字节码中被抹掉,这是不可逆的。如下是一个简单演示样例生成的 Objective-C 代码,看起来就像汇编:

XMLVM_ENTER_METHOD("org.xmlvm.tutorial.ios.helloworld.portrait.HelloWorld", "didFinishLaunchingWithOptions", "?

") XMLVMElem _r0; XMLVMElem _r1; XMLVMElem _r2; XMLVMElem _r3; XMLVMElem _r4; XMLVMElem _r5; XMLVMElem _r6; XMLVMElem _r7; _r5.o = me; _r6.o = n1; _r7.o = n2; _r4.i = 0; _r0.o = org_xmlvm_iphone_UIScreen_mainScreen__(); XMLVM_CHECK_NPE(0) _r0.o = org_xmlvm_iphone_UIScreen_getApplicationFrame__(_r0.o); _r1.o = __NEW_org_xmlvm_iphone_UIWindow(); XMLVM_CHECK_NPE(1) ...

终上所述,尽管代码转换这样的方式风险小。但我认为对于很是多小 APP 来讲共享不了多少代码,因为这类应用大多数环绕 UI 来开发的,大部分代码都和 UI 耦合,因此公共部分很少。其借鉴性意义不大。

编译流

编译流比代码转换流的代码转换更进一步,它直接将某个语言编译为普通平台下可以识别的二进制文件。採用这样的方式主要有如下特色:

优势

  • 可以重用一些实现很是复杂的代码。比方以前用 C++ 实现的游戏引擎,重写一遍成本过高
  • 编译后的代码反编译困难

缺点

  • 转换过于复杂,而且后期定位和改动成本会很是高
  • 编译后体积太大,尤为是支持 ARMv8 和 x86等CPU架构的时候

接下来,咱们经过不一样的语言来介绍这个流派下不一样的技术实现。

C++方案

因为眼下Android、iOS和Windows Phone都提供了对C++开发的支持。特别是C++ 在实现非界面部分,性能是很是高效的。

而假设C++ 要实现非界面部分。仍是比較有挑战的。这主要是因为Android 的界面绝大部分是 Java 实现。而在 iOS 和 Windows Phone下可以分别使用C++的超集Objective-C++和 C++/CX来开发。

那么要解决用C++开发Android界面,眼下主要有两种方案:

  • 经过 JNI 调用系统提供的 Java 方法
  • 本身画 UI

第一种方式尽管可行,但是代码冗余高。实现过于复杂。那另一种方式呢,比方 JUCE 和 QT就是本身用代码画的。

只是在Android 5下就悲剧了。很是多效果都没出来,比方按钮没有涟漪效果。根本缘由在于它是经过 Qt Quick Controls 的本身定义样式来模拟的。而不是使用系统UI组件。所以它享受不到系统升级本身主动带来的界面优化。


固然咱们可以使用OpenGL来绘制界面,因为EGL+OpenGL自己就是跨平台的。而且眼下大多数跨平台游戏底层都是这么作的。


既然可以基于 OpenGL 来开发跨平台游戏,可否用它来实现界面?固然是可行的。而且Android 4的界面就是基于OpenGL的。只是它并不是仅仅用 OpenGL 的 API。那样是不现实的。因为 OpenGL API 最初设计并不是为了画 2D 图形的,因此连画个圆形都没有直接的方法,所以Android 4中是经过Skia将路径转换为位置数组或纹理,而后再交给 OpenGL 渲染的。
然而直接使用OpenGL来作界面的绘制,代价是很是大的,而且眼下在各个平台下都会有良好的官方支持。

所以对于大多数应用来讲本身画UI是很是不划算的。

Xamarin

Xamarin 可以使用 C# 来开发 Android 及 iOS 应用,它是从 Mono 发展而来的,眼下看起来商业运做得不错,相关工具及文档都挺健全。
因为它在 iOS 下是以 AOT 的方式编译为二进制文件的。因此把它归到编译流来讨论。事实上它在 Android 是内嵌了 Mono 虚拟机 来实现的。所以需要装一个 17M 的执行环境。


在 UI 方面,它可以经过调用系统 API 来使用系统内置的界面组件,或者基于 Xamarin.Forms 开发定制要求不高的跨平台 UI。


对于熟悉 C# 的团队来讲,这还真是一个看起来很是不错的,但这样的方案最大的问题就是相关资料不足。遇到问题很是可能搜不到解决方式,只是因为时间关系我并无细致研究,推荐看看这篇文章,当中谈到它的优缺点是:

优势

  • 开发 app 所需的基本功能所有都有
  • 有商业支持,而且这个项目对 Windows Phone 很是有利。微软会大力支持

缺点

  • 假设深刻后会发现功能缺失,尤为是定制 UI,因为未开源使得遇到问题时不知道怎样修复
  • Xamarin 自己有些 Bug
  • 相关资源太少,没有原平生台那么多第三方库
  • Xamarin studio 比起 Xcode 和 Android Studio 在功能上还有很是大差距

Objective-C 编译为 Windows Phone

微软知道本身的 Windows Phone 太非主流,因此很是懂事地推出了将 Objective-C 项目编译到 Windows Phone 上执行的工具,眼下这个工具的相关资料很是少,鉴于 Visual Studio 支持 Clang,因此极有多是使用 Clang 的前端来编译。这样最大的优势是之后支持 Swift 会很是方便。所以我归到编译流。

Swift – Apportable/Silver

apportable 可以直接将 Swift/Objective-C 编译为机器码,但它官网的成功案例所有都是游戏,因此用这个来作 APP 感受很是不靠谱。
因此后来它又推出了 Tengu 这个专门针对 APP 开发的工具。它的比起以前的方案更灵活些,本质上有点类似 C++ 公共库的方案,仅仅只是语言变成了 Swift/Objective-C,使用 Swift/Objective-C 来编译生成跨平台的 SO 文件,提供给 Android 调用。
还有一个类似的是 Silver,只是眼下没正式公布,它不只支持 Swift,还支持 C# 和自创的 Oxygene 语言(看起来像 Pascal),在界面方面它还有个跨平台非 UI 库 Sugar,然而眼下 Star 数仅仅有 17,太非主流了,因此不值得研究它。

Go

Go作为后端服务开发语言,专门针对多处理器系统应用程序的编程进行了优化。使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。

Go 从 1.4 版本号開始支持开发Android应用(并在1.5 版本号支持iOS)。

尽管能同一时候支持Android和ios。但是眼下可用的api很是少,Go仍然专一于后端语言开发。
Android的View层全然是基于Java写的,要想用Go来写UI不可避免要调用Java 代码,而这方面Go尚未简便的方式,眼下Go调用外部代码仅仅能使用cgo。经过cgo再调用jni,这就不可避免的需要写很是多的中间件。

而且 cgo 的实现自己就对性能有损失,除了各类无关函数的调用,它还会锁定一个 Go 的系统线程。这会影响其余 gorountine 的执行,假设同一时候执行太多外部调用。甚至会致使所有 gorountine 等待
因此使用Go开发跨平台移动端应用眼下不靠谱。

虚拟机流

除了编译为不一样平台下的二进制文件。还有还有一种常见作法是经过虚拟机来支持跨平台执行。比方 JavaScript 和 Lua 都是天生的内嵌语言,因此在这个流派中很是多方案都使用了这两个语言。
只是虚拟机流会遇到两个问题:一个是性能损耗。还有一个是虚拟机自己也会占不小的体积。

Java 系

说到跨平台虚拟机你们都会想到 Java,因为这个语言一開始就是为了跨平台设计的,Sun 的 J2ME 早在 1998 年就有了,在 iPhone 出来前的手机上,很是多小游戏都是基于 J2ME 开发的。这个项目至今还活着。能执行在 Raspberry Pi 上。
前面提到微软提供了将 Objective-C 编译在 Windows Phone 上执行的工具,在对 Android 的支持上我没找到的详细资料,因此就临时认为它是虚拟机的方式,从 Astoria 项目的介绍上看它作得很是无缺,不只能支持 NDK 中的 C++,还实现了 Java 的 debug 接口,使得可以直接用 Android Studio 等 IDE 来调试。整个开发体验和在 Android 手机上差点儿没差异。
另外 BlackBerry 10 也是经过内嵌虚拟机来支持直接执行 Android 应用。只是听说比較卡。


只是前面提到 C# 和 Java 在 iOS 端的方案都是经过 AOT 的方式实现的。眼下还没见到有 Java 虚拟机的方案,我想主要缘由是 iOS 的限制。普通 app 不能调用 mmap、mprotect。因此没法使用 JIT 来优化性能,假设 iOS 开放。也许哪天有人开发一个像微软那样能直接在 iOS 上执行 Android 应用的虚拟机,就不需要跨平台开发了。你们仅仅需要学 Android 开发就够了。

Titanium/Hyperloop

Titanium 应该很多人听过,它和 PhoneGap 差点儿是同一时候期的著名跨平台方案,和 PhoneGap 最大的差异是:它的界面没有使用 HTML/CSS,而是本身设计了一套基于 XML 的 UI 框架 Alloy,代码类似如下这个样子:

app/styles/index.tss
 ".container": {
 backgroundColor:"white"
 },
 // This is applied to all Labels in the view
 "Label": {
 width: Ti.UI.SIZE,
 height: Ti.UI.SIZE,
 color: "#000", // black
 transform: Alloy.Globals.rotateLeft // value is defined in the alloy.js file
 },
 // This is only applied to an element with the id attribute assigned to "label"
 "#label": {
 color: "#999" /* gray */
 }

前面咱们说过因为 CSS 的过于灵活拖累了浏览器的性能,那是否本身创建一套 UI 机制会更靠谱呢?尽管这么作对性能确实有优势。然而它又带来了学习成本问题,作简单的界面问题不大。一旦要深刻定制开发就会发现相关资料太少,因此仍是不靠谱。

Titanium 还提供了一套跨平台的 API 来方便调用,这么作是它的优势更是缺点。尤为是如下三个问题:

API 有限,因为这是由 Titanium 提供的。它确定会比官方 API 少且有延迟,Titanium 是确定跟只是来的
相关资料及社区有限。比起 Android/iOS 差远了,遇到问题都不知道去哪找答案
缺少第三方库,第三方库确定不会专门为 Titanium 提供一个版本号,因此不管用什么都得本身封装
Titanium 也意识到了这个问题,因此眼下在开发下一代的解决方式 Hyperloop,它可以将 JavaScript 编译为原生代码。这样的优势是调用原生 API 会比較方便,比方它的 iOS 是这样写的:

@import("UIKit");
 @import("CoreGraphics");
 var view = new UIView();
 view.frame = CGRectMake(0, 0, 100, 100);

这个方法和以前的说的Xamarin一模一样。也是将JavaScript将翻译为Objective-C而后由官方的方案执行。只是这项目开发都快三年了,但至今仍然是试验阶段,显然有点不靠谱。

NativeScript

以前说到 Titanium 本身定义 API 带来的各类问题,因而就有人换了个思路,比方前段时间推出的 NativeScript,它的方法说白了就是用工具来本身主动生成 wrapper API。和系统 API 保持一致。
有了这个本身主动生成 wrapper 的工具,它就能方便基于系统 API 来开发跨平台组件。以简单的 Button 为例,源代码在 cross-platform-modules/ui/button 中,它在 Android 下是这样实现的:

export class Button extends common.Button {
 private _android: android.widget.Button;
 private _isPressed: boolean;
public _createUI() {
 var that = new WeakRef(this);
 this._android = new android.widget.Button(this._context);
 this._android.setOnClickListener(new android.view.View.OnClickListener({
 get owner() {
 return that.get();
 },
 onClick: function (v) {
 if (this.owner) {
 this.owner._emit(common.knownEvents.tap);
 }
 }
 }));
 }
 }

在 iOS 下是这样实现的:

export class Button extends common.Button {
 private _ios: UIButton;
 private _tapHandler: NSObject;
 private _stateChangedHandler: stateChanged.ControlStateChangeListener;
constructor() { super(); this._ios = UIButton.buttonWithType(UIButtonType.UIButtonTypeSystem);
this._tapHandler = TapHandlerImpl.new().initWithOwner(this);
 this._ios.addTargetActionForControlEvents(this._tapHandler, "tap", UIControlEvents.UIControlEventTouchUpInside);
this._stateChangedHandler = new stateChanged.ControlStateChangeListener(this._ios, (s: string) => { this._goToVisualState(s); }); }
get ios(): UIButton {
 return this._ios;
 }
 }

可以看到使用方法和官方 SDK 中的调用方式是同样的,仅仅只是语言换成了 JavaScript。而且写法看起来比較诡异罢了,风格类似前面的 Hyperloop 类似,因此也相同会有语法转换的问题。


这么作最大的优势就是能完整支持所有系统 API,对于第三方库也能很是好支持,但它眼下最大缺点是生成的文件体积过大。即使什么都不作。生成的 apk 文件也有 8.4 MB,因为它将所有 API binding 都生成了,而且这也致使在 Android 下首次打开速度很是慢。
从底层实现上看。NativeScript 在 Android 下内嵌了 V8,而在 iOS 下内嵌了本身编译的 JavaScriptCore(这意味着没有 JIT 优化,详细缘由前面提到了)。这样的优势是能调用更底层的 API。也避免了不一样操做系统版本号下 JS 引擎不一致带来的问题,但后果是生成文件的体积变大和在 iOS 下性能不如 WKWebView。
WKWebView 是基于多进程实现的,它在 iOS 的白名单中,因此能支持 JIT。它的使用体验很是不错,作到了一键编译执行。而且还有 MVVM 的支持,能进行数据双向绑定。
在我看来 NativeScript 和 Titanium 都有个很是大的缺点,那就是排它性太强,假设你要用这两个方案,就得完整基于它们进行开发,不能在某些 View 下进行尝试。也不支持直接嵌入第三方 View,有没有方案能很是好地解决这两个问题?有。那就是咱们接下来要介绍的 React Native。

React Native

React Native是由FaceBook开源的基于JavaScript和React搭建的一套跨平台开发框架。而在设计之初,React Native採用就是在不一样平台下使用平台自带的UI组件。

觉得它採用JavaScript和React来开发,因此得到了很多前端程序员的青睐。


有人说。React Native採用js等前端技术是回归H5,但事实上 React Native和Web 扯不上太多关系。ReactNative尽管借鉴了CSS中的Flexbox、navigator、XMLHttpRequest 等Api的写法,但是大部分仍是经过原生的组件或者本身封装的组件来开发的。就像FaceBooK的内部软件Facebook Groups。iOS版本号很是大一部分基于React Native开发。当中用到了很多内部通用组件。
React Native相比传统Objective-C和UIView,学习成本更低了。熟悉JavaScript 的开发人员可以在半天写个使用标准UI界面,而且用XML+CSS 画界面也远比 UIView 中用 Frame 进行手工布局更易读。

在加上React Native师出名门,截止眼下,React Native已更新到0.4.2版本号,而且逐步趋于稳定。

因为其更加接近原生的体验。国内一些大厂纷纷增长,诸如阿里、腾讯、美团等纷纷開始本身app想React Native的改造。

React Native代码:

@implementation ArticleComponent
+ (instancetype)newWithArticle:(ArticleModel *)article
 {
 return [super newWithComponent:
 [CKStackLayoutComponent
 newWithView:{}
 size:{}
 style:{
 .direction = CKStackLayoutDirectionVertical,
 }
 children:{
 {[HeaderComponent newWithArticle:article]},
 {[MessageComponent newWithMessage:article.message]},
 {[FooterComponent newWithFooter:article.footer]},
 }];
 }
 ...

很是多人认为跨平台历来都不靠谱。但事实上是有的,那就是 Web,这个历史上最成功的样例。就像当年web挤掉pc成为互联网的主流同样,将来的互联网必将是web的时代。

相关文章
相关标签/搜索