英文:
WebViewClient.shouldOverrideUrlLoading() documentation clarification
问题
关于仅适用于API级别 24+ 的 shouldOverrideUrlLoading 版本,文档明确指出:
注意: 不要使用请求的URL调用WebView#loadUrl(String),然后返回true。这样会不必要地取消当前加载并以相同的URL开始新的加载。继续加载给定URL的正确方法是只需返回false,而不调用WebView#loadUrl(String)。
然而,在我的应用程序中,我必须在加载URL之前执行一些额外的活动,这些活动只能在MyWebView#loadUrl(String)中完成,因此我在MyWebViewClient#shouldOverrideUrlLoading中调用MyWebView#loadUrl
,然后返回true;
。
这似乎运行正常,但现在我有一些疑虑:
这个关于“继续加载给定URL的正确方法”的警告是否意味着,如果我不遵循它,这段代码可能会在以下情况下出现问题:
- 未来会出现问题(比如“使用未记录的内部API”)
- 或者现在在某些“异常的网站”上出现问题?
在什么情况下(例如框架、iframe、301/302重定向)这种return true;
方案可能会破坏正确的URL加载?
英文:
Referring to the API level 24+ only version of shouldOverrideUrlLoading, the documentation clearly states:
> Note: Do not call WebView#loadUrl(String) with the request's URL and
> then return true. This unnecessarily cancels the current load and
> starts a new load with the same URL. The correct way to continue
> loading a given URL is to simply return false, without calling
> WebView#loadUrl(String).
However, in my app I have to perform some extra activities before loading the URL that could only be done in MyWebView#loadUrl(String) and so I do call MyWebView#loadUrl
from within MyWebViewClient#shouldOverrideUrlLoading
then return true;
.
This seems to work fine but I now have some doubts:
Does this warning about "the correct way to continue loading a given URL" mean that if I am not following it, this code could break
- in the future (as in "using undocumented internal API")
- or break now with some "unusual website"?
In what scenarios (e.g. frames, iframes, 301/302 redirects) this return true;
scheme could break proper URL loading?
答案1
得分: 1
只要URL是有效的且符合RFC 3986标准,你的方法不太可能直接与普通URL发生冲突。
在shouldOverrideUrlLoading
中调用loadURL
的主要问题是它会使你的应用程序效率低下,导致过多的网络流量(在大多数情况下是不必要的,除非你实际上要修改URL或根据某种自定义输入格式调用不同的网页)。
可以重新表述为:"如果你在shouldOverrideUrlLoading
中不修改URL,那就不要再次调用loadURL
。"
基本上,当你不需要时,你正在两次发起网络请求。
关于从shouldOverrideUrlLoading
返回true
,示例中列出了一种情况,他们返回true
,因为需要修改输入URL,因为他们使用了自定义格式,需要以不同方式处理。
// URL方案应该是非层次结构的(不带尾斜杠)
private static final String APP_SCHEME = "example-app:";
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(APP_SCHEME)) {
urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
respondToData(urlData);
return true;
}
return false;
}
在上面的示例中,他们之所以重写行为,是因为他们使用了自定义格式:<a href="example-app:showProfile">
因此,应用程序会说:"这是一个奇怪的自定义开发者定义的格式,而不是普通的URL,因此应用程序应该使用这个自定义的respondToData(urlData);
"
在WebView中可能会遇到的问题类似于这个问题,在该问题中,你创建了自定义URL,但WebView的实现期望的是不同的东西(即,基于Web标准的有效URL)。
如果你使用自定义URL方案或不符合RFC 3986标准的基本URL,可能会在这些情况下无法正确触发shouldOverrideUrlLoading()
回调。
如果你没有预期的话,还可能会遇到URI规范化的问题。
只要框架、内嵌框架和/或301/302重定向表示有效的URL地址和格式,就不应该出现问题。但在这些情况下,只要你不在shouldOverrideUrlLoading
中更改URL或使用某种自定义响应URL的方式,就不需要再次调用WebView#loadURL
。
英文:
Based on Handle Custom URLs portion of WebView docs
It is unlikely that your method will directly break with normal URLs as long as they're valid URLs that conform to RFC 3986.
The primary concern with calling loadURL
inside shouldOverrideUrlLoading
is it makes your app inefficient and leads to excessive web traffic (and in most cases is unnecessary if you're not actually modifying the URL or calling a different web page based on some kind of custom input format.
A way to rephrase would be to say, "If you're not changing the URL in shouldOverrideUrlLoading
, then don't call loadURL
again."
Basically, you're calling a web request twice when you don't need to.
In terms of returning true from shouldOverrideUrlLoading
, the examples list a case where they return true
because modification of the input URL was necessary, since they're using a custom format, that needs to be handled differently.
// The URL scheme should be non-hierarchical (no trailing slashes)
private static final String APP_SCHEME = "example-app:";
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(APP_SCHEME)) {
urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
respondToData(urlData);
return true;
}
return false;
}
In the above example, they're only overriding the behavior because they're using a custom format: <a href="example-app:showProfile">
So the app says "its this weird custom developer defined format, rather than a normal URL, so the app should instead use this custom respondToData(urlData);
"
The issues you run into with WebView are like this question where you make your own custom URL, except then the implementation of WebView expects something different (namely, a valid URL based on web standards)
This can be especially tricky if you are using a custom URL scheme or a base URL, that is not a valid URL that conforms to RFC 3986. In those cases you may not properly trigger the shouldOverrideUrlLoading()
callback.
You can also run into issues with URI Normalization if you're not expecting that behavior.
As long as frames, iframes, and/or 301/302 redirects represent valid URL addresses and formats, then there should not be an issue. However, in those cases, as long as you're not changing the URL within shouldOverrideUrlLoading
or using some type of custom response to the URL, then you don't need to call WebView#loadURL
again.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论