44

I have a webview in my android app and would like to detect when the url changes.

I want to use this to hide the info button in the top bar when the user is on the info.php page and show it again when he is not on the info.php page.

I googled but can't find any working code, can anybody help me?

Ali Khaki
  • 1,184
  • 1
  • 13
  • 24
Daniel
  • 1,275
  • 1
  • 22
  • 31
  • 1
    Perhaps this will help you http://stackoverflow.com/questions/6868599/unable-to-get-currnet-url-on-click-event-of-web-view-in-android .. get the current url for the page using onPageStarted and you should be set. – Sergey Benner Feb 16 '12 at 13:56
  • kindly accept/upVote answer if you have got yours – RPB Jul 02 '12 at 07:57

13 Answers13

102

I know I'm late to the game but I ran into this issue over and over ... I finally found a sloution which is pretty straight forward. Just override WebViewClient.doUpdateVisitedHistory

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

It works with all url changes even the javascript ones!

If this does not make you happy then I don't know what will :)

grAPPfruit
  • 2,041
  • 3
  • 20
  • 29
15

You can use WebViewClient.shouldOverrideUrlLoading to detect every URL changes on your WebViewClient

RPB
  • 16,006
  • 16
  • 55
  • 79
14

For those load url by javascript. There is a way to detect the url change by JavascriptInterface. Here I use youtube for example. Use JavaScriptInteface has async issue, luckily its just a callback here so that would be less issue. Notice that @javascriptinterface annotation must be existed.

{
    youtubeView.getSettings().setJavaScriptEnabled(true);
    youtubeView.setWebViewClient(mWebViewClient);
    youtubeView.addJavascriptInterface(new MyJavaScriptInterface(),
            "android");
    youtubeView.loadUrl("http://www.youtube.com");

}

WebViewClient mWebViewClient = new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
        view.loadUrl("javascript:window.android.onUrlChange(window.location.href);");
    };
};

class MyJavaScriptInterface {
    @JavascriptInterface
    public void onUrlChange(String url) {
        Log.d("hydrated", "onUrlChange" + url);
    }
}
Shu Zhang
  • 521
  • 12
  • 20
  • 3
    why to use MyJavaScriptInterface while you can work directly in onPageFinished? – Usman Rana Jul 07 '17 at 10:08
  • 1
    javascript:window.android.onUrlChange(window.location.href); is javascript language works inside webview. JavascriptInterface prints actually url. Since the webview load url by javascript, onPageFinished still passing the original url but you actually already enter a new url. – Shu Zhang Jul 07 '17 at 13:39
  • @Shu Zhang, Not working, my webpage have a redirect using javascript but is not working. please help. – Chris Harris Aug 02 '17 at 03:33
  • 1
    Do we need to add onUrlChange in webpage? – Chris Harris Aug 02 '17 at 03:40
  • @ChrisHarris Don't need in my case. Can you confirm both `onPageFinished`, `onUrlChange` was called in the code above, and which webpage you try to monitor? what url they gave you(include `window.location.href`)? I feel like something in the webpage stop this mechanism. – Shu Zhang Aug 02 '17 at 03:52
  • @ShuZhang, I will add my code as answer for this question please take a look. – Chris Harris Aug 02 '17 at 04:27
  • @ChrisHarris you also need to `addJavascriptInterface` to your webview. And its class based. So you need wrap it in class. – Shu Zhang Aug 02 '17 at 04:57
  • 2
    @ShuZhang, I have added all that. i also tried wrap in the classs not working. – Chris Harris Aug 02 '17 at 05:01
  • @ShuZhang, Is Javascript redirect call after onPageFinished? – Chris Harris Aug 02 '17 at 05:02
  • @ChrisHarris The `view.loadUrl("javascript:window.android.onUrlChange(window.location.href);");` actually is the one who pass the url to your JavascriptInterface. So that's why I need you to confirm does all the methods are called in your website. And if you do got url in the JavascriptInterface I think bcz your website is more complex so I will suggest to try to find the real url in the dom tree and pass it using view.loadUrl like this to pass url parameter to the JavascriptInterface. – Shu Zhang Aug 02 '17 at 07:58
7

if you override this method of WebViewClient you will be able to handle url changes, and javascript url changes:

public class YXWebViewClient extends WebViewClient {

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
    super.onPageStarted(view, url, favicon);
    Log.i("Listener", "Start");

}

@Override
public void onPageFinished(WebView view, String url) {
    super.onPageFinished(view, url);
    Log.i("Listener", "Finish");
   }

}

