我试图拦截进出主机应用程序内WebView的所有网络通信。我的尝试集中在WebViewClient提供的两个shouldInterceptRequest方法:
@Override
public WebResourceResponse shouldInterceptRequest(final WebView view, String url) {
Log.d(Constants.Tags.WEBVIEW_CLIENT, "WV REQUEST (OLD) " + url);
return processRequest(url);
}
@Override
@TargetApi(21)
public WebResourceResponse shouldInterceptRequest(final WebView view, WebResourceRequest
interceptedRequest) {
Log.d(Constants.Tags.WEBVIEW_CLIENT, "WV REQUEST (NEW) " + interceptedRequest.getUrl
().toString() + " " + interceptedRequest.getMethod());
return processRequest(interceptedRequest);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private WebResourceResponse processRequest(WebResourceRequest ir) {
if (!"GET".equals(ir.getMethod())) {
Log.d(Constants.Tags.WEBVIEW_CLIENT, "IGNORING " + ir.getMethod() + " " + ir.getUrl());
return null;
}
return processRequest(ir.getUrl().toString());
}
private WebResourceResponse processRequest(String url) {
Request request = new Request.Builder().url(url).build();
try {
return processResponse(okHttpClient.newCall(request).execute());
} catch (SSLHandshakeException e) {
Log.d(Constants.Tags.WEBVIEW_CLIENT, "SSLHandshakeException: " + e.getMessage());
} catch (IOException e) {
Log.d(Constants.Tags.WEBVIEW_CLIENT, "IOException: " + e.getMessage());
e.printStackTrace();
}
return null;
}
private WebResourceResponse processResponse(Response response) {
String contentType = response.body().contentType().toString();
if (contentType != null) {
String mimeType = contentType;
if (contentType.contains(";")) {
mimeType = contentType.split(";")[0].trim();
}
WebResourceResponse webResourceResponse = new WebResourceResponse(mimeType, response
.header("content-encoding", "utf-8")
, response.body().byteStream());
if (Build.VERSION.SDK_INT > 21) {
webResourceResponse.setResponseHeaders(convertHeaders(response.headers()));
webResourceResponse.setStatusCodeAndReasonPhrase(response.code(),"whatever");
}
return webResourceResponse;
}
return null;
}
private Map<String, String> convertHeaders(Headers headers) {
Map<String, String> map = new HashMap<>();
for (int i = 0; i < headers.size(); i++) {
map.put(headers.name(i), headers.value(i));
}
return map;
}
为了使这个成为可行的解决方案,我试图将所有标头和响应代码附加到API级别21或更高级别的WebResourceResponse对象上。 我认为这是不可能做到的原因之一,即使我跳过除GET请求之外的任何事情都是不支持拦截重定向的事实。这两种方式都是有效的:应用程序 - &gt; Webview和WebView - &gt;应用。
摘自WebResourceResponse的文档,关于setStatusCodeAndReasonPhrase中状态代码参数的值:
int:状态代码需要在[100,299],[400,599]范围内。 不支持通过指定3xx代码导致重定向。
我设法通过绕过带有反射的受监视的setter来获取响应代码302以在Lollipop或更新的浏览器上工作。这仅对应用程序有效 - &gt; WebView,因为WebView不会向WebViewClient确认它正在执行重定向请求(在我传回hacky 302 WebResourceResponse之后的下一步)。只是没有为该请求调用shouldInterceptRequest。
我不打算用最初的意图打扰任何人。我只是想知道为什么现代WebView不支持重定向?到目前为止,我正在得出的结论是,原因是与4.4之前的WebView提供程序兼容(可能不是基于Chromium的)。但是,这没有多大意义:我根本无法在5.0以下的Android版本上调用setStatusCodeAndReasonPhrase。
非常感谢任何反馈。