转:  http://www.infoq.com/cn/articles/hybrid-app

编者按:InfoQ开设新栏目“品味书香”,精选技术书籍的精彩章节,以及分享看完书留下的思考和收获,欢迎大家关注。本文节选自徐凯著《跨终端Web》第八章“Hybrid App”,主要讲述Hybrid App的发展现状以及技术实现,最后还介绍了两种主流Hybrid开发框架PhoneGap/Cordova和Titanium。


Native App(以下简称Native)和Mobile Web(以下简称Web)二者混合开发的产物被称为Hybrid App(以下简称Hybrid)。Hybrid并不是什么新概念,最早可以追溯到Symbian时代,直到iOS和Android出现之后才充分展现出价值。

Hybrid简史

1. 背景

Hybrid既利用了Native App丰富的设备API(Device API),又能拥有Mobile Web的跨平台、高效开发、快速发布的能力,对于相当庞大的应用场景而言都是适用的。

Hybrid优势在于:

  • 跨平台

    Web内容可以做到开发一次,所有平台生效,诸多产品需要这种能力。

  • 快速发布

    iOS平台,Apple Store平均审核周期1~2周不等,甚至更长,产品的发布周期从2周到1月,这对需要快速发布的产品而言难以接受。

    Android平台,应用商店众多,发布过程烦琐。虽然可以应用内升级,但是带来的问题是新App需要通过应用商店,此外APK体积庞大,2G/3G环境下体验差。

  • 高效开发

    Web开发经过20年的发展,已经将结构(HTML)、表现(CSS)、行为(JavaScript)3部分很好地分离开,在分工协作、开发效率上会具明显优势。

  • 丰富的Device API

    Web(HTML5)强调通用性,受限于标准和浏览器实现,许多有用的系统功能未能得到支持(或部分支持)。而Native最大的优势在于设备API的调用能力,只要桥接Native和Web,Web也就能够拥有这种能力。

Hybrid劣势表现为:

  1. CPU/GPU密集类应用目前看更适合Native,例如极品飞车这样的游戏。这种劣势是在不断弱化的,正如 “CSS Transform 3D”引入GPU大大缓解了Web动画不流畅的问题。
  2. 静态资源从服务器端加载导致的UI展示延迟问题。这个问题可以通过Native拦截WebView通信加载已打包的公共库来缓解。

2. 简史

  • 雏形

    雏形阶段大致为:

    • Symbian V3/5时代已经有Hybrid雏形。
    • iOS最初的App都是由Objective-C编写而成的,受限应用商店的发布周期,内容经常变化的部分开始通过使用内置浏览器控件(WebView)加载服务端页面来实现。
    • Android出现并流行之后,可以将更多的App功能通过Hybrid来实现,这样在不同平台上就可以只维护一个版本。
  • 发展

    “跨平台”成了Hybrid最大的卖点,以PhoneGap[1]为首的Hybrid框架陆续出现,带来了诸多改变。

    • 访问设备功能。

      • Web(HTML5)不支持的功能可以让Native实现,再通过Native和Web之间通信,通过这种方式可以让Web获得和Native相同的设备API调用能力,这是PhoneGap这类Hybrid框架的基本工作原理。
      • 与此同时,将Web代码转为Native的Hybrid框架(如Tianium[2])也出现了。
    • PhoneGap子项目weinre是一种远程调试工具,极大地缓解了Hybrid难于调试的问题,进一步促进了Hybrid的发展。
    • Hybrid框架提供了应用打包功能,开发者可以完全使用HTML、CSS、JavaScript开发Native App。
  • 成熟

    随着PhoneGap这类Hybrid框架在全球的流行,一些问题暴露了出来,也正是这些问题的解决,让Hybrid走向成熟。

    • 开发体验提升。

      • weinre这类调试工具仍属于插件性质,诸如“网络”、“本地资源”等高级调试功能无法支持,WebView的原生调试需求越来越强烈。
      • iOS 6.0+已经支持原生的远程调试[3]。
      • Chrome for Android在原生远程调试上处于领先地位[4]。
      • 从Android 4.4开始,WebView也支持原生的远程调试[5]。
    • 提升WebView性能的呼声日益增强。
    • 某些追求极致性能的功能转由Native实现,如转场(页面间切换)动画。
    • 静态资源本地化是理想状态,其他场景下Native拦截WebView的请求,并让公共资源重定向到App内置资源,同样能实现为Web提速。

