写点什么

BlendUI,让 webapp 的体验和交互得到质的提升

  • 2014-07-15
  • 本文字数:4744 字

    阅读完需:约 16 分钟

故事背景

百度轻应用已经推出半年多了,在市场上已有一定的影响力。但同时我们发现,开发者之所以使用轻应用,看中的是百度的渠道分发能力,而在体验上和 Native app 有比较大的差异,这个问题在应用复杂以后变得尤为明显。

前些年,在做移动 web 站点时,我们都会追求一些无刷新的跳转、换页效果,但后来发现这样做在市场顶级的手机上尚不能运行流畅,就更不用说那些相对廉价和低端的智能机了。所以近一年来,大家倾向于不在移动 web 站点中采用复杂的特效,只在最关键的部分,用最小的代价来实现。

现在你已经很少在 Android 中看到用 Javascript 实现的换页效果了;又比如百度的多数产品线放弃了 Javascript 实现的局部滚动效果,转而采用原生滚动实现,或者只应用到页面的少数交互元素中。与此同时,很多公司已经将重点精力投入到 Native 原生应用的开发中,减缓了在 web 端的投入。

而对我们,当然希望轻应用的体验和交互能够和 Native 媲美,那我们要做什么才能达到这个目标呢?做什么才是最有效的呢?

调研

我们首先看到了 w3c 的 (一份报告) ,这是来自缩短与本地应用差距(closing the gap with native) 的任务组产出。这份报告指出了 webapp 相对 Native app 的优势与劣势。

我们接着寻找了很多份数据,概括得最好、数据量也很丰富的是 Developer Economics 的这份调研数据详细说说其中两组关键的数据:

  1. 为什么开发者不使用 HTML5 技术开发应用?
  2. 多少 Native app 可以用 web 技术实现?

经过对 6000+ 开发者的调查,他们发现,46% 的开发者认为性能是影响他们选择的因素,这也是在所有因素中占比最高的,其次是API 的缺乏,占 37%,再次是与 Native 元素的整合,占 29%。这和做为移动开发者的我们的主观感受相当一致,性能是 Webapp 的巨大瓶颈,不流畅的 app 一定不受用户喜欢;其次是一些功能无法用 web 实现,比如语音、定位等;再次,即使这些功能可以用 Native 原生代码实现,也无法将他们整合到 Webapp 中。

而第二个问题是第一个问题的延展:抛开性能问题,webapp 的能力和 Native app 相比有多大差距呢?他们调研了 Google Play 中的 30339 个 app。如果只使用 HTML5 技术,能实现 37% 的 app,如果使用 Phonegap,能实现 49%,如果使用 Appcelerator,能实现 63%。这个结果让人觉得很乐观,只要我们能用一些技术,将设备的一些基础功能开放到 web 中,能大幅提高 webapp 的应用范围。

与此同时,我们调研了百度内部的 16 款 webapp,希望了解做为国内一线厂商的工程师,他们认为 webapp 的瓶颈所在。结论出奇的简单和一致,有 87.5% 的工程师认为,在自己的业务场景中,转场和动画问题是最首要的问题

其实移动 web 站点经过这些年的发展(我在 2010 年就参与过百度内部移动前端基础库的研发工作),工程师和产品经理已经很清晰地认识到什么交互是 web 无法实现的,比如 3D 转屏,动态的卡片式操作,他们会灵活地调整产品设计,避免这些交互。

但有一点是无法避开的,那就是页面的转场动画。web 是基于链接构建的,从一个页面点击链接跳转到另一个页面,如果通过有刷新的打开方式,用户要面对一个空白的页面等待,如果通过无刷新的方式,用 Javascript 移入 DOM 节点,在 Demo 状态下能做得很好,但一旦产品化,就要冒着很高的性能风险:页面太大,可能转场不流畅甚至浏览器 crash;单个 webview 中 DOM 节点过多,同时还要保存多个场景的状态,会占用过多内存,在使用的过程中会变得越来越卡;更不用提那些低端机型和低端浏览器了……

