简单HTML5 App开发踩坑手记
zsx2015/8/15 in 记录整理 / 0 / 6219

人哪,不能太贪心。否则,就会踩坑。——题记


事儿要从我的【自主招生信息服务器】项目开始说起。这个项目必须搭配一个手机客户端以实现推送等效果。你看,最近HTML5 App很火热嘛;很不幸地,我被蒙骗了。用了两种不同的方式,实现了两个版本的手机App。不过说真的,现在写这个也是有点太迟了。

第一个项目:HBuilder + Vue.js + MaterializeCSS + Page.js + jQuery

第二个项目:Visual Studio 2015 Community + React + React-Router + Material UI + Browserify + Gulp + Cordova

为了写起来方便,我在HBuilder的项目是直接照搬原先的前端JavaScript,只是把CSS从Pure换成了MaterializeCSS。


就把GitHub推上来好了:

项目一:https://github.com/zsxsoft/toy-zzzs-mobile-hbuilder 

项目二:https://github.com/zsxsoft/toy-zzzs-mobile-cordova 


性能坑

现在的手机,都拿着性价比当卖点。然而,手机CPU因为考虑平衡性的缘故,势必不可能快。再加上Android平台本身一些特点,导致性能成为HTML5 App最麻烦的一块。

为了保证安装包大小,或是七七八八什么原因,这些App都是基于系统WebView的打包,并不像各种国产浏览器那样带了内核。我们可以直接从navigator.userAgent得到结论。

首先是 CSS 的性能问题。

