引子
web?native?这是个争论了很久的问题。
自从微信开放了更多的JS接口之后,移动web开发重新火了起来,前端程序猿也水涨船高。
毫无疑问,web页面有诸多优点:
- 跨平台:一次开发,可以同时在Android,iOS和Other Phone上运行(美好的愿望)
- 快速迭代,内容统一:内容修改后,不同版本都能展示最新内容。可以避免频繁的客户端升级,也无需经过App Store的审核
- 语言优势:庞大JavaScript开发人员,能够带来移动端内容的繁荣
本人多年开发研究web与native混合APP,因为这里面有很多的坑,很有必要把经验归纳一番。
准备
区分APP和浏览器
我们的web页面是通过哪个应用打开的呢?这是要解决的第一个问题,这样才能做到APP与系统浏览器的内容差异化。
- 通过域名
将不同用途的页面归类到不同服务器或Web项目下,这是最简单也最笨的方法,如果同一个页面要在三端上都展示,那么就要复制3份了 - 通过元数据
用meta标签区分,这样相对于把文件做区分,同样会面临上面的问题 - 通过UA标识
这是web页面统计访问终端的品牌和分辨率的常用方法
我会在WebView的默认UA后面,加上自定义的标识,包括APP的标识 (AndroidApp、iPhoneApp)、应用包名和APP的版本号
判断是否微信浏览器就可以使用这个方法,同时最好检查是否加载了微信自定义的weixin.js文件
配置WebView基础参数
final WebSettings settings = getSettings();
// 允许JS弹出提示框
settings.setJavaScriptCanOpenWindowsAutomatically(true);
// 允许web执行JS
settings.setJavaScriptEnabled(true);
// 设置浏览器标识
settings.setUserAgentString(buildAppUserAgent(getContext(), settings.getUserAgentString()));
// 是否支持缩放,默认不支持(看起来更native)
settings.setSupportZoom(false);
settings.setBuiltInZoomControls(false);
// 打开H5的离线缓存
settings.setAppCacheEnabled(true);
final String cachedir = getContext().getDir("cache", Context.MODE_PRIVATE).getPath();
settings.setAppCachePath(cachedir);
// 打开H5的Dom Storage(localStorage,sessionStorage)
settings.setDomStorageEnabled(true);
// 如果要使用离线缓存和DomStorage必须要设置web database
final String dbdir = getContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabaseEnabled(true);
settings.setDatabasePath(dbdir);
WebViewClient对象
监听页面加载情况(开始加载、资源加载、完成加载、页面错误)
通常情况下,我们都会有一个loading界面覆盖在webview上面,当页面加载完成隐藏loading。
这里存在2个小问题:
- webview只有当所有内容都加载完成后,才会回调onPageFinished。
也就是说,当DOM元素加载完成,并且所有图片也加载完成才会触发,这对于追求体验的移动APP来说,显然无法接受。尤其是当网络不好或图片太大时尤为明显,用户看到的是明明页面已经基本出来