所以,我们面临的首要目标是,如何能 webapp 的转场能像 Native 那般流畅

实现思路

在说实现思路之前,要先给大家说说轻应用的业务场景,以便理解。

轻应用的业务场景

轻应用有两大入口:移动搜索和百度搜索 app,接入轻应用的开发者他们最为看重的就是这个入口,尤其看重百度搜索 app 的入口。因为在普通浏览器中,通过移动搜索到达轻应用,这跟普通的 webapp 没有本质区别;而在百度搜索 app 中,由于轻应用的运行环境是百度框,我们能为轻应用的开发者暴露一些 Native API 的接口,这就是 Clouda API,包括提供设备能力的 Device API,提供百度云服务能力的 MBASS API。

技术选型

由于轻应用的使用场景天然和 Native 结合得很好,我们很自然地想到利用 Native 技术来做转场。相对用 web 技术,这条路更为现实:市面上有很多转场相关的 Javascript 库,百度内部也有若干实现,但最后产品化以后是否成功,完全取决于具体业务开发者。开发者能否有效地缩减 DOM 数量和层次,能否找到性价比较高的方案是关键。而轻应用开发者的水平良莠不齐,用 web 技术来解决此问题显然不可行。

而用 Native 技术来做转场,我们也经历了一些波折。最初,我们重点考虑的是类似 Appcelerator 的方案,不过我们不像 Appcelerator 那么激进地将 Javascript 编译成 Native code,而希望暴露一组基本的 Native API,供前端工程师调用以实现流畅的 app 效果。但这样随之而来的问题是,开发者的可定制性会变得特别差,极其依赖 Native API,而且开发感受也会很糟糕,毕竟他操作的不再是 DOM,而是一个 Java like 的东西。这个方案很快被我们否定。

根据前面所说的调研,我很快发现其实大家对普通的 web 元素,并没有太多性能方面的担忧。不管页面多复杂,很少有会担心页面内部的性能,而担忧统统来自跨页面的转场效果。因此,我提出了一个概念:Every element can be a webview.

Every element can be a webview

从逻辑上来看,webapp 是由多个 view 组成,而每个 view 又由多个 Element 组成。但在原生的 web 技术中,没有 View 这个概念,我们只能利用 Javascript,将 View 用 Element 实现,这样,一个 webapp 中就有超大量的 DOM 节点。在 view 切换时,需要进行大量的重绘,性能就差了,在移动设备上表现尤为明显。

而 BlendUI 的这个概念让 View 有了「原生」支持,任何的 Element 都可以用一个独立的 webview 来实现,浏览内核的负担就减轻了,而且切换时的过场动画用原生代码实现,也保证了性能。

举个例子,这是已经采用 BlendUI 上线的百度阅读 app,采用 BlendUI 来实现的话,原来是单页的 webapp 将分成很多不同的 webview。

在首页,背后是一个 webview,只用来显示头部,而底部由多个 webview 组成,以实现流畅的滑动效果。

打开图书页以后,覆盖在上面的是一个新的 webview。

甚至可以将某个复杂的控件做成一个独立的 webview 或者由 Native 控件实现。

也就是说,页面中任何一个独立出现的元素,都可以用一个独立的 webview 来实现。简单一个概念,解决了三大问题:

  1. 转场不再卡顿。从我们事后的实测数据来看,FPS 提高了一倍,从 30 fps 提高到 60fps。
  2. 随处都可以使用原生滚动,因为我们可以将卡头卡尾的页面区域用独立的 webview 实现
  3. 单个 web 页的 DOM 节点数减少,从而使页面本身的性能大幅提高

最后的结果证明,这条路用极小的成本解决了关键问题。

在我们开发出了 Demo 后,Basecamp 的工程师发了一篇博客,他里面有两个核心观点:

  1. Decisions based on computing speeds quickly decay. 硬件制约是一时的,语言和平台的生命力才最重要。
  2. Native shell + native navigation. 这是 Hybrid app 的一个简单但重要的改进,他们把 Native code 用在了对性能最为有利的部分。

