149

Is "shouldOverrideUrlLoading" really deprecated? If so, what can I use instead?

It seems like shouldOverrideUrlLoading is deprecated targeting Android N and I need to make an app work since API 19 until the latest right now which is Android N (beta), I use some features that are new in Android N (like Data Saver), so targeting Marshmallow will not help with the issue since I need to use those new features, here is the part of the code I use:

public boolean shouldOverrideUrlLoading(WebView webview, String url) {
    if (url.startsWith("http:") || url.startsWith("https:")) {
        ...
    } else if (url.startsWith("sms:")) {
        ...
    }
    ...
}

And this is the message Android Studio gave me:

Overrides deprecated method in 'android.webkit.WebViewClient' This inspection reports where deprecated code is used in the specified inspection scope.

Google says nothing about that deprecation.

I wonder if using @SuppressWarnings("deprecation") will let me work on all devices since the API 19 until the latest Android N Beta (and its final version when it gets released), I can't test it myself, I never used that and I need to be sure that it works, so, anyone can tell?

Henry
  • 16,294
  • 7
  • 56
  • 86
Minion
  • 2,287
  • 3
  • 23
  • 28
  • 2
    There are two versions of that callback method. The old one is deprecated. In this case, "deprecated" means "hey, we have something else that you might want to try, if it's appropriate for you". The old callback should continue to work, as the old callback is required for pre-N versions of Android. – CommonsWare Apr 07 '16 at 18:13
  • First, thanks for the comment, the version I'm using I think is the good one, since is the exact same as the Android Developer Docs, except for the name of the string, they used "view" and I used "webview", for the rest is te same, so why should I do to make it work on all versions? – Minion Apr 07 '16 at 18:30

4 Answers4

200

Documenting in detail for future readers:

The short answer is you need to override both the methods. The shouldOverrideUrlLoading(WebView view, String url) method is deprecated in API 24 and the shouldOverrideUrlLoading(WebView view, WebResourceRequest request) method is added in API 24. If you are targeting older versions of android, you need the former method, and if you are targeting 24 (or later, if someone is reading this in distant future) it's advisable to override the latter method as well.

The below is the skeleton on how you would accomplish this:

class CustomWebViewClient extends WebViewClient {

    @SuppressWarnings("deprecation")
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        final Uri uri = Uri.parse(url);
        return handleUri(uri);
    }

    @TargetApi(Build.VERSION_CODES.N)
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        final Uri uri = request.getUrl();
        return handleUri(uri);
    }

    private boolean handleUri(final Uri uri) {
        Log.i(TAG, "Uri =" + uri);
        final String host = uri.getHost();
        final String scheme = uri.getScheme();
        // Based on some condition you need to determine if you are going to load the url 
        // in your web view itself or in a browser. 
        // You can use `host` or `scheme` or any part of the `uri` to decide.
        if (/* any condition */) {
            // Returning false means that you are going to load this url in the webView itself
            return false;
        } else {
            // Returning true means that you need to handle what to do with the url
            // e.g. open web page in a Browser
            final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            startActivity(intent);
            return true;
        }
    }
}

Just like shouldOverrideUrlLoading, you can come up with a similar approach for shouldInterceptRequest method.

Henry
  • 16,294
  • 7
  • 56
  • 86
  • 3
    It's better to use [`@RequiresApi`](https://developer.android.com/reference/android/support/annotation/RequiresApi.html) in stead of @TargetApi here for future use – Hibbem Nov 02 '16 at 12:09
  • @Henry getUrl() is required minimum API level 21 so how to we deal with lower version API – Garg's Dec 20 '16 at 14:29
  • @Garg's Why do you need `getUrl()`? For lower version, you will directly get the Url as String in the `shouldOverrideUrlLoading(WebView view, String url)` method. You can get a `Uri` from this url. – Henry Dec 20 '16 at 15:10
  • Or you can pass the view to the handleUri() method and then get context from it using view.getContext() method – gonephishing Mar 17 '17 at 23:30
  • 1
    The problem with overriding both methods, at least with `shouldInterceptRequest`, is that on Android N+ devices they are *both* invoked and you'll be handling each uri twice! To remedy that, I added a `Build.VERSION.SDK_INT < Build.VERSION_CODES.N` condition in the deprecated version. – Jonik Jun 07 '17 at 10:19
  • can anyone confirm what @Jonik said applies to `shouldOverrideUrlLoading`? – Maria Jul 09 '17 at 08:50
  • 9
    @JohnLee Normally only one of the methods will be invoked. But if you were to put `super. shouldOverrideUrlLoading(view,request)` in the non-deprecated method, then yes both the non-deprecated and the deprecated method will be invoked. This is because the default implementation of the non-deprecated method is to internally invoke the deprecated method. Just take a look at the `WebViewClient.shouldOverrideUrlLoading(WebView view, WebResourceRequest request)`. So make sure that you don't call `super.shouldOverrideUrlLoading()`. – Henry Jul 09 '17 at 15:44
  • @Henry I am not sure we want to depend on that functionality. It is not documented so it could possibly change in a future release. – Austyn Mahoney Jul 13 '17 at 00:00
  • @AustynMahoney I didn't say we have to depend on the internal implementation. The answer above doesn't depend on the internal implementation. I cited that to explain why sometimes both the deprecated and non-deprecated methods will be invoked in the latest API version. The goal is to override both methods and ensuring only one of them is invoked. I am sorry if I caused any misunderstanding – Henry Jul 13 '17 at 05:31
  • 1
    Just pointing out that the functionality of having both methods called is not documented. I wouldn't rely on that always being the case since it is not mentioned in the documentation. – Austyn Mahoney Jul 18 '17 at 22:11
  • A really provident answer. – Kirill Starostin Aug 27 '18 at 09:33
  • 2
    To add to the discussion, I have tried the code on Pie and only one of the methods was called. – Subhrajyoti Sen Dec 18 '18 at 09:45
  • This works fine, but when the link get opened in the browser, the webview become white screen, how can I fix that? – Bouh Nov 17 '20 at 12:12
