“shouldOverrideUrlLoading”真的已经被弃用了吗?我应该使用什么替代品?

171

“shouldOverrideUrlLoading”是否真的已弃用?如果是,我应该使用什么替代方法?

看起来“shouldOverrideUrlLoading”已被弃用,针对Android N,而我需要使一个应用程序可以在API 19上工作,并一直持续到最新版本即Android N(beta版)。我使用了一些在Android N中新的功能(如数据节省),因此以Marshmallow为目标将无法解决此问题,因为我需要使用这些新功能。以下是我使用的代码部分:

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

这是Android Studio给我的信息:

覆盖了'android.webkit.WebViewClient'中已弃用的方法 此检查报告指定检查范围内使用了废弃代码的位置。

Google没有提到该被弃用的内容

我想知道是否使用@SuppressWarnings("deprecation")可以让我在所有设备上工作,从API 19到最新的Android N Beta(以及其发布的最终版本),我无法自己测试它,我从未使用过它,我需要确保它可以正常工作,所以,有人可以告诉我吗?


2
那个回调方法有两个版本。旧的已经被弃用了。在这种情况下,“废弃”意味着“嘿,我们有另一种你可能想尝试的东西,如果适合你的话”。旧的回调应该继续工作,因为旧的回调是必需的,针对 Android 版本 N 之前的系统。 - CommonsWare
首先,感谢您的评论。我认为我使用的版本是正确的,因为它与Android开发者文档完全相同,除了字符串的名称不同。他们使用了“view”,而我使用了“webview”。所以,我应该怎么做才能让它在所有版本上都能正常工作呢? - Minion
5个回答

223

详细记录供日后读者参考:

简短回答是您需要覆盖两种方法。在 API 24 中,shouldOverrideUrlLoading(WebView view,String url) 方法已经过时,并添加了 shouldOverrideUrlLoading(WebView view,WebResourceRequest request) 方法。如果您的目标是旧版 Android,则需要使用前一种方法。如果您的目标版本是 24(或更高版本,如果有人在遥远的未来读到这篇文章),建议您同时覆盖后一种方法。

以下是如何实现此操作的框架:

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;
        }
    }
}

就像shouldOverrideUrlLoading方法一样,你可以为shouldInterceptRequest方法构想出类似的方法。


6
为了将来的使用,最好使用@RequiresApi而不是@TargetApi - Hibbem
2
覆盖两种方法的问题,至少在shouldInterceptRequest方面,是在Android N+设备上它们都被调用,你将处理每个URI两次!为了解决这个问题,在弃用版本中添加了一个Build.VERSION.SDK_INT < Build.VERSION_CODES.N条件。 - Jonik
9
通常只会调用其中一种方法。但是如果您将 super.shouldOverrideUrlLoading(view, request) 放在非弃用的方法中,那么这两种方法都将被调用。这是因为非弃用方法的默认实现是内部调用弃用方法。请查看WebViewClient.shouldOverrideUrlLoading(WebView view, WebResourceRequest request)。因此,请确保不要调用 super.shouldOverrideUrlLoading() - Henry
1
@AustynMahoney 我并没有说我们必须依赖于内部实现。上面的答案并不依赖于内部实现。我引用它来解释为什么有时候在最新的API版本中会调用弃用和非弃用方法。目标是覆盖这两个方法并确保只调用其中一个。如果我造成了任何误解,我很抱歉。 - Henry
2
为了增加讨论,我已经在Pie上尝试了这段代码,只有其中一种方法被调用。 - Subhrajyoti Sen
显示剩余8条评论

112

我认为我使用的版本是好的,因为它与Android开发者文档完全相同,除了字符串名称,他们使用了“view”,而我使用了“webview”,其他方面都是相同的。

不,它不是。

在N Developer Preview中新增加的方法签名如下:

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)

这个方法在所有 Android 版本中都被支持,包括 N 版本,方法签名如下:

public boolean shouldOverrideUrlLoading(WebView view, String url)

那么我该怎么做才能使它在所有版本上都能正常工作?

覆盖那个被弃用的方法,即第二个参数采用 String 的方法。


3
@Minion:“那还不兼容API 19”。 不,它是兼容的。 “因为我必须使用"url.getUrl().toString()"来获取URL字符串” - 不是这样的。 URL以第二个参数的形式提供,作为一个字符串。例如,对于针对API Level 19编译的此示例应用程序,在Android 6.0驱动的Nexus 5上工作得很好。 - CommonsWare
2
@Minion:正确。这仅适用于Android N(以及可能更高版本)。你问:“那我该怎么做才能让它在所有版本上都能工作?”我告诉你要覆盖已弃用的方法,即将String作为第二个参数的方法。例如,我链接的示例应用程序覆盖了已弃用的回调,在运行N Developer Preview 1的Nexus 6上可以正常工作。 - CommonsWare
6
如果你想保证未来兼容性,你可以同时重写两种方法。这样你的应用程序将在 Android 版本小于21时继续工作,但一旦旧方法被完全废弃,你就已经做好了准备。而且你也不需要担心 getUrl(),因为新方法只会在Android 24及以上版本中调用。 - yuval
@SuppressWarnings("deprecations") - Michael
@SuppressWarnings("deprecation") - Michael
显示剩余4条评论

22

使用

public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    return shouldOverrideUrlLoading(view, request.getUrl().toString());
}

2
它是view.loadUrl(request.getUrl().toString()); - Hibbem
它可以工作,但如果我们使用返回键,它将关闭应用程序。 - MRRaja
4
这将不支持低于21的API。 - mumair

1

实现如下所示的已弃用和非已弃用方法。第一个是处理API级别21及更高版本,第二个是处理低于API级别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
        }
}

1
这似乎是 Henry 回答的部分副本,但它丢弃了 Uri.parseparseUri 返回的值。新的回答应该添加有用的新信息和对主题的新见解。 - AdrianHHH
让我浪费了时间,因为API仅在API 24上被弃用,而不是在21上。 - Gustavo Baiocchi Costa

1

截至2023年,使用此方法来解决问题:

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        return false;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接