最终,basecamp 的这个版本大受好评,37singals 只投入了 1-2 个工程师和半个设计师。他们的思路竟与我们出奇地一致。

核心实现

因为把握住了问题的核心,所以 BlendUI 的核心实现特别简单,向其他人解释这个问题也特别容易。我不用 BlendUI 有多少原生接口和能力这样的数据吓唬人,也不用长篇大论地解释内部有多么复杂的实现,只要演示我们的 Demo,然后告诉听众,我们解决了页面转场和卡头卡尾的问题就可以了。

设计原则

我们秉承的设计原则有三条:模型从简;事件驱动;为开发者保留最大的灵活性

  • 模型从简,这条原则贯穿始终。一句话来说,BlendUI 让 Javascript 拥有了控制 webview 的能力。
  • 事件驱动,这也是 Javascript 的核心。跨 webview 通讯、Javascript 和 Native code 通讯,几乎全是事件。
  • 为开发者保留最大的灵活性。这意味着 BlendUI 不会影响开发者对其他库、框架的选择,更不会在 UI 风格上面有任何限制,所有的东西都是 Web 的,定制性无限。

系统概览

系统亦很简单,分成上下两层。下层(蓝色部分)由 Native code 实现,上层(绿色部分)由 web 实现,下层提供核心能力,上层完成封装。

核心能力包括两部分,Runtime 和 BlendUI。前者是轻组件的运行环境,插件机制是它的核心,设备能力、BlendUI 都是插件,这样能最大限度地减少 SDK 的体积(极限状态下 100 多 K),所有插件都可以动态联网下载和更新。BlendUI 的核心自然是其 Webview 控制力,除此之外还包括扩展 BlendUI 的 Native 组件的能力,这和 Runtime 的插件机制类似,它能通过 Javascript 调用动态地加载外挂的组件。

在上层封装中,我们除了封装 iOS 和 Android 两个平台的能力,提供统一的 API 之外,还提供了一套退化的 web 实现,这样我们能让基于 BlendUI 开发的应用在普通浏览器下也能正常运行。

关键概念

Layer 和 LayerGroup 是 BlendUI 两个关键概念,Layer 即 webview,LayerGroup 即一组 webview 的集合。Layer 可以通过 Javascript 设定其显示的位置和大小,也可以指定滑入时的动画;LayerGroup 实现了最典型的组合,通过滑动切换不同的 Layer。

要让某元素固定在可视区域的某位置,比如顶部的 Tab 切换条,用一个独立的 Layer 实现 Tab,并固定其位置和大小即可:

复制代码
new Layer({
url: "/path/to/tab.html",
top: 0,
left: 0,
height: 30px
})

剩余的区域用一个 LayerGroup 实现:

复制代码
new LayerGroup({
url: "/path/to/content.html",
top: 30,
left: 0,
layers: [
{
url: "/path/to/content1.html"
},{
url: "/path/to/content2.html"
},
]
})

事实上,这些 Javascript API 都是通过调用 Native 植入 window 上下文的 window.lc_bridge 方法来实现的。

此外,通过监听 BlendUI 提供的事件,就可以实现内容切换时,Tab 页高亮区域转变的效果:

复制代码
document.addEventListener('groupScrolled', function(index){
highlightSwitch(index);
});

我们很快也会提供 ListView Header 类似的滑动卡头的能力。

除了 Layer 和 LayerGroup,就是原生组件的嵌入了。

复制代码
new Slider({
"images" : [
{
url: "/path/to/photo1.jpg"
} , {
url: "/path/to/photo2.jpg"
}
]
})

前文已经提到,原生组件是动态选择和加载的,这部分封装其实调用了 window.lc_bridge.addComponent(“com.baidu.blendui.component.slider”),addComponent 方法会去动态地加载 Slider,并且调用其中的 execute 方法。

适用场景

这项技术,首先对轻应用开发者来说是巨大的福音。在不接触任何 Native 代码的前提下,就能让轻应用的体验有质的提高,这项技术将很快通过轻应用 Runtime 下发到所有轻应用的运行环境中。一旦 BlendUI 集成到百度搜索 app 中,直接在 app 中打开的轻应用,这样既能使用百度的分发渠道,也能有较好的浏览体验。