我这里选用的两个库,MaterializeCSSMaterial-UI,动画的帧率都比较一般,不过还是CSS3动画。如果直接用JavaScript控制DOM Style,结局就是下一个Facebook(http://www.infoq.com/news/2012/09/Facebook-HTML5-Native)。它们在Android Chrome下可以勉强达到原生的效果。根据文章(http://livoras.com/post/23)所言,如使用手机原生WebView,在部分手机会出现很严重的掉帧,或直接就是卡顿。

我们直接拿Material-UI GitHub的gh-pages分支,经由Cordova打包后,在某国产Android 4.2.2平板测试。如图所示,并非GIF录制问题。


其次,是 DOM 性能问题。
感谢 React 带来了 Virtual DOM,部分解决了局部区域 DOM 刷新时的性能问题。不过,一旦涉及到较大区域 DOM 更新,反倒有更大的性能损耗(最终计算出来的结果还是要全部替换掉,多做了一步 Diff )。

也分享一篇文章,可以看看坑:移动端HTML5游戏性能优化

这里有个例子:微众银行 App 是 Cordova + Ionic + Angular:微众很行app十分卡顿,大家觉得么?

安全坑

正如.apk -> .dex -> .jar -> .class -> .java一下就能把代码全部拿出来看一样,.apk -> .js 更为方便,解压一下就好了。于是,在 Release 前,必须 gulp / grunt 构建工作流,把 uglify 之类全部一股脑塞进去。这部分和做网页前端没啥区别,差别大概只有不需要考虑代码切分等(毕竟没有网络,全在本地)。
然而,这样的代码,修改成本非常低。比如我做一个付费的本地游戏,只要简单地修改一下.js,轻轻松松破解验证等后重新打包回去,破解版游戏就做好了,比 Java 的简单多了。就算有 C++,我 js 不调用你,你又奈我何?没有服务器验证的话,玩蛋去吧。

开发坑

如果没有 Native Code,一切HTML5 App都是空架子。所以,Java / Objective-C / C#仍然是必须学习的语言;Native App 如何开发也仍然是必修。

如以下是HBuilder在Android打开浏览器的代码(在Cordova只需要window.open,然而Cordova调用Java更麻烦,需要插件或addJavascriptInterface)。

    function openInBrowser(originalUri) {

    	var Intent = plus.android.importClass("android.content.Intent");

    	var main = plus.android.runtimeMainActivity();

    	var Uri = plus.android.importClass("android.net.Uri");

    	var uri = Uri.parse(originalUri);

    	var intent = new Intent(Intent.ACTION_VIEW,uri);

        main.startActivity(intent);

    }

不可能在没有平台原生App开发的基础上直接拿HTML5开发App,这样做只能做界面,或是调用别人封装好的东西。

另外,由于涉及两种不同语言,相互交互的数据结构也必须要搞清楚。

调试坑

先吐槽:Android 5.0+ 的系统内的 WebView ,可以用 Chrome for PC 来调试。但需要翻墙。

HBuilder不提供本地直接apk打包,所以不能像直接adb install推送一个安装包到手机。他们的解决方案是提供一个公用容器App,通过向这个App文件的存放地址adb push文件来达到调试的目的。另外,这样做的一个特点就是快。只是,用这种方式来调试,容易碰到环境不统一的BUG。这也是比较麻烦的部分。

然后看看逻辑与界面两方面的调试。
JavaScript 方面,如果 throw 出一个错误,很可能剩下的事情你都干不了了。手机端的表现就是什么操作都没用,也不会崩溃退出之类。在开发时,对于 JavaScript 报错,MUI 和 Cordova 均可以通过 adb logcat 来检查报错;Release 后可就没办法找用户连 USB 了。weinre 等工具对于 JavaScript Debug 没啥用。
那 weinre 干啥用?只是让你看 DOM 层级或动态执行代码罢了。这就是 UI 方面的调试了。这部分的话,考虑到兼容问题,自求多福吧……

Cordova 提供了 Ripple,倒的确是一个很不错的解决方案。但是并不能涵盖所有的手机……

兼容坑

因为基于file协议的缘故,没有Rewrite Rule没有后端Router,这个时候前端路由就麻烦得多,光调试就搞弄半天。必须注意的是,别用History API当路由

然后看看最恶心的坑:

官方Android系统的 WebView 一般随 Android 版本更新(当然,也可以自己去 Play Store 更新),每个版本所支持的功能均不同。坑的是,在国内的环境下,基本不会再更新了。有的功能,在 PC 上对应版本的Chrome 是有的,到该版本 WebView 就没有了。

比如说,XMLHttpRequest 的 onprogress 在 Android 4.0.4 上不被支持。于是,针对这类系统,只能采用像之前对 IE 的 Hack 一样,用 iframe 来替代进度条。
再比如说,ECMAScript 6 被高版本 WebView 支持。如果开发者写惯了后,引入了 Symbol 等,又忘记了 polyfill 。在低版本 WebView 就会出错。就像我这样:<Table> doesn't support old browsers. · Issue #1685 · callemall/material-ui · GitHub
接着呢,感谢 ROM 厂商乱改系统自带的 WebView ,从而导致在各种小细节上不同手机的显示效果或运算结果不同。更倒霉的是,有的甚至还会全页面混乱。
怎么解决?个人认为,像微信那样自带一个 X5,也许算是一个解决方案吧。

至于兼容问题的例子,还是微众银行好了:https://www.v2ex.com/t/215728 (与新版 iOS 9 的 WebView 不兼容)

总结

总结是,现阶段的HTML5,非但不适合拿来开发手机App,甚至于不能像Atom / Visual Studio Code那样,UI用HTML + CSS制作,核心由C++(手机为Java / ObjC)编写。下次研究C# + HTML5 Hybrid App跨平台,这个算是比较成熟的技术了(然而贵)。

如果像QQ、微信那样,塞一个像X5一样的自定内核到App里,能不能解决一些问题呢?

不过说真的,Flipboard这样用Canvas实现的手机App速度也不知道如何(http://engineering.flipboard.com/2015/02/mobile-web/) ,然而难度略高,高三在即,想必也不会有时间去研究了吧。


其它

也许我真的应该去买个WebStorm了。

原定用TypeScript + React开发,悲惨地失败了。Visual Studio不支持tsx,Visual Studio Code和其它编辑器支持tsx但不支持IntelliSense。Visual Studio Code不支持jsx。Visual Studio 2015对jsx的支持存在问题,对ECMAScript 6的支持也有问题(import、解构提示语法错误)。Sublime Text找不到适合的插件格式化jsx文件。Atom太卡。

然后,TypeScript Compiler在目前的Stable是1.5,而为了编译React至少需要1.6,这就需要nightly版本。于是费了心思强行升级Microsoft SDKs/TypeScript/1.6,最后没用上_(:з」∠)_

如果本文对你有帮助,你可以用支付宝支持一下:

Alipay QrCode