102

The version I'm using I think is the good one, since is the exact same as the Android Developer Docs, except for the name of the string, they used "view" and I used "webview", for the rest is the same

No, it is not.

The one that is new to the N Developer Preview has this method signature:

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)

The one that is supported by all Android versions, including N, has this method signature:

public boolean shouldOverrideUrlLoading(WebView view, String url)

So why should I do to make it work on all versions?

Override the deprecated one, the one that takes a String as the second parameter.

akhilesh0707
  • 5,244
  • 4
  • 34
  • 44
CommonsWare
  • 910,778
  • 176
  • 2,215
  • 2,253
  • Hello, and thanks for the answer, that still not compatible since API 19, because to get the URL string I have to use "url.getUrl().toString()" and it has been added on API 21, any way to make it work since API 19? – Minion Apr 07 '16 at 18:55
  • 3
    @Minion: "that still not compatible since API 19" -- yes, it is. "because to get the URL string I have to use "url.getUrl().toString()"" -- no, the URL is provided as the second parameter, in the form of a `String`. For example, [this sample app](https://github.com/commonsguy/cw-omnibus/tree/master/WebKit/Browser4), compiled against API Level 19, works fine, such as on an Android 6.0-powered Nexus 5. – CommonsWare Apr 07 '16 at 19:01
  • Hello, using the "WebResourceRequest request" does not have a String parameter – Minion Apr 07 '16 at 19:03
  • 2
    @Minion: Correct. That only works on Android N (and, presumably, higher). You asked "so why should I do to make it work on all versions?". I told you to override the deprecated one, the one that takes a `String` as the second parameter. For example, the sample app that I linked to, which overrides the deprecated callback, works fine on a Nexus 6 running the N Developer Preview 1. – CommonsWare Apr 07 '16 at 19:06
  • Thanks a lot for your help :) – Minion Apr 07 '16 at 19:58
  • 6
    If you want to be future-proof, you could actually override BOTH methods. That way your app will continue to work on < 21, but you'll be ready to go once they do fully deprecate the old method. And you won't have to worry about `getUrl()` because the new method will only be called for 24+ – yuval Oct 08 '16 at 01:23
  • @SuppressWarnings("deprecations") – Michael Jul 06 '17 at 20:27
  • @SuppressWarnings("deprecation") rather – Michael Jul 06 '17 at 20:38
  • As @yuval said, override both. Annotate the new one with TargetApi(androidN) and the old one with SuppressWarnings and your tools should be happy. – Snicolas Oct 19 '17 at 19:04
19

Use

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
Vlad
  • 5,448
  • 2
  • 43
  • 39
Saleem Kalro
  • 882
  • 8
  • 11
0

Implement both deprecated and non-deprecated methods like below. First one is to handle API level 21 and higher, second one is handle lower than API level 21

webViewClient = object : WebViewClient() {
.
.
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
            parseUri(request?.url)
            return true
        }

        @SuppressWarnings("deprecation")
        override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
            parseUri(Uri.parse(url))
            return true
        }
}
emre
  • 57
  • 1
  • 8
  • 1
    This appears to be a partial copy of Henry's answer, but this discards the value returned by `Uri.parse` and `parseUri`. New answers should add useful new information and new insights into the topic. – AdrianHHH Jul 25 '19 at 10:40
  • Made me lose time since api is only deprecated on API 24 and not 21 – Gustavo Baiocchi Costa Sep 12 '19 at 11:16