查看原文
其他

【第269期】在Android Webview的assets目录下开发Hybrid App的一些坑…

awebird 前端早读课 2019-11-02

来自早读君:

又是一篇hybird的实践经验总结~站在巨人的肩膀上,爽~


正文从这开始~

其实Hybrid App的最佳实践,还是应该把所有的html css js和主要的图片资源离线存储在Android的asset文件夹下,然后由Android实现从服务器端到手机的这个www主文件夹的更新机制,这样才不用凡事从server端下载..”没想到这么快就应用到新的项目中了。

当然,还只是实现了将webapp放在Android app的assets下,通过json api与server交互这步,理想中的通过app文件操作的更新机制还没有做,但是已经是梦想照进现实的节奏。感谢Android开发的同事包容了我这边不厌其烦反反复复的修改调试,才让这个相对Cutting Edge的方法得以应用到产品中。原本使用Hybrid App的初衷是为了分担Android开发同事的一些工作,但由于实践经验不足,而且Android webview确实还存在一些bug和兼容问题,最后评估下来反而多耗了不少时间精力。因此我们对于Hybrid App方式的使用暂时告一段落,web侧工作重心回归数据和后台开发,但是这轮开发的经验和教训还是很宝贵的,也给了我们更多信心,相信再过一小段时间,HTML5在移动设备的大规模应用就会到来。

好的,梦醒了还是总结下在Android Webview的assets目录下开发Hybrid App的一些坑,和各种跳过或者踩过坑的方案吧。

【坑 #1】 部分Android 4.0设备(HTC、海尔等)LoadUrl不能识别?参数或#hashtag

项目开始的时候,web部分是单独开发的,为了以后加入更多模块的扩展考虑,这个项目采用了AngularJs MVVM前端框架和ui-router做页面路由,其实就是单页应用(SPA)。当然,web程序无论采用什么技术,传参数只有两种方式

(1) ?参数形式,如top.html?id=1

(2) #hashtag形式,如index.html#topic/1

如果把程序部署在server端,或者Android的assets目录下,使用Webview访问的方式为


我们之前的项目已经大量使用了第一种url_server的方式进行开发,webview loadUrl远程链接也从没有出过问题,所以就顺理成章的开发着,但是等web端做的差不多了,部署到Android工程的assets目录下测试时,遇到一个非常棘手的问题,有一台HTC Android 4.0.3的测试机总是无法打开网页(Page not found)


由于Android开发侧的同事不懂Web,我这边对Android的了解也是汗毛级别,所以遇到这种问题的纠结与困惑就不赘述,直接给出“坑#1_desc”

Android的issue 17535 (Issue 17535:WebView – URL mechanism is broken – passingparameters does not work) https://code.google.com/p/android/issues/detail?id=17535

打开这个页面,一阵惊叹,反正我是第一次在googlegroups或者stackoverflow上看到这么多老外对一个bug如此大面积的愤怒情绪爆发,这个密集程度快赶上国内门户网站中国足球新闻下的评论了Orz..

具体bug不细描述,其实就是Android 3.0以后的webview在访问assets目录下的本地html资源时,带?参数和#hashtag的URL机制不能被识别,上面链接(#148楼)里2012年6月29号有google的开发人员回帖说这个问题已经在Jelly Bean被修复,当然这个只是Android代码的修复,所以现在市面上还是有很多手机的Android版本依然存在这个问题,就像我们不能强迫用户都改用Chrome,不能强迫国行Android用户root手机安装GMS服务包一样,我们也没办法让“找不到网页”的用户换手机或者升级系统,所以问题还是要被解决,下面提供三种方案,我们使用了最后一种:

(1)从Android侧扩展webview类进行处理

相关的方案和jar包已经在下面的链接列出 Step1~6即可解决。由于要对项目java部分进行改动,所以我们这边app侧没有采纳次方案,但应该是可行的。多提一句,我这边测试过,Phonegap的开源版本Apache Cordova就已经修复了这个问题

http://bricolsoftconsulting.com/fixing-the-broken-honeycomb-and-ics-webview/

https://github.com/bricolsoftconsulting/WebViewIssue17535Fix

(2)loadUrl(‘index.html’)后,再loadUrl一句js跳转语句的方法

这个方法,是得到V2EX的Archangel_SDY童鞋提醒,就是先只载入不带参数的页面(可以显示空白页或者loading效果),在页面载入后(onPageFinished),在loadUrl一句javascript用于跳转页面,下面的locationTo是在index.html写好的js函数,具体内容可以自己控制,只要接收到参数就ok

