android hybird app 踩坑之旅

发布于 2019-09-26 作者 风铃 104次 浏览 版块 前端

最近在写一个hybird的项目,过程中遇到了各种大大小小的问题。究其原因,就是android的webview太坑了。

在项目开始之前,首先要清楚自己这个项目有多长的开发周期,如果开发周期比较长,我们可以自己去封装原生的webview

封装原生webview相对第三方的webview来说,大小会小很多,而且自己封装的内容清晰,出了bug也方便解决,最重要的就是

在封装的过程中,我们可以学到很多东西。

关于原生webview封装的注意事项,我觉得这篇文章写的很好,我就不重复写了http://www.jianshu.com/p/d657580ac643

如果是项目周期比较短的情况下呢?我们可以使用第三方的浏览器内核,目前比较火的内核有

1.腾讯x5内核 https://x5.tencent.com/tbs/ 

这个项目刚开始的时候,各种坑,骂声一片,然而到目前为止,虽然还有一些问题,但是已经比较稳定了

x5 的优势在于,相比于其他内核,大小要小很多,内部解决了广告过滤还有api17以下js交互漏洞的问题,这也是我目前在用的一个内核

2.crosswalk https://crosswalk-project.org

crosswalk 的优势是性能优秀,解决了android webview 碎片化的问题。它唯一的缺点就是,太大了,所以我直接放弃了。

3.phonegap https://github.com/Wizcorp/phonegap-facebook-plugin 

这个项目我没有集成过,只是简单看了下源码,内部也是通过原生webview实现的

除了这些之外,还可以看看一个开源浏览器Ninja的源码,有些设置还有优化的地方可以借鉴

接下来说一说开发过程中遇到的一些问题:

1.webview在fragment中使用,在fragment销毁的时候,会报一个内存泄漏,由于时间太久远,具体的日志不贴了

解决方式就是在fragment的生命周期中添加如下代码

override fun onResume() {
    super.onResume()
    // 解决一个内存泄漏问题
    mWebView?.settings?.javaScriptEnabled = true
}

override fun onPause() {
    super.onPause()
    // 解决一个内存泄漏问题
    mWebView?.settings?.javaScriptEnabled = false
}
2.在webviewclient中,onReceiveError会先于onPageFinish回调

这个问题主要影响的是我们自定义error页面的时候,在OnReceiveError中会设置显示错误的页面,如果我们在onPageFinish中有隐藏错误页面的逻辑

就会发现error页面总是没法出现,因为不管页面出错与否,onpagefinish都会回调,在这里注意处理显示和隐藏逻辑的先后顺序和判断就好了

3.onReceiveError只会在断网或者网速过慢加载失败的时候回调,如果网页404,或者500,这个方法是不会回调的

所以我们自定义错误页面,不仅要在onReceiveError中处理,还需要想办法获取到页面的请求返回码

目前api23以上的新增了onReceivedHttpError这个回调,解决了这个问题,但是在api23以下的如何解决呢?

我这里是通过webchromeclient的onReceivedTitle回调处理的

override fun onReceivedTitle(p0: WebView?, p1: String?) {
    super.onReceivedTitle(p0, p1)
    if (p1?.contains("404")!! || p1.contains("500") || p1.contains("Error")) {
        
    }
}
4.关于自定义user-agent,需要注意一个问题,就是格式不能乱来,如果随意用一个字符串定义user-agent,就会被页面当成是pc端的浏览器

举个例子,我们加载淘宝的登录页面,原本应该显示一个简单的帐号密码输入框,和一个确定的按钮,当我们修改了user-agent之后,就会变成pc端的登录页面,变得很小。

所以要自定义user-agent,推荐的方式是这样

val userAgentString = agentWeb?.getWebSettings()?.userAgentString
agentWeb?.getWebSettings()?.setUserAgent(userAgentString + "/xxxx")
在原来的基础上拼接,这样页面在获取你的user-agent之后,仍然会认为你是一个手机浏览器。

5.在h5中使用cookie的时候,如果希望cookie在浏览器关闭的时候被清除,那么不设置cookie时长即可,然而android webview在销毁的时候,并不相当于浏览器关闭

如果h5需要退出时清除cookie,我们需要手动调用

override fun onDestroy() {
    super.onDestroy()
    CookieManager.getInstance().removeAllCookie()
    mWebView?.destroy()
}
6.腾讯x5内核,首次初始化的时候,需要一定的时间,如果不注意这点,你会发现在低端手机上会出现黑屏(白屏)的效果

要解决这个问题,应该尽可能早的调用内核的初始化方法。腾讯也提供了一个初始化结束的回调,我们可以通过这个api灵活优化

例如在splash中,先让内核初始化完毕,这样就不会出现白屏的效果。

温馨提示:如果手机装了微信或者qq,或者qq浏览器,可以加快x5的初始化。

7.webview设置多窗口的api慎用,在有些页面中不支持,你会发现设置了之后,无法打开新页面。

8.为了优化用户体验,我们可以在不同的情况下采用不同的缓存策略,不至于用户没网进来什么也看不到

if (isNetworkConnected()) {
    settings?.cacheMode = WebSettings.LOAD_DEFAULT
} else {
    settings?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
}
9.另外我们可以延迟网页图片的加载,让页面更快显示出来,首先在初始化的时候

settings?.loadsImagesAutomatically = Build.VERSION.SDK_INT >= 19
之后在webviewclient的onPageFinished的回调中

if (!mWebView?.settings?.loadsImagesAutomatically!!) {
    mWebView?.settings?.loadsImagesAutomatically = true
}
10.有些h5的插件会严重影响页面的加载速度,所以优化页面加载速度,绝对不只是android工程师一个人的问题,需要前端工程师配合

暂时想起来这么多,就到这吧。。。

收藏
暂无回复