另外,BlendUI 很适合大 app 中的独立频道单独发布 app 上架(比如豆瓣那一大堆子频道),既能节省人力成本,能保证基本的用户体验,又有很高的定制性,迭代速度和 web 相当。这样就能快速试错,即使产品决策失误,开发成本也不高,也容易调整 —— 这是互联网产品的核心优势。

作者专栏

行云出岫

云无心以出岫,鸟倦飞而知还。希望能给你带来一点灵感。


感谢王保平对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014-07-15 12:455187

评论

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

【LeetCode】加一Java题解

Albert

算法 LeetCode 8月日更

万字深入HarmonyOS ACE UI框架解析,带你看懂UI渲染流程

科技汇

百度大脑FaceID人脸识别模型量化技术,确保算法精度无损加速一倍

百度大脑

算法 人脸识别 精度

【Vue2.x 源码学习】第二十四篇 - 异步更新流程

Brave

源码 vue2 8月日更

图分析在吴亦凡事件中的应用场景

6979阿强

图算法 图计算 GraphScope 吴亦凡 一站式图计算平台

面试官:你说说一条查询SQL的执行过程

艾小仙

2021 年最全Java架构面试点+技术点标准手册:完全对准一线大厂,猛攻!

Java 编程 面试 IT 计算机

IM开发干货分享:网易云信IM客户端的聊天消息全文检索技术实践

JackJiang

全文检索 即时通讯 IM

知道ThreadLocal吗?一起聊聊到底有啥用

华为云开发者联盟

Java 架构 线程 ThreadLocal 链路

高亮的架构毕业总结

高亮

架构训练营

1个月学会Java开发!2021年最新Java面试点梳理

策划Java工程师

Java 程序员 后端

架构学习总结

c

架构实战营

阿里P8架构师又传喜讯!最新产出 Java 架构师 1575 道“完美圣经”,汇总十家互联网大厂面试题!

Java 编程 IT 计算机 知识

LeetCode题解:173. 二叉搜索树迭代器,递归,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

体验百度EasyEdge,畅快部署超多AI芯片

百度大脑

人工智能 飞桨

面试官:你了解Java中的锁优化吗?

程序员阿杜

Java 面试 JVM 同步 8月日更

译文 | 四种产品经理成长框架,你是哪一种?

LigaAI

产品经理 产品管理 PM

AudioTracker实用封装

Changing Lin

8月日更

科技融合:Hightopo受邀参加厦门公安科技活动周

一只数据鲸鱼

数据可视化 智慧公安 智能化 安全态势

2021Java春招面试真题:记一次蚂蚁金服Java研发岗的面试经历

策划Java工程师

Java 程序员 后端

外包三年经验,耗时半年进大厂,整合出 25W 字 Java 全栈面试题,把初心分享出来!

编程 架构 面试 IT 计算机

Lucene 倒排索引原理

Qunar技术沙龙

数据库 全文检索 lucene 倒排索引 搜索

应对极端天气,百度智能云推出城市内涝智能监测预警系统

科技热闻

高防云服务器 VS 云服务器

九河云安全

258W 字 Java 全栈面试题!实锤:阿里架构师耗时半年整合而来!

Java 编程 架构 面试 计算机

WICC 2021 技术分论坛 “开箱即用”语聊房Demo成亮点

融云 RongCloud

Springboot 配置文件、隐私数据脱敏的最佳实践(原理+源码)

程序员小富

Java springboot 数据安全 数据脱敏

高防服务器选择注意的三大方面

九河云安全

Cocos Creator v3.2 正式支持 HarmonyOS 多设备协同能力

科技汇

香港服务器流量选择,该如何选择?高防服务器租用防御多少G合适呢?

九河云安全

鬼知道我这一年是怎么过来的?Java 开发从二面被拒到收割阿里架构 offer!

Java 编程 面试 IT 计算机

BlendUI,让webapp的体验和交互得到质的提升_语言 & 开发_雷志兴_InfoQ精选文章