WebViewClient未调用shouldOverrideUrlLoading

时间:2016-10-11 14:42:59

标签: android webview android-webview

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

WebViewClient

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

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

上次更新的网址(点击产品后永远不会调用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调用它们。

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

任何替代或解决方案?

10 个答案:

答案 0 :(得分:14)

当您点击该网页上的某个产品时,它会使用JavaScript加载新内容,并使用HTML5 History APIs更新地址栏中的可见网址。

从上面的MDN文章:

  

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

这些有时被称为single-page applications。由于实际加载的页面没有更改,因此不会调用页面加载的WebView回调。

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

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

如果您无法控制加载的页面,您仍然可以尝试inject a local JavaScript file进入网页observe when the history APIs are used,然后通过JS界面调用Android应用程序中的方法。我尝试使用上一个链接中描述的方法在Chrome中观察这些事件,它似乎工作正常。

答案 1 :(得分:6)

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

然后再试一次,如果找到新的网址,则会调用shouldOverrideUrl()

答案 2 :(得分: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
            }
        }

    }; 

答案 3 :(得分:5)

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

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {

然后从未调用。我花了一段时间才注意到正确的签名是:

public boolean shouldOverrideUrlLoading(WebView view, String url) {

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

答案 4 :(得分:2)

您可以尝试另一种方法:通过javascript端抓取网址。使用以下命令初始化您的webView:

"prepublish": "(in-publish && npm run clean && flow check && npm run test && npm run build) || not-in-publish" 

页面完全加载后(您可以使用算法来检查此https://stackoverflow.com/a/6199854/4198633),然后:

webView.addJavascriptInterface(new WebAppInterface(getActivity()), "Android");

并声明您的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);"); }

WebAppInterface

你可以做类似的事情来获取网页内的网址或其他内容。

答案 5 :(得分:1)

public class AndroidMobileAppSampleActivity extends Activity {
 /** Called when the activity is first created. */
String mCurrentUrl="";
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    WebView mWebView = (WebView) findViewById(R.id.mainWebView);

    WebSettings webSettings = mWebView.getSettings();
    webSettings.setJavaScriptEnabled(true);

    mWebView.setWebViewClient(new MyCustomWebViewClient());
    mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);

    mWebView.loadUrl("https://m.pandora.net/es-es/products/bracelets/556000");

}

private class MyCustomWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        mCurrentUrl = url;
        Log.i("mCurrentUrl",""+mCurrentUrl);  
        view.loadUrl(url);

        return true;
    }
}
}

尝试这个...

答案 6 :(得分:1)

对我来说,问题出在线下-

mWebView.getSettings().setSupportMultipleWindows(true);

删除它后,应该调用了OverrideUrlLoading。

答案 7 :(得分:0)

添加     webView.getSetting().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);     那么shouldOverrideUrl将被触发。

答案 8 :(得分:0)

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

https://stackoverflow.com/a/56395424/10506087

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

答案 9 :(得分:0)

onProgressChanged总是在重新加载时触发,使用userclick或XmlHttpRequest加载新页面。 比较先前加载的URL和当前加载的URL,您将知道它正在重新加载或加载新页面。在我的单页Web应用程序中,这很完美。

首先声明一个全局变量以存储最后一个URL。

String strLastUrl = null;

然后重写onProgressChanged(WebView视图,int进度)

mWebView.setWebChromeClient(new MyWebChromeClient(){

   @Override
   public void onProgressChanged(WebView view, int progress) {
            if (progress == 100) {
                //A fully loaded url will come here
                String StrNewUrl = view.getUrl();
                if(TextUtils.equals(StrNewUrl,strLastUrl)){
                   //same page was reloaded, not doing anything
                }else{
                   //a new page was loaded,write this new url to variable
                   strLastUrl = StrNewUrl;
                   //do your work here
                   Log.d("TAG", "A new page or xhr loaded, the new url is : " + strLastUrl);
                }
            }
            super.onProgressChanged(view, progress);
        }
});

我也尝试了上述解决方案,但就我而言,大多数解决方案都存在问题:

  1. doUpdateVisitedHistory 有时XmlHttpRequest生成的“#”后不能返回正确的url。
  2. onReceivedTitle在我的情况下不起作用,因为XMLHttpRequest检索的响应没有<title></title>标记。
  3. JavascriptInterface方法也可以,但是恐怕会导致 javascript的安全性相关问题。