【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

跨终端 Web 之 Hybrid App

  • 2015-05-26
  • 本文字数:7368 字

    阅读完需:约 24 分钟

编者按: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

复制代码
functionwindow{
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 invokecmd{
log('invoke', cmd);
if (ANDROID) {
prompt(cmd);
}
else if (IOS) {
location.href = 'bridge://' + cmd;
}
else if (WP) {
// TODO ...
}
}
var Bridge = {
callByJS: functionopt{
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: functionopt{
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 做了第二次分享。


2015-05-26 21:508574

评论

发布
暂无评论
发现更多内容

解读科学计算助力行业高质量发展|2023开放原子全球开源峰会科学智能分论坛即将启幕

开放原子开源基金会

人工智能 开源 开放原子 科学智能

WICC · 出海嘉年华倒计时!精彩不容错过,「指南」一手掌握

融云 RongCloud

社交 融云 泛娱乐 出海 wicc

1 行代码开启「密钥检测」,给敏感数据加上防护锁

极狐GitLab

DevOps 安全 DevSecOps 安全左移 密钥检测

为什么 AIGC 和大模型创业者都在安利向量数据库?

Zilliz

Milvus AIGC 向量数据库 zillizcloud

开源数据库迎来技术创新拐点|2023开放原子全球开源峰会开源数据库分论坛即将启幕

开放原子开源基金会

数据库 开源 开放原子

软件测试/测试开发丨接口测试实战学习笔记

测试人

程序员 软件测试 自动化测试 接口测试 测试开发

一文回顾 Boundless Hackathon at Stanford 首期 Workshop

大瞿科技

得物App万米高空WiFi拦截记

得物技术

App wifi 得物 拦截

单卡轻松打造 ChatGPT 竞争者“原驼”,QLoRA 革新大语言模型微调技术

Zilliz

openai AIGC Towhee ChatGPT

多数据中心助力中企出海全球化经营

用友BIP

中企出海

wireshark分析tcp传输之文件上传速率问题

蓝胖子的编程梦

TCP 网络 Wireshark tcpdump 抓包

Why Docker? Why not?

K

Docker 镜像 PaaS #云原生

数字化转型应该如何去做?(技术篇)

数字随行

数字化转型

开源教育与人才|2023开放原子全球开源峰会开源教育和人才分论坛即将启幕

开放原子开源基金会

开源 开放原子 教育与人才

通义千问预体验,如何让 AI 模型应用“奔跑”在函数计算上?

阿里巴巴云原生

阿里云 云原生 函数计算

Authing 结合 APISIX 实现统一可配置 API 权限网关(快速启动版)

Authing

API APISIX APISIX 网关 API 接口

2023数字政府高质量发展论坛在京召开

信通院IOMM数字化转型团队

数字化转型 数字政府 IOMM 政府数字化转型

项目汇报的正确打开方式

老张

汇报 向上管理

启用Windows防火墙后,FTP传输非常慢

镭速

Web3 游戏的用户留存的挑战与机遇:从经济模型与游戏设计谈起

Footprint Analytics

区块链游戏 web3 web3游戏

瑞云科技CTO赵志杰出席广州广告数字创意峰会并发表演讲

3DCAT实时渲染

元宇宙 实时云渲染 云3D渲染

SDK轻量化,降低日均耗电量和日均流量

MobTech袤博科技

小小机械臂 带动产业自动化

说山水

2023-06-01:讲一讲Redis常见数据结构以及使用场景。

福大大架构师每日一题

redis 福大大

Java 致命错误: 在类路径或引导类路径中找不到程序包 java.lang

Andy

展望开源产业与数字经济未来|2023开放原子全球开源峰会开源创新理论与实践分论坛即将启幕

开放原子开源基金会

开源 开放原子

悦数图数据库:图 + AI 在金融行业的应用及技术前瞻

悦数图数据库

AI 金融 图数据库实战

聊点技术 | 可观测性十问十答

博睿数据

可观测性 智能运维 博睿数据 发展趋势 聊点技术

嘉为蓝鲸荣登广东软件风云榜,获评新技术应用最受欢迎产品TOP10

嘉为蓝鲸

软件 新技术 应用程序

OS 生成文件目录树

Andy

在金融数据里挖呀挖,GaussDB开出了花

脑极体

数据库

跨终端Web之Hybrid App_移动_徐凯_InfoQ精选文章