WebView问题:not defined;canGoBack()不准;onPageFinished()不准;webview输入法焦点遮盖

前几行代码就不说了

//开启js通讯
webview.getSettings().setJavaScriptEnabled(true);
//web调用js函数或代码
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
	webView.loadUrl(js);
}else {
	webView.evaluateJavascript("javascript:" + js, value -> {
		//something
	});
}

1.WebView之not defined

未定义的内容可能是element节点,也可能是函数.不管是哪一种,导致的原因都是

调用时机问题,排查调用时DOM树及js是否已经加载完成.有些element节点是动态增加的,尽管dom都加载完成了也不一定有,哈哈.可以看看我下面eleInsertedCallback 的代码说明

所以我们在onPageFinished()回调中执行十有八九没问题,但它不准,所以还是可能出问题,接下来就说说该怎么办.

2.WebView之onPageFinished()不准

百度搜一下,诚不欺我,可能还不如onProgressChanged() = 100 来的安心!还有一种方法就是

插入js监听dom加载回调

我们可以在webview.onPageStarted()的回调中注入js,

//使用window.onload方式监听dom加载
val domFinishedCallback1 = """window.addEventListener('load', (event) => {
    //do something
  });"""

//使用DOMContentLoaded方式监听dom加载
val domFinishedCallback2 = """document.addEventListener('DOMContentLoaded', (event) => {
    //do something
  });"""

//使用DOMNodeInserted方式监听element节点的创建
val eleInsertedCallback = """document.addEventListener('DOMNodeInserted', function(){
        var ele = document.getElementsByClassName('xxxClass')[0];
        if(ele != undefined){
            //do something
        }});"""

override fun onPageStarted(val view: WebView, url: String, favicon: Bitmap){
    view.evaluateJavascript(
        "javascript:" + domFinishedCallback1, 
        value -> {}
    )
}

思路打开了,发挥空间就不止这些了. 

当然如果你还想回调到native层,那不妨在native挂载一个对象,然后在这段js语句中调用native挂载对象的方法就实现了无缝衔接!这属于题外话不赘述.

3.WebView之canGoBack()不准

这个问题影响因素有很多,可能是h5的问题也可能是native端的问题.
首先我推荐使用evaluateJavascript(),因为loadUrl()执行js可能会导致这个问题.


如果问题仍然存在,可能的原因如这篇博客所述【BUG笔记】WebView返回时重复加载问题(CanGoBack返回true) - 简书 (jianshu.com)
求人不如求己

 按照上文的思路,我们进行一个兜底处理,来一个将计就计,既然canGoBack()判断错误了,自然就走了goBack()的逻辑中了,那我们就改造一下goBack()实现就可以了

@Override
public void goBack() {
    //在goBack()中再判断一次是不是真的可以返回,是则走返回逻辑,否则finish当前所在页面
    evaluateJavascript(
            "javascript:(function() {var state = window.history.state;return state.current != state.back && state.back && state.back != '/';})()",
            value -> {
                boolean canGoBack = Boolean.parseBoolean(value);
                if (canGoBack) {
                //可以返回,但有部分机型的super.goBack()就是不生效,为什么,我不知道。只能自己实现goBack()逻辑了
                    evaluateJavascript(
                            "javascript:(function() {return window.location.href.replace(window.history.state.current, window.history.state.back);})()",
                            value1 -> {
                                String realUrl = "";
                                //为什么有这个判断,反正js回调的数据就是这样的,只能这样搞了
                                if (value1.startsWith("\"") && value1.endsWith("\"")) {
                                    realUrl = value1.substring(1, value1.length() - 1);
                                }
                                if (!TextUtils.isEmpty(realUrl)) {
                                    loadUrl(realUrl);
                                } else {
                                    //最后兜个底
                                    super.goBack();
                                }
                            });
                } else {
                    Activity activityFromContext = getActivityFromContext(mContext);
                    if (activityFromContext != null) {
                        activityFromContext.finish();
                    }
                }
            });
}

 有朋友肯定会问,既然canGoBack()判断错了,为什么不直接重写canGoBack()呢?

实际上这里是2个问题,一个问题是canGoBack()判断错误;另一个问题是部分机型的goBack()不生效,明明可以返回就是返回没反应

 下面是一个错误的处理,谨防上当。调试后你会发现evaluateJavascript是在主线程调用的,而回调也是在主线程,导致await()阻塞主线程的同时,这两处调用也阻塞了,导致jsGoBack成了摆设,尴尬ing...这时肯定相对在子线程调用evaluateJavascript,你会发现需要在相同的线程中调用它才行。所以我没有想到更好的版本处理这个同步!

 

4.webview输入法焦点遮盖奇葩

大部分情况百度一下都有,仅记录自己遇到的。所有的办法都尝试了,折腾了一个下午终于算是找到问题的原因了。当导航栏被强制禁用时,webview的输入法会遮盖焦点!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值