WebViewClient不调用shouldOverrideUrlLoading

Sup*_*ngs 15 android webview android-webview

问题很简单.在应用程序中,我们希望跟踪显示的当前URL.为此,我们使用shouldOverrideUrlLoading回调来WebViewClient保存url到每个更新的类字段.这是相关代码:

    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.getSettings().setDomStorageEnabled(true); 
    mWebView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            mCurrentUrl = url;

            // If we don't return false then any redirect (like redirecting to the mobile
            // version of the page) or any link click will open the web browser (like an
            // implicit intent).
            return false;
        }



        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            ...
        }
    });
    mWebView.loadUrl(mInitialUrl);
Run Code Online (Sandbox Code Playgroud)

但是,至少有一种情况,即回调永远不会被触发,并且mCurrentUrl字段不会更新.

网址:https://m.pandora.net/es-es/products/bracelets/556000

上次更新的URL(在单击产品时永远不会调用shouldOverrideUrlLoading):https://m.pandora.net/es-es/products/bracelets

我尝试过像onPageStarted()这样的回调,但是url也被过滤了,因为它的受保护代码似乎没有可访问的上游.

阅读有关WebView的android文档我发现了这个:

https://developer.android.com/guide/webapps/migrating.html#URLs

在请求资源和解析使用自定义URL方案的链接时,新WebView会应用其他限制.例如,如果实现了诸如shouldOverrideUrlLoading()或shouldInterceptRequest()之类的回调,则WebView仅针对有效URL调用它们.

但仍然没有意义,因为上面的网址是通用的,应该符合标准.

任何替代或解决方案?

Leo*_*ilä 21

当您单击该网页上的产品时,它会使用JavaScript加载新内容,并使用HTML5历史记录API更新地址栏中的可见URL .

从上面的MDN文章:

这将导致URL栏显示http://mozilla.org/bar.html,但不会导致浏览器加载bar.html甚至检查bar.html是否存在.

这些有时被称为单页面应用程序.由于实际加载的页面不会更改,因此不会调用页面加载的WebView回调.

如果您确切地知道要拦截哪种HTTP请求,则可以使用shouldInterceptRequest为每个请求调用的回调.Web应用程序可能会从API加载一些数据,例如,当显示产品时,您可以检测到该数据.

如果无法检测到这一点,但您可以控制Web应用程序,则可以使用Android JavaScript界面直接从Web页面调用Android应用程序中的方法.

如果您无法控制加载的页面,您仍然可以尝试将本地JavaScript文件注入网页并观察何时使用历史API,然后通过JS接口调用Android应用程序中的方法.我尝试使用上一个链接中描述的方法在Chrome中观察这些事件,它似乎工作正常.


Mik*_*nov 9

也许这对某人有帮助,虽然问题中的签名是正确的,但 Android Studio 建议使用以下方法签名:

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Run Code Online (Sandbox Code Playgroud)

然后就再也没有打电话过来。我花了一段时间才注意到正确的签名是:

public boolean shouldOverrideUrlLoading(WebView view, String url) {
Run Code Online (Sandbox Code Playgroud)

抱歉,如果这不是 100% 符合问题,但我相信这可能会对处于相同情况的人有所帮助。注意到第二个参数不同并不总是容易的。

  • 使用 API 23 及更低版本的设备上会出现此问题。为了支持所有 Android 版本,必须实现这两个回调。我向 Chromium 提交了一个错误(带有文档):https://bugs.chromium.org/p/chromium/issues/detail?id=1064537 (5认同)

Jij*_*ijo 7

请省略 mWebView.getSettings().setDomStorageEnabled(true);

然后再试一次,如果发现一个新的url会调用 shouldOverrideUrl()


小智 7

在偶然发现这个问题并寻找解决方案之后,我找到了最适合我的解决方案

/sf/answers/3947679711/

 override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
    // your code here
    super.doUpdateVisitedHistory(view, url, isReload)
}
Run Code Online (Sandbox Code Playgroud)


Tro*_*iPM 5

您可以尝试的另一种方法:通过 javascript side 捕获 url。使用以下命令初始化您的 webView:

webView.addJavascriptInterface(new WebAppInterface(getActivity()), "Android");
Run Code Online (Sandbox Code Playgroud)

页面完全加载后(您可以使用算法来检查,如下/sf/answers/433989811/),然后:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    webView.evaluateJavascript("(function() {return window.location.href;})", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String url) {
            //do your scheme with variable "url"
        }
    });
} else {
    webView.loadUrl("javascript:Android.getURL(window.location.href);");
}
Run Code Online (Sandbox Code Playgroud)

并声明你的WebAppInterface

public class WebAppInterface {
    Activity mContext;

    public WebAppInterface(Activity c) {
        mContext = c;
    }

    @JavascriptInterface
    public void getURL(final String url) {
        mContext.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //do your scheme with variable "url" in UIThread side. Over here you can call any method inside your activity/fragment
            }
        });

    }

}
Run Code Online (Sandbox Code Playgroud)

您可以执行类似的操作来获取 url 或页面内的其他任何内容。


Mic*_*kov 5

我遇到了与您相同的问题,并且完成了通过侦听回调到WebViewChromeClient的扩展

public void onReceivedTitle(WebView view, String title)

mWebView.setWebChromeClient(mSWWebChromeClient);

private WebChromeClient mSWWebChromeClient = new WebChromeClient() {

        @Override
        public void onReceivedTitle(WebView view, String title) {
            super.onReceivedTitle(view, title);
            if (!view.getUrl().equals(mCurrentUrl)) {
                mCurrentUrl = view.getUrl();
                //make something
            }
        }

    }; 
Run Code Online (Sandbox Code Playgroud)


Hri*_*dam 5

对我来说,问题出在下面——

mWebView.getSettings().setSupportMultipleWindows(true);
Run Code Online (Sandbox Code Playgroud)

删除它后,shouldOverrideUrlLoading 被调用。