文中是我个人的一些开发经验,希望对各位有用,也希望各位多多支持讨论,指出文中不足以及提出您的一些建议。
双容器
得益于近几年移动端的发展,前端早已今非昔比,从大型框架来说angularJS、react、VueJS都有其应用场景,从工程化来说各种配套构建工具也纷纷出世,而从前端复杂度来说,最近几年的前端代码难度着实提升不少,从模块化的必须,到MVC的必要、再到组件化编程,一种分而治之的思想逐渐侵入前端领域,而这种种迹象均表明一个问题,前端代码现在不好写了!!!
抛开近几年前端交互加重而导致的难度,我们今天主要探讨下前端跨平台一块的痛点,也就是Hybrid多容器解决方案。
Hybrid是一种混合开发模式,最简单的理解就是,Native会提供一个webview容器(确实不明白可以理解为iframe),然后在里面加载你的H5站点。
在大约三年前,当时Hybrid平台还比较少,如果一个公司前端团队比较强的话可以做到一套代码三端运行就很不错了,也就是一个H5页面同时运行在:
① 浏览器
② 公司IOS APP Webview容器
③ APP Andriod Webview容器
再这里有个和简单iframe不同的是,处于Native中的话,那么很多H5的表现便不太一样了,比如header一部分的UI是Native的,比如获取定位信息直接由Native给H5,在这里面会有些差异化处理,一般来说只有保持应用层API一致,底层稍作修改即可;但也有一些特殊场景需要判断,比如,一个按钮的回调在H5站点的处理和处于Native中不一样,这个时候可能就需要if else判断处理了。
总的来说,双容器时代持续了一阵子,而因为条件仍然比较单一,无非只是判断H5站点或者自身APP容器,所以问题也就不大。
多容器
量变到一定阶段便不再一样了,简单从携程来说,Hybrid的频道从最初的一个发展到现在APP中80%都是Hybrid频道,携程APP本身有一套完整的Hybrid交互规范,俨然已经不再简单是个APP了,而是一个Hybrid平台,开发规范一旦制定,一旦进入工厂化开发就很难更改了,除了携程各个业务团队依赖这个APP外,还有很多携程子公司乃至第三方公司依赖这个APP,那么这个时候底层若是不稳定,那么导致的问题将是连锁的、不可控的。
这种平台化的APP产品远不止携程一家,已知的就有:
① 微信APP平台
② 淘宝APP平台
③ 手机百度APP平台
④ 糯米平台
⑤ 手机QQ平台
……
国内这些“平台”都有各自问题,不论是微信一些版本不支持flex、手机百度IOS、Andriod Webview容器各种不一致,还是糯米Native默认后退不处理导致假死,都可以看出为了抢占市场,各个团队走的太急,考虑的应用场景过少,推出产品后后宣传网站写的漂亮,API看似丰富,但是光鲜的只是表面,真正形成平台后,各个业务方接入会形成各种小概率场景,而Native发版是无力的,Native不动就只能业务开发代码适配,这个时候受苦的总是各个接入方,而导致骂声一片。
各个平台不稳定、考虑场景太少其实也无可厚非,毕竟Hybrid才火不到几年,各个公司真正的经验场景又很难被其它公司吸收,所以这种现象还得持续一段时间……
当然,APP底层的问题不是我们今天思考的重点,我们还是回到前端应用层。
多容器与前端
上述平台产品虽然有各自的问题,但是其流量优势是无可比拟的!所以很多业务方、第三方公司都会接入,对于前端来说难度便增加了不少,以百度为例:
最初是前端代码运行在浏览器即可,而现在一套前端代码却需要运行在:
① 浏览器
② 自身APP
③ 百度地图APP
④ 手机百度APP
⑤ 糯米APP
而各个APP平台的Hybrid交互又完全不一致,更有甚者后期还需要微信APP、手机QQ等Hybrid平台,那么就简单一个按钮的交互都会令人头疼的!因为我们的代码中可能会出现这种东东:
1 2 3 4 5 6 7 8 9 10 |
if (shoujibaidu) { //手机百度逻辑 } else if (baiduditu) { //百度地图逻辑 } else if (nuomi) { //糯米逻辑 } //......其它平台逻辑 |
这种代码十分令人头疼,所以我们一般会封装一个方法在底层,哪个平台有差异就做特殊处理:
1 2 3 4 5 6 7 8 9 |
hybridCallback({ //默认回调 callback: function() { }, //手机百度回调 shoubaicallback: function () { }, //...... }); |
这个方法就是用于处理Hybrid差异而生,只有处于某一个环境,才会执行其中的回调,这其实只是一个语法糖,将判断的逻辑封装了,所以这个方案依旧很烂,如果哪天你要多一个容器或者少一个容器,整个站点的代码要如何处理呢?如果代码量超过万行,这个代码可不好处理!
更好的解决方案是抽离共性,是继承,一般来说,Hybrid还是有一个很大的特点:主要逻辑与H5一致,一些差异往往是显示什么,不显示什么(比如糯米中不显示H5推荐下载APP的广告),更多的是一些点击回调的响应,于是我们找到了更好的方案:
多容器解决方案
容器判断
解决多容器的第一步是容器判断,一般来说,不同的Webview容器会有不同的userAgent:
1 2 3 4 5 |
//微信中UA为: Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257 MicroMessenger/6.1.5 NetType/WIFI //浏览器中为: Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53 //糯米Mozilla/5.0 (iPhone; CPU iPhone OS 9_2_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13D15 BDNuomiAppIOS |
手机百度也会包含关键字:bdbox_x.x(x.x一般是版本号),根据ua我们可以知道当前处于什么环境(ios还是Andriod)与什么平台。
前端实现
如果是页面片的开发模式,一个页面往往会有一个js文件,做的好的团队这个js文件会是一个类,通过requireJS可以轻易拿到该文件,我们这里不做无用功,直接在之前代码的基础上做,有疑问的朋友请移步该文章:
在上文中,我们将一个个页面以组件化的方式打散了,我们这里新增一个index页面,并且新增一个按钮,点击按钮弹出一个提示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
define([ 'AbstractView', 'text!IndexPath/tpl.layout.html' ], function ( AbstractView, layoutHtml ) { return _.inherit(AbstractView, { propertys: function ($super) { $super(); this.template = layoutHtml; this.events = { 'click .js_clickme': 'clickAction' }; }, clickAction: function () { this.showMessage('显示消息'); }, initHeader: function (name) { var title = '多Webview容器'; this.header.set({ view: this, class="crayon-sy">.set({ view: this, 端的发展,前端早已今非昔比,从大型框架来说angularJS、react、VueJS都有其应用场景,从工程化来说各种配套构建工具也纷纷出世,而从前端复杂度来说,最近几年的前端代码难度着实提升不少,从模块化的必须,到MVC的必要、再到组件化编程,一种分而治之的思想逐渐侵入前端领域,而这种种迹象均表明一个问题,前端代码现在不好写了!!!
抛开近几年前端交互加重而导致的难度,我们今天主要探讨下前端跨平台一块的痛点,也就是Hybrid多容器解决方案。 Hybrid是一种混合开发模式,最简单的理解就是,Native会提供一个webview容器(确实不明白可以理解为iframe),然后在里面加载你的H5站点。 在大约三年前,当时Hybrid平台还比较少,如果一个公司前端团队比较强的话可以做到一套代码三端运行就很不错了,也就是一个H5页面同时运行在: ① 浏览器 ② 公司IOS APP Webview容器 ③ APP Andriod Webview容器 再这里有个和简单iframe不同的是,处于Native中的话,那么很多H5的表现便不太一样了,比如header一部分的UI是Native的,比如获取定位信息直接由Native给H5,在这里面会有些差异化处理,一般来说只有保持应用层API一致,底层稍作修改即可;但也有一些特殊场景需要判断,比如,一个按钮的回调在H5站点的处理和处于Native中不一样,这个时候可能就需要if else判断处理了。 总的来说,双容器时代持续了一阵子,而因为条件仍然比较单一,无非只是判断H5站点或者自身APP容器,所以问题也就不大。 多容器量变到一定阶段便不再一样了,简单从携程来说,Hybrid的频道从最初的一个发展到现在APP中80%都是Hybrid频道,携程APP本身有一套完整的Hybrid交互规范,俨然已经不再简单是个APP了,而是一个Hybrid平台,开发规范一旦制定,一旦进入工厂化开发就很难更改了,除了携程各个业务团队依赖这个APP外,还有很多携程子公司乃至第三方公司依赖这个APP,那么这个时候底层若是不稳定,那么导致的问题将是连锁的、不可控的。 这种平台化的APP产品远不止携程一家,已知的就有: ① 微信APP平台 ② 淘宝APP平台 ③ 手机百度APP平台 ④ 糯米平台 ⑤ 手机QQ平台 …… 国内这些“平台”都有各自问题,不论是微信一些版本不支持flex、手机百度IOS、Andriod Webview容器各种不一致,还是糯米Native默认后退不处理导致假死,都可以看出为了抢占市场,各个团队走的太急,考虑的应用场景过少,推出产品后后宣传网站写的漂亮,API看似丰富,但是光鲜的只是表面,真正形成平台后,各个业务方接入会形成各种小概率场景,而Native发版是无力的,Native不动就只能业务开发代码适配,这个时候受苦的总是各个接入方,而导致骂声一片。 各个平台不稳定、考虑场景太少其实也无可厚非,毕竟Hybrid才火不到几年,各个公司真正的经验场景又很难被其它公司吸收,所以这种现象还得持续一段时间…… 当然,APP底层的问题不是我们今天思考的重点,我们还是回到前端应用层。 多容器与前端上述平台产品虽然有各自的问题,但是其流量优势是无可比拟的!所以很多业务方、第三方公司都会接入,对于前端来说难度便增加了不少,以百度为例: 最初是前端代码运行在浏览器即可,而现在一套前端代码却需要运行在: ① 浏览器 ② 自身APP ③ 百度地图APP ④ 手机百度APP ⑤ 糯米APP 而各个APP平台的Hybrid交互又完全不一致,更有甚者后期还需要微信APP、手机QQ等Hybrid平台,那么就简单一个按钮的交互都会令人头疼的!因为我们的代码中可能会出现这种东东:
这种代码十分令人头疼,所以我们一般会封装一个方法在底层,哪个平台有差异就做特殊处理:
这个方法就是用于处理Hybrid差异而生,只有处于某一个环境,才会执行其中的回调,这其实只是一个语法糖,将判断的逻辑封装了,所以这个方案依旧很烂,如果哪天你要多一个容器或者少一个容器,整个站点的代码要如何处理呢?如果代码量超过万行,这个代码可不好处理! 更好的解决方案是抽离共性,是继承,一般来说,Hybrid还是有一个很大的特点:主要逻辑与H5一致,一些差异往往是显示什么,不显示什么(比如糯米中不显示H5推荐下载APP的广告),更多的是一些点击回调的响应,于是我们找到了更好的方案: 多容器解决方案容器判断解决多容器的第一步是容器判断,一般来说,不同的Webview容器会有不同的userAgent:
手机百度也会包含关键字:bdbox_x.x(x.x一般是版本号),根据ua我们可以知道当前处于什么环境(ios还是Andriod)与什么平台。 前端实现如果是页面片的开发模式,一个页面往往会有一个js文件,做的好的团队这个js文件会是一个类,通过requireJS可以轻易拿到该文件,我们这里不做无用功,直接在之前代码的基础上做,有疑问的朋友请移步该文章: 在上文中,我们将一个个页面以组件化的方式打散了,我们这里新增一个index页面,并且新增一个按钮,点击按钮弹出一个提示:
|