Android侧 (onKeyDown和java interface是用于处理返回事件问题的)


Web侧index.html中js (sessionStorge和javascript Interface调用代码是处理手机返回键事件用的)


当然,由于我手上没有这个问题的测试机(Android开发在不同城市Orzzzz),其实也不能确认这个方法是否真正有效,因为插入了一个中间页面,所以带来了返回和跳转问题,我们很快放弃了这个方案,继续寻找其它方法

(3)重写onReceivedError()方法 #最终采纳并测试有效版本#

参见

http://stackoverflow.com/questions/6542702/basic-internal-links-dont-work-in-honeycomb-app/7297536#7297536

代码(只支持#hashtag)


【坑 #2】所有Android Webview不能捕获#hashtag变化

Hybrid App中Android侧经常需要捕获webview中的url变化来做一些响应(比如改变header title的文字,处理终端的返回键等等)

但是无论是Server端的Url还是assets中的Url,webview都无法捕获到#hashtag的变化,也就是说index.html#step1 –> index.html#step2 –> index.html#step3 … 这些页面跳转是不能被Android监控到的。

这里提供两个解决方案

(1)在webapp里面使用javascript window.onhashchange里面调用Android的Javascript Interface方法,通知Android hash变化

http://stackoverflow.com/questions/15176519/android-webview-is-it-possible-to-detect-url-hash-change

(2)自己在页面跳转逻辑里,根据需要调用Android的Javascript Interface方法实现需要的功能

比如我这边用Angularjs,就在每个url对应的controller里面,调用Android侧的Javascript Interface方法,后来极端一点,由于不同页面功能点差别较大,直接废弃了web侧的ui-router功能,所有的跳转都交给java处理,也就是每个web页面(包括SPA中的一个状态)都交给Android的一个单独Activity,也就是做Activity的条状,Web侧的router白白浪费了T-T

其实上面的(1)和(2)是同一种方法,Android的Java和Webview里的web交互只有两种办法,一个是url捕获,一个是Javascript Interface,这里在#hashtag不能被url捕获到的情况下,就只能使用Javascript Interface了。

这样处理的一个结果就是Hybrid app里的web部分加入的java接口调用,如果脱离了App环境,要单独处理,或者通过检测Javascript Interface对象是否存在,来决定是采用web方法还是app方法跳转


总之,不完美…

【坑 #3】Android 2.X Webview不能Scroll滑动

发现有HTML5的页面在Android 4.x下一切正常,在Android 2.X下不能滑动(Scroll)的问题

这个问题无疑是Android的 bug

目前有两个解决方案

(1)Html中去掉meta viewport tag (未经验证)


http://stackoverflow.com/questions/10552702/cant-scroll-webview-in-android

由于viewport对于移动端的页面适配很重要,前端的同学说不能去掉,试过去掉后样式乱掉了,所以没有采用此方案

(2)Android中的layout布局,将webview布局在ScrollView中


这是Android侧的方案,上面的布局xml只是一个简单demo,web童鞋遇到了可以跟app开发的童鞋沟通解决。

【—–Scroll问题后续——】

后续开发过程中,Android的同事说不能使用上面的ScrollView布局,因为了整体的布局架构有冲突,所以这个问题再次无解,下面是后ScrollView时代的血泪史

(1)采用iScroll

angulrjs可以使用ng-iscroll

iscroll可以让webapp乍一看很有原生的感觉,但是我个人认为在webview存在不少问题,而且体验也不够顺畅,除非下拉刷新获取更多数据这种场景,应该尽量不用。

使用iscroll后测试确实可以在Android 2.3的手机上Scroll,但是有个问题,是因为我们的页面是先载入,在动态$http.post获取数据,更新页面内容的,所以Scroll的范围特别是高度总是会出现可以滑动到最底部,但是又弹回上面的问题..

后来分析是isroll的区域判断了初始页面的位置,所以在$http.post的数据获取后,$timeout延时refresh myscroll

上面的方案貌似解决了,但是在webview下又出现了页面闪烁的现象,而且scroll的体验很不好。

(2)最后痛定思痛,还是删除了所有的iscroll部分,重新寻找原因,重要发现元凶


是他,是他,就是他!

[原因] Android 2.X不支持这句css

[解决方案] 去掉,加上 height:auto

[参考] ScrollableDIV on mobile phones


长按图片识别图中二维码



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存