Is `shouldOverrideUrlLoading` really deprecated? What can I use instead?
Asked Answered
L

5

174

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?

Lenoir answered 7/4, 2016 at 18:11 Comment(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.Spew
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?Lenoir
S
113

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.

Spew answered 7/4, 2016 at 18:47 Comment(11)
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?Lenoir
@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, compiled against API Level 19, works fine, such as on an Android 6.0-powered Nexus 5.Spew
Hello, using the "WebResourceRequest request" does not have a String parameterLenoir
@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.Spew
Thanks a lot for your help :)Lenoir
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+Carlie
@SuppressWarnings("deprecations")Exhortation
@SuppressWarnings("deprecation") ratherExhortation
As @Carlie said, override both. Annotate the new one with TargetApi(androidN) and the old one with SuppressWarnings and your tools should be happy.Wills
I am targeting API 28 (P) Is it safe to only override the non-deprecated method?Lightfooted
@MahNas92: I believe soSpew
D
225

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.

Detrital answered 20/7, 2016 at 14:28 Comment(13)
It's better to use @RequiresApi in stead of @TargetApi here for future useOwensby
@Detrital getUrl() is required minimum API level 21 so how to we deal with lower version APIGlockenspiel
@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.Detrital
Or you can pass the view to the handleUri() method and then get context from it using view.getContext() methodLassie
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.Fullblown
can anyone confirm what @Fullblown said applies to shouldOverrideUrlLoading?Stir
@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().Detrital
@Detrital I am not sure we want to depend on that functionality. It is not documented so it could possibly change in a future release.Aroma
@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 misunderstandingDetrital
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.Aroma
A really provident answer.Smack
To add to the discussion, I have tried the code on Pie and only one of the methods was called.Carbazole
This works fine, but when the link get opened in the browser, the webview become white screen, how can I fix that?Saunderson
S
113

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.

Spew answered 7/4, 2016 at 18:47 Comment(11)
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?Lenoir
@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, compiled against API Level 19, works fine, such as on an Android 6.0-powered Nexus 5.Spew
Hello, using the "WebResourceRequest request" does not have a String parameterLenoir
@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.Spew
Thanks a lot for your help :)Lenoir
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+Carlie
@SuppressWarnings("deprecations")Exhortation
@SuppressWarnings("deprecation") ratherExhortation
As @Carlie said, override both. Annotate the new one with TargetApi(androidN) and the old one with SuppressWarnings and your tools should be happy.Wills
I am targeting API 28 (P) Is it safe to only override the non-deprecated method?Lightfooted
@MahNas92: I believe soSpew
A
23

Use

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
Amoretto answered 9/7, 2016 at 19:49 Comment(3)
it's view.loadUrl(request.getUrl().toString());Owensby
its work but if we use back then it will close the appMinima
this wouldn't support api less than 21Mien
M
1

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
        }
}
Melanie answered 25/7, 2019 at 10:16 Comment(2)
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.Perfumer
Made me lose time since api is only deprecated on API 24 and not 21Risa
P
1

As of 2023, use this to fix the problem:

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        return false;
    }
}
Portcullis answered 21/4, 2023 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.