3. 现状

以上便是Hybrid的发展概述,从国内最新的资料可以看出,Hybrid的趋势也是非常明显的。从图8-1可以看到越来越多的开发者决定使用Hybrid(跨平台技术),最近两年的总量已经有54%;而接近60%的开发者在Hybrid的技术方案上选择了PhoneGap。

图8-1 Hybrid在国内的发展情况[6]

  1. 在受访的2309个Mobile开发者中,到2013年8月为止完全使用Native开发的只有8%,而剩余的92%都可以被认为使用的是Hybrid,如图8-2所示。

    图8-2 Hybrid使用情况

  2. App的跨平台特性成为一个重要的考虑,如图8-3所示。

    图8-3 跨平台特性受关注

图8-4显示了Hybrid惊人的增长速度:2013年无论是开发中、已发布的Hybrid(或HTML App)均相比于2012年出现了超过125%~400%的增长率[8]。

图8-4 Hybrid增长迅猛[9]

Hybrid技术

无论Android还是iOS,实现一个最简单的Hybrid App只需要几行代码:实例化WebView、加载页面,之后便是页面自身的代码。要想实现更为复杂的、完整的Hybrid还需要不少知识。

  1. Mobile Web开发基础:HTML、CSS、JavaScript。
  2. Native App开发基础:Android、iOS。
  3. Native与Web双向通信机制。

Mobile Web开发基础可以参考本书第2章,Native App开发基础已经超出本书的讨论范围,同样有很多可选择的书籍,本节来讲剩余的第3个问题 “Native与Web双向通信机制”。

1. Native调用Web

无论Android还是iOS ,Native调用Web(JavaScript) 都有很好的原生支持,如代码8-1和代码8-2所示。Android中的调用方式如下,其中webView是Webview的实例。

代码8-1 Android调用JavaScript

