首发个人博客:Android Hybrid App四大坑css
首先解释下题目,Hybrid App,混合应用,表明平台PhoneGap,通常指使用原生包装Web页面开发的应用。与原生应用相比,主要用户界面和业务逻辑都是用Web技术也就是HTML+CSS+Javascript实现的;与Web应用相比,Web部分打包在应用内部,使用时不须要网络。html
顺便说一句,不少解决方案其实不算Hybrid,好比Adobe AIR、Titanium、Mono,这些都是使用某一特定技术开发跨平台应用的工具,最终产品都是编译成原生来跑的。前端
咱们没有选择PhoenGap为技术基础(我对此并不满意,我认为以PhoneGap为基础能够少走一些弯路,少花一些精力,还能产出不少有价值的副产品),而是自行开发原生框架,主要目标平台是Android——嗯,就是那个从系统版本到模块组合都巨分散的Android,能够这么说,坎坷从立项的那一刻起就已经注定了……接下来,便请听我一一讲述:Android Hybrid App四大坑。(此文主要针对Android 4.3及以前的webview,部分浏览器好比Chrome已经改善了具体实现,因此Web App其实环境不错。)android
前端代码开源就好,https://github.com/Dianjoy/gamepop,要跑起来须要修改config.js,把if (debug) {}
的内容删掉。css3
Flexbox是CSS3里面一项很是重要的改进,大大改善了布局工做。惋惜从草案到终案时间跨度太长,因而市面上绝大部分设备只支持display:-webkit-box
。这给上图中图标区域的布局带来了难处,最终只能混合使用两种布局,display:inline-block
和display:flex
。须要注意,inline-block
元素之间,若是在代码中有空格换行符的话,渲染时会有约0.25em
~0.5em
大小的间隙,因此想一行4列每列width:25%
的话会放不下致使折行。开始我在其父元素中设置font:0/0 a
,大部分手机都OK,中兴ZTE795就不行,擦,上次也是它……后来我索性把全部空格和换行符都干掉,终于OK了。git
这段代码演示inline-block布局时父元素字体对子元素之间间歇的影响。github
<iframe src="http://jsfiddle.net/meathill/9Uk5Y/embedded/result,html,css,js/presentation/" height="200" width="100%" allowfullscreen="allowfullscreen" frameborder="0"></iframe>因此,对于多行多列的grid布局,咱们要谨记:web
对父元素使用display:flex;
flex-direction: row;
flex-wrap: wrap;
在现代浏览器和Android4.4以上的系统中,能够取得完美表现。
使用display:inline-block;
box-sizing: border-box;
vertical-align: top;
,而且在代码中移除块与块之间的空白字符,避免换行,保留合适的边距。
遗憾的是,低版本的webview中,高度不会自适应,除非使用js进行计算,否则仍是尽可能避免在元素下方画线的举动。浏览器
tap
vs click
(这个问题简直使人发指。)咱们知道,不少浏览器默认行为都依赖click
事件触发,好比超连接、input[type=radio]
的选中,等等。在4.4以前的webview中,click
比真实操做延迟约300ms触发,会带给用户明显的延滞感。为了提高用户体验,咱们多数使用tap
事件部分替代click
事件,以便及时响应用户操做。可选方案不少,Hammer.js、Fastclick,甚至Zepto都有封装。服务器
因而新的问题出现了。好比咱们用<a>
实现了一个删除按钮,tap
时,删除当前元素,而且将按钮重置为下载按钮,href
为下载的url。用PC开发时一切正常,但到真机测试就会发现,由于tap
是即时的,新按钮马上替换了旧按钮,300ms后,click
事件在新按钮上触发了,结果又开始下载……再好比,图层中有个后退按钮,点击后,图层移除,露出下面覆盖的部分,若是在tap
的位置上恰好有一枚连接,此时就会触发click
,页面跳转……以及,上次总结说的下载连接不触发click
,问题也同样,只不过翻过来,click
该触发的时候,被图层挡住了,因此没有触发。
解决方案基本围绕“如何熬过300ms”,和“甄别事件对象”来设计。
仍是上面两个场景,第一个,按下以后,setTimeout
400ms(以防万一)后再替换按钮;第二个,给图层加一个消失的动画,持续400ms,保证click
触发时图层还在。可能你们有疑问,为什么不干脆禁掉click
事件,前面说了,不少浏览器默认行为依赖click
事件,禁掉以后又会引起别的问题。
另外一个解决方案是甄别事件对象,在用户touchstart
的时候,记下event.target
,等到click
触发时,对比,若是不一致则认为是抽风,event.preventDefault()
。我更推荐这种作法,毕竟400ms也不算短。不过要注意,<label>
在响应click
时,会自动触发它for
的元素的click
,因此要用新增的control
属性进行二次对比,以避免误伤。
position:relative;
居然抢事件这个问题解决起来容易,排查时没少花时间。表现为,一个按钮,就在那里,但怎么点都没用。后来只好追踪全局事件,发现事件的对象并不是按钮,而是按钮下面被遮盖的层。很奇怪,我知道translateZ
可能致使这个问题,不过如今彻底没用到;并且下面的图层实际并无那么长(参照上图中,内容列表和下面的三个按钮,就是那里),列表的底部是bottom:60px
,恰好应该把<footer>
的三个按钮空出来。
而后我开始怀疑position:relative;
,由于只有这个东西会影响布局。把它点掉后,按钮果真能够点了,因而我给<footer>
也加上了position:relative;
问题就这样解决了。我以为这确定又是个Android Webview的Bug,由于我并无给下面层里的元素设置z-index
,只有position:relative
。总之,若是按钮点击没反应,尽早看看事件对象是哪一个,说不定被哪一个层抢走了。
caniuse.com是个神器,我在使用某个API或者CSS属性时不太有把握的话,都会去查一下。然而,谁又知道Android Webview默认不少API都没开呢?大到localStorage
,小到alert
、confirm
,都须要主动开放,否则就无法用。测试的时候又很难查,原生的环境多不在我这儿,配也不太容易,你们的习惯都不一致,只能等对方反馈过来错误信息,我到代码里查,但经常死活看不出来哪儿有问题。
后来认清现实就好办,Android Webview实际上是个半残废,有不明白的问题,多半是API实现不全致使的。最简单的办法是用modernizr之类的工具进行特性检测,或者在Weinre、Adobe Inspect CC里直接敲API。总之,别怀疑本身,基本都是Android Webview的问题。
这也是我为何但愿以PhoneGap为基础的缘由:PhoneGap已经按照规范实现了大部分API。插件库也很丰富,好比GA——说到这个,咱们想实现一个简单的统计,由于老板嫌GA太大,因此干脆使用一样的接口,只请求一下咱们的日志服务器,留下条日志就好,结果咱们惊讶地发现:Android里原生给Webview环境增长API,方法的参数不能多也不能少,否则就报错,真奇葩——能够省下不少时间。产出的结果,还能够分享到社区一部分,对于咱们公司,也能增长了很多开发者资源。
早先别人鄙视Hybrid App的时候我也各类不服,心说“大家丫懂毛啊就指手画脚的说不行”;如今经历了各类大坑小坑连环坑以后,个人想法已经变成了“大家丫懂毛啊不就是一不当心蒙对了么”。
Hybrid App开发会遭遇比原生和Web App更多的坎坷,这我有心理准备;如此多的坑无形中也在提高个人我的价值,我对此甚至隐隐有些高兴。不过我仍是但愿这段混乱之治尽快过去,Android平台不要再分裂了,高版本系统尽快普及,全部前端开发的日子都会好过许多。
如今,若是可能的话,尽可能以PhoneGap为基础进行开发,能省不少时间和精力。对于前端人来讲,更是能把测试环境搬到本地,实在是很是大的帮助。
Android 4.4时再次分裂,以后使用blink做为webview的基础;以前则是webkit,前者不管CSS仍是API都有更佳表现,Nexus 5基本没怎么改就都测试经过了。因此未来老罗的锤子手机开卖我必定买一台支持他,由于他良心的采用4.4为基础,对前端真是个可贵的好消息。