and then in your WebView set the WebViewClient

 yxWebViewClient = new YXWebViewClient();
 webview.setWebViewClient(yxWebViewClient);
Vins
  • 385
  • 4
  • 9
7

I used this method:

webView.setWebChromeClient(new WebChromeClient()
        {
            @Override public void onProgressChanged(WebView view, int newProgress) {
                if (view.getUrl().equals(mUrl))
                {

                }
                else
                {
                    mUrl = view.getUrl();
                    // onUrlChanged(mUrl) // url changed
                }
                super.onProgressChanged(view, newProgress);
            }
        };
);

mUrl is a fields as String...

ultra.deep
  • 1,699
  • 1
  • 19
  • 23
3

Try to use onLoadResource. It will be called at least 1 time even if you are using JS to change your url. But it may be called more than one time, so be careful.

3

Method onPageFinished seems to work at least in modern WebViews.

beefeather
  • 1,040
  • 5
  • 8
3

An implementation of rinkal-bhanderi's answer would look like this:

class MyWebClient(
    private val myCustomMethod: () -> Unit) : WebViewClient() {
  
  override fun shouldOverrideUrlLoading(view: WebView?,
      url: String?): Boolean {
      myCustomMethod()
      return true
    }
  }
}

And you would use it like:

webview.webViewClient = MyWebClient(::hideButton)

Where webview is the actual webview you get from calling FindViewById or the object reference you get from binding. And hideButton is a method accessible in the same scope last expression is evaluated.

RobertoAllende
  • 8,744
  • 4
  • 30
  • 49
2

My requirement was to handle the visibility of a floating button in my page based on the url change.

if url is changing from https/ooooo//login to https/ooooo//homepage it may not be registered in onPageFinished or shouldOverrideUrlLoading. This was the issue I was facing.

I fixed that issue by following method:

@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
    super.doUpdateVisitedHistory(view, url, isReload);
    String currentUrl = view.getUrl();
}

*please don't use url which we are getting with doUpdateVisitedHistory method.That will be the basic url.so go with view.getUrl().

:)

Leo DroidCoder
  • 14,527
  • 4
  • 62
  • 54
XamarinInfo
  • 133
  • 1
  • 8
  • how can i use this function, I tried to implement it, but I got an error: this method doesn't override method from its super superclass?! by the way i tried searching for the method in webview class and couldn’t find it!! – Joseph Ali May 29 '21 at 15:16
  • @JosephAli you should override this method inside of your WebViewClient object – Astrit Veliu Jul 22 '21 at 07:21
1

I had an interesting problem that brought me to this question and happy to provide a solution that may help someone else if they come this way due to a googlebingyahoo search.

mwebVew.reload() would not pick up the new URL I wanted to load once I returned from a preference screen where I either logged on the user or logged off the user. It would update the shared preferences well enough but not update and replace the url web page. So after a few hours of not seeing an answer I tried the following and it worked a real treat.

mWebView.resumeTimers();

Here is the link to the doco if you want more info.

Hope it saves someone else the pain I went through, and happy to have someone tell me I should of implemented it another way.

timv
  • 3,346
  • 4
  • 34
  • 43
1

I had the same problem. So i've solved this problem by overriding public void onPageStarted(WebView view, String url, Bitmap favicon) method as follows:

 webView.setWebViewClient(new WebViewClient(){

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon)
    {
        // Here you can check your new URL.
        Log.e("URL", url);
        super.onPageStarted(view, url, favicon);
    }

 });

Also you can overridepublic void onPageFinished(WebView view, String url) method to get a new URL at the end of page load process.

Rahim Rahimov
  • 1,347
  • 15
  • 24
0

Use WebViewClient.shouldOverrideUrlLoading() when the base/host url changes. Use Use WebViewClient.doUpdateVisitedHistory() method of webview if the base url doesnt change like it happens in single page applications and it detects URL change by javascript which does not lead to a web page reload. @Helin Wang

Raghav Sharma
  • 780
  • 10
  • 18
-1

This will help to detect redirect caused by javascript.

WebViewClient mWebViewClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            view.loadUrl("javascript:window.android.onUrlChange(window.location.href);");            }
    };
    myWebView.setWebViewClient(mWebViewClient);
    }
@JavascriptInterface
public void onUrlChange(String url) {
    Toast.makeText(mContext, "Url redirected",Toast.LENGTH_SHORT).show();
}
Chris Harris
  • 71
  • 2
  • 13