webView.loadUrl("javascript:(function(){ alert(‘ok’); })()”);

iOS中的调用方式如下,其中webView是UIWebview的实例。

代码8-2 iOS调用JavaScript

[webView stringByEvaluatingJavaScriptFromString: @"alert('ok')" ];

2. Web调用Native

“Native调用Web”本质上是JavaScript脚本的动态执行,在“Web调用Native”的场景下由于目前Native语言(Java和Objective-C)不容易像JavaScript那样便于动态执行,所以需要另辟蹊径。

2.1 Android

Android上常见的方式有3种。

  1. 重写WebViewClient.shouldOverrideUrlLoading(如代码8-3所示)。

    代码8-3 重写WebViewClient.shouldOverrideUrlLoading

    webView.setWebViewClient(new WebViewClient(){
    @Override
    public boolean shouldOverrideUrlLoading (WebView view, String url){
    // TODO解析URL并触发Native代码
    return true;
    }
    });

    当页面内的URL发生变化时,如点击链接、执行JavaScript(如location.href=”http://”)等均会触发WebViewClient.shouldOverrideUrlLoading,通过将Web调用Native的数据封装在URL,再由Native解析数据并执行响应Native方法。

  2. 重写WebChromeClient.onJsPrompt,或onJsConfirm,或onJsAlert,以WebChromeClient.onJsPrompt为例,如代码8-4所示。

    代码8-4 重写WebChromeClient.onJsPrompt

    	webView.setWebChromeClient(new WebChromeClient() {
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    // TODO解析message并触发Native代码
    result.confirm("");
    return true;
    }
    });

    当执行“window.prompt(“{}”)”这样的JavaScript代码时,将会触发WebChromeClient.onJsPrompt。

  3. WebView.addJavascriptInterface,这种方式和前两种都不同,通过将Java Object(A) 映射为JavaScript Object(B),从而调用B.func1时将会自动触发A.func1,通过这种原生的方式实现了 “Web调用Native”,如代码8-5所示。

    代码8-5 WebView.addJavascriptInterface

    	webView.addJavascriptInterface(new Object() {
    public void func1() {
    } public void func2() {
    }
    }, "webViewObj");

以上3种方式,最常用的是方式2;方式2相比方式1有内置的队列支持,不会出现高频访问数据丢失的情况;方式3是Android原生方式,但是不如前两种方式灵活。

2.2 iOS

iOS中可用的方式类似Android中的WebViewClient.shouldOverrideUrlLoading, 通过监控WebView的URL变化实现Web调用Native,如代码8-6所示。

代码8-6 shouldStartLoadWithRequest

- (BOOL)webView:(UIWebView *) webView shouldStartLoadWithRequest:
(NSURLRequest *)request
navigationType: (UIWebViewNavigationType)navigationType { }

3. Bridge

有了前两节的知识,可以实现一个通用模块(Bridge)来维护不同平台上的“Web与Native双向通信机制”功能。如图8-5所示为Web调用Native的Bridge时序图。

图8-5 Web调用Native的Bridge时序图

Web调用Native的实现原理如下。

  1. Web端调用Bridge.callByJS({name:’func1’, callback: function(){}, param:{}}),由Bridge根据特定“Web调用Native”方式通知Native执行相应方法(图8-5中的“func1”)。
  2. Native执行完毕后通过“Native调用Web”的方式调用Bridge. callByNative({token: ‘t1234’ })。如图8-6所示为Native调用Web时的Bridge时序图。
  3. 其中JavaScript回调函数会映射为字符串型的token,通过这个方式来保证最终触发JavaScript的回调函数(包括匿名函数和通过闭包实现的私有函数)。

图8-6 Native调用Web时的Bridge时序图

可以看到,Bridge实现“Native调用Web”是类似的。

  1. Native端调用Bridge.callByNative({token:’t1234’, script: ‘//todo’}),由Bridge根据特定“Native调用Web”方式通知Web执行相应脚本。
  2. Web执行完毕后通过“Web调用Native”的方式调用Bridge. callByJS({token: ‘t1234’ })。
  3. 如果Bridge.callByNative的script中执行了异步操作,需要在script主动调用Bridge.callByJS,并且不需要传token参数。

笔者已经在Android上实现了完整的Bridge[10],Bridge由JavaScript实现可以运行在Android和iOS的WebView中,同时也非常容易扩展到Windows Phone等新平台,如代码8-7所示。

  1. Bridge代码在产品环境下使用时请设置DEBUG = false。
  2. 避免在iOS下快速变化URL时造成的数据丢失,可以考虑使用队列机制缓存命令。
  3. 扩展至Windows Phone等平台时JavaScript部分只需要扩展invoke,Native代码可以参考Android的实现。
  4. 目前Bridge单次通信后会删除回调函数,如果需要多次调用缓存的回调函数(如连续监控传感器数据),可以扩展Bridge.callByNative。

代码8-7 bridge.js

(function(window) {
var DEBUG = true;
var callbacks = {};
var guid = 0;
var ua = navigator.userAgent;
// TODO精确性待改进
var ANDROID = /android/i.test(ua);
var IOS = /iphone|ipad/i.test(ua);
var WP = /windows phone/i.test(ua);
//ANDROID = 0; IOS = 1; /**
* 方便在各个平台中看到完整的log
*/
function log() {
if (DEBUG) {
console.log.call(console, Array.prototype.join.call(arguments, ' '));
}
} /**
* 平台相关的Web与Native单向通信方法
*/
function invoke(cmd) {
log('invoke', cmd);
if (ANDROID) {
prompt(cmd);
}
else if (IOS) {
location.href = 'bridge://' + cmd;
}
else if (WP) {
// TODO ...
}
} var Bridge = {
callByJS: function(opt) {
log('callByJS', JSON.stringify(opt));
var input = {};
input.name = opt.name;
input.token = ++guid;
input.param = opt.param || {};
callbacks[input.token] = opt.callback; invoke(JSON.stringify(input));
},
callByNative: function(opt) {
log('callByNative', JSON.stringify(opt));
var callback = callbacks[opt.token];
var ret = opt.ret || {};
var script = opt.script || ''; // Native主动调用Web
if (script) {
log('callByNative script', script);
try {
invoke(JSON.stringify({
token: opt.token,
ret: eval(script)
}));
} catch (e) {
console.error(e);
}
}
// Web主动调用Native,Native被动响应
else if (callback) {
callback(ret);
try {
delete callback;
log(callbacks);
} catch (e) {
console.error(e);
}
} }
}; window.Bridge = Bridge;
window.__log = log;
})(window);

Hybrid框架

目前一个Hybrid框架通常提供以下功能。

  1. Device API:封装Native的功能,跨平台提供一致的Device API。
  2. App打包:将HTML5编写的代码打包为App(Titanium会转换代码)。

PhoneGap几乎成了Hybrid的代名词,Titanium和PhoneGap的设计理念差异较大,图8-7形象地展示了PhoneGap和Titanium的组成部分。

图8-7 Hybrid框架[11]

1. PhoneGap

1.1 PhoneGap和Cordova

PhoneGap开发商Notibi 2010年将PhoneGap代码贡献给Apache软件基金(ASF),PhoneGap核心引擎成为新的开源项目Cordova,同时PhoneGap成了Cordova的一个发行版本[12]。2011年10月,Notibi被Adobe收购[13],但没有影响到PhoneGap和Cordova的开源性质。

1.2 原理

written once,run everywhere

如引文所述“一处编写,多处运行”,PhoneGap主要的功能为:

  1. 提供Hybrid API,可由JavaScript直接调用诸如加速度、摄像头、指南针、GPS、联系人等系统级API,完整的API列表请访问PhoneGap API Reference。
  2. 使用Web(HTML、CSS、JavaScript)开发的内容经过PhoneGap编译打包为各个平台的Native App,如图8-8所示。

图8-8 PhoneGap编译打包功能

1.3 经典案例

来自PhoneGap Showcase[14]和其他数据源的资料显示:

  • Facebook Mobile SDK[15]和SalesForce Mobile SDK[16]均是基于Cordova的分支开发的。
  • Facebook客户端中Web代码超过90%[17]。
  • LinkedIn iPad客户端中Web代码甚至超过95%。
  • Wikipedia更是直接用PhoneGap开发了自己的iOS/Android Hybrid App[18],并将代码在GitHub上开源 [19]。

2. Titanium

Titanium设计思路和PhoneGap有很大不同,Titanium目的为移动开发提供一种跨平台的JavaScript运行时环境和API。

2.1 设计思路

Titanium设计的核心思路如下。

  1. 有一套核心的移动开发API,它们可以跨平台进行规范,这些方面的重点应放在代码重用上。
  2. 有针对特定平台的API、用户界面约定以及功能特性,开发者在针对该特定平台从事开发时采用,应该有针对特定平台的代码,以便这些用例提供最佳的用户体验。

Titanium从设计理念上不追求“written once, run everywhere”,这是它的缺点,但同时它追求平台差异的更佳的用户体验,因而也受到一部分用户的追捧。Titanium的另一个缺陷是插件难于扩展,要想支持新平台则更加困难。

2.2 工作流程

工作流程如下。Titanium工作流如图8-9所示。

  1. 使用Titanium SDK在自带的IDE(ALLOY)中开发。
  2. 使用工具编译为平台相关的App。

图8-9 Titanium工作流

书籍简介

移动互联网不可阻挡地进入了我们的生活。作者将自己在百度和天猫期间的跨终端Web的开发实践转化为书中的技术方案和实现,呈现给各位读者。第1章提出了跨终端Web的概念以及实现跨终端Web的多重途径,第2章主要介绍Mobile Web的技术基础,第3~7章是全书的核心,按照开发流程组织逐步讲解了实现跨终端Web所需要的各类技术基础设施,第8章主要介绍了Hybrid App的发展历程、实现细节以及成熟的框架,第9章介绍的跨终端存储方案(Storage)是作者曾经的冠军作品,第10章完整介绍了如何通过脚本录制和回放来实现跨终端动作同步。

《跨终端 Web》讲解深入浅出,通畅易懂,适合有一定PC Web基础,希望迅速了解Mobile Web,致力于PC和Mobile Web技术融合的读者。

作者简介

鬼道(原名徐凯),2011年毕业于同济大学计算机系,模式识别方向硕士研究生。曾就职百度,现为天猫前端通用组技术Leader。本书源于2013年7月在D2上的主题分享“移动优先的跨终端Web”,2013年11月在W3CTECH 2013做了第二次分享。


  • [1] PhoneGap是主流Hybrid框架。
  • [2] http://www.appcelerator.com/titanium/
  • [3] http://www.36kr.com/p/117773.html
  • [4] http://www.html5rocks.com/en/tutorials/developertools/mobile/
  • [5] https://developers.google.com/chrome-developer-tools/docs/remote-debugging#debugging-webviews
  • [6] 摘自《友盟2013上半年报告》2013.09。
  • [7] http://www.kendoui.com/surveys/html5-native-debate-is-over.aspx
  • [8] http://www.businessinsider.com/html5-vs-native-apps-for-mobile-2013-6?op=1
  • [9] 此图来自 http://www.businessinsider.com/html5-vs-native-apps-for-mobile-2013-6?op=1。
  • [10] http://luics.github.io/cew/Bridge.zip
  • [11] 此图来自http://www.businessinsider.com/html5-vs-native-apps-for-mobile-2013-6?op=1。
  • [12] http://phonegap.com/2012/03/19/phonegap-cordova-and-what%E2%80%99s-in-a-name/
  • [13] http://www.adobe.com/aboutadobe/pressroom/pressreleases/201110/AdobeAcquiresNitobi.html
  • [14] http://phonegap.com/app/
  • [15] https://developers.facebook.com/docs/guides/mobile/
  • [16] http://wiki.developerforce.com/page/Mobile_SDK
  • [17] http://www.geekpark.net/read/view/164456
  • [18] http://itunes.apple.com/us/app/wikipedia-mobile/id324715238?mt=8
  • [19] https://github.com/wikimedia/WikipediaMobile

转: 跨终端Web之Hybrid App的更多相关文章

  1. 跨终端Web之Hybrid App

    Native App(以下简称Native)和Mobile Web(以下简称Web)二者混合开发的产物被称为Hybrid App(以下简称Hybrid).Hybrid并不是什么新概念,最早可以追溯到S ...

  2. 单纯觉得是篇好文——跨终端Web之Hybrid App

    [reference]http://www.infoq.com/cn/articles/hybrid-app#theCommentsSection 编者按:InfoQ开设新栏目“品味书香”,精选技术书 ...

  3. 跨终端 Web

    跨终端 Web(移动优先|响应式|HTML5|Hybrid|桌面+移动应用|一线前端负责人联袂推荐) 徐凯  著   ISBN 978-7-121-23345-6 2014年6月出版 定价:55.00 ...

  4. 初识跨终端Web

    近期试读了<跨终端Web>这本书的部分章节,既为了拿到书,也为了记录下读后的收获的东西,这会是个非常好的习惯吧. 标题为"初识跨终端Web".对我来说最贴切了,在此之前 ...

  5. 跨终端Web

    1.终端vs设备 H5页面运行在同一设备的不同终端下. (1)Web浏览器. (2)微信.QQ浏览器. (3)移动App的Webview. (4)TV机顶盒. 2.跨终端的实现方式 (1)响应式 存在 ...

  6. 《跨终端Web》读书笔记

    跨终端的Web成为了趋势,而这本书就是讲了在这种趋势下进行开发的常见问题及其解决方案,可能是限于篇幅,每个方面都没有展开细说,但这是这样让本书干货满满,几乎没有一句废话. 下面是一些笔记. Web的本 ...

  7. 浅谈移动优先的跨终端Web 解决方案

    1.基准 我们定义测试基准和开发基准,也就是说我们定义我们在哪些浏览器上去进行调试. 左侧图主要是定义PC上的基准,其中A级项目中必须支持,B级可选,C级观察. 2.检测 主要是终端检测 这是一张架构 ...

  8. [已读]跨终端web

    13年去听阿里技术嘉年华,鬼道分享了<移动优先前端产品的探索>.今年我买这本书,事实上是被高大上的目录吸引→ → 买来后发现,嘿,似曾相识啊,但还是老老实实得花一下午把书翻了一遍.翻完之后 ...

  9. Hybrid APP混合开发的一些经验和总结

    http://www.cnblogs.com/kingplus/p/5588339.html 写在前面: 由于业务需要,接触到一个Hybrid APP混合开发的项目.当时是第一次接触混合开发,有一些经 ...

随机推荐

  1. HTTP 错误 405.0 - Method Not Allowed

    如果A页面通过表单(form)向B页面传递参数,而B页面是以“.htm or .html ”为扩展名的话,通过IIS解析会出现“HTTP 错误 405 -禁止访问资源”错误的提示. 原因:IIS解析文 ...

  2. 窥探EasyMock(1)基础使用篇

    EasyMock的应用分为5步: 1. 使用 EasyMock 生成 Mock 对象: SomeInterface mockObj = createMock(SomeInterface.class); ...

  3. 表单input按钮在各浏览器之间的兼容性

    从网上看了这篇关于表单input按钮的浏览器兼容性问题,总结的还不错,所以copy下来学习下. input按钮在各个浏览器之间的兼容性问题,看下边这段代码: input.item { backgrou ...

  4. Js制作点击输入框时默认文字消失的效果

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期 2014-02-17) 为了提高用户体验和易用度,一些设计师会对网页中用户经常用的东西进行优化,比如输入框.一般的输入框是怎样优化的呢 ...

  5. Codeforces Round #290 (Div. 2) B. Fox And Two Dots dfs

    B. Fox And Two Dots 题目连接: http://codeforces.com/contest/510/problem/B Description Fox Ciel is playin ...

  6. C#窗体钉在桌面、置底、嵌入桌面的办法

    想做一个桌面时钟,钉在桌面上不影响正常使用,只在看桌面的时候显示. 从网上多方寻找找到这么个代码,但是还是有不方便的地方,大家探讨一下. 这个程序在使用“显示桌面”的时候还可以显示,将程序的Form1 ...

  7. android一些系统相关的东西

    添加快捷方式和删除快捷方式: private void addShortcut() { Intent shortcut = new Intent( "com.android.launcher ...

  8. Vs2008几个快捷键

    CTRL+M 收缩 格式化cs代码:Ctrl+k+f    格式化aspx代码:Ctrl+k+d 5. 怎样快速切换不同的窗口? Ctrl+Tab   7. 怎样快速添加代码段? 输入prop然后按两 ...

  9. Trie 树 及Java实现

    来源于英文“retrieval”.   Trie树就是字符树,其核心思想就是空间换时间. 举个简单的例子.   给你100000个长度不超过10的单词.对于每一个单词,我们要判断他出没出现过,如果出现 ...

  10. MySQL优化---DBA对MySQL优化的一些总结

      非原创, 来自梦嘉朋友, 非常好的总结, 一起学习. ------------------------------------------------- 1. 要确保有足够的内存数据库能够高效的运 ...