Android 拦截WebView中发生的所有网络通信
我希望能够站在WebView和服务器之间,观察和修改进出的任何数据。这需要在主机应用程序中进行 我想截取所有内容——而不仅仅是表示页面加载的简单GET请求。我希望能够看到所有请求,而不考虑动词,例如由HTML表单触发的POST请求。我想看看重定向 有哪些用例:Android 拦截WebView中发生的所有网络通信,android,webview,android-webview,okhttp3,intercept,Android,Webview,Android Webview,Okhttp3,Intercept,我希望能够站在WebView和服务器之间,观察和修改进出的任何数据。这需要在主机应用程序中进行 我想截取所有内容——而不仅仅是表示页面加载的简单GET请求。我希望能够看到所有请求,而不考虑动词,例如由HTML表单触发的POST请求。我想看看重定向 有哪些用例: 将附加头附加到请求 从响应中读取标题 针对每个请求的证书固定 我已经阅读了所有我能在网上找到的东西。我的结论是,没有任何自定义WebView实现可以插入到我的应用程序中并满足我的需要。到目前为止,我最接近的方法是使用WebViewCl
- 将附加头附加到请求
- 从响应中读取标题
- 针对每个请求的证书固定
@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;
}
@覆盖
公共WebResourceResponse应InterceptRequest(最终WebView视图,字符串url){
Log.d(Constants.Tags.WEBVIEW_客户端,“WV请求(旧)”+url);
返回processRequest(url);
}
@凌驾
@塔吉塔皮(21)
公共WebResourceResponse应该InterceptRequest(最终WebView视图,WebResourceRequest
截取请求){
Log.d(Constants.Tags.WEBVIEW_客户端,“WV请求(新)”+interceptedRequest.getUrl
().toString()+“”+interceptedRequest.getMethod());
返回processRequest(interceptedRequest);
}
@RequiresApi(api=Build.VERSION\u code.LOLLIPOP)
私有WebResourceResponse processRequest(WebResourceRequest ir){
如果(!“GET”.equals(ir.getMethod())){
Log.d(Constants.Tags.WEBVIEW_客户端,“忽略”+ir.getMethod()+“”+ir.getUrl());
返回null;
}
返回processRequest(ir.getUrl().toString());
}
私有WebResourceResponse processRequest(字符串url){
Request Request=newrequest.Builder().url(url.build();
试一试{
返回processResponse(okHttpClient.newCall(request.execute());
}捕获(SSLhandE){
Log.d(Constants.Tags.WEBVIEW_客户端,“SSLHandshakeException:+e.getMessage());
}捕获(IOE异常){
Log.d(Constants.Tags.WEBVIEW_客户端,“IOException:+e.getMessage());
e、 printStackTrace();
}
返回null;
}
私有WebResourceResponse processResponse(响应){
字符串contentType=response.body().contentType().toString();
if(contentType!=null){
字符串mimeType=contentType;
if(contentType.contains(“;”){
mimeType=contentType.split(“;”)[0]。trim();
}
WebResourceResponse WebResourceResponse=新的WebResourceResponse(mimeType,response
.header(“内容编码”、“utf-8”)
,response.body().byteStream());
如果(Build.VERSION.SDK_INT>21){
webResourceResponse.setResponseHeaders(convertHeaders(response.headers());
webResourceResponse.setStatusCodeAndReasonPhrase(response.code(),“无论什么”);
}
返回webResourceResponse;
}
返回null;
}
私有映射头(头){
Map Map=newhashmap();
对于(int i=0;i
OkHttpClient:
public static OkHttpClient getNewHttpClient() {
CertificatePinner.Builder certPinnerBuilder = new CertificatePinner.Builder();
for (Map.Entry<String, String> entry : THUMB_PRINTS.entrySet()) {
certPinnerBuilder.add(entry.getKey(), entry.getValue());
}
CertificatePinner certPinner = certPinnerBuilder.build();
OkHttpClient.Builder client = new OkHttpClient.Builder()
.certificatePinner(certPinner)
.addNetworkInterceptor(new AdditionalHeaderInterceptor())
.followRedirects(false)
.followSslRedirects(false)
.retryOnConnectionFailure(true)
.connectTimeout(Constants.REQUEST_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(Constants.REQUEST_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(Constants.REQUEST_TIMEOUT, TimeUnit.SECONDS)
.cache(null);
return enableTls12OnPreLollipop(client).build();
}
public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, null);
client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build();
List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
specs.add(ConnectionSpec.COMPATIBLE_TLS);
specs.add(ConnectionSpec.CLEARTEXT);
client.connectionSpecs(specs);
} catch (Exception exc) {
Log.e(Constants.Tags.GENERAL, "Error while setting TLS 1.2", exc);
}
}
return client;
}
publicstaticokhttpclient getNewHttpClient(){
CertificatePaner.Builder certPinnerBuilder=新的CertificatePaner.Builder();
对于(Map.Entry:THUMB\u PRINTS.entrySet()){
添加(entry.getKey(),entry.getValue());
}
CertificatePaner certPinner=certPinnerBuilder.build();
OkHttpClient.Builder client=新的OkHttpClient.Builder()
.CertificatePaner(certPinner)
.addNetworkInterceptor(新的AdditionalHeaderInterceptor())
.followRedirects(false)
.followslRedirects(false)
.retryOnConnectionFailure(真)
.connectTimeout(常数.REQUEST\u TIMEOUT,TimeUnit.SECONDS)
.readTimeout(常数.REQUEST\u TIMEOUT,TimeUnit.SECONDS)
.writeTimeout(常数.REQUEST\u超时,时间单位.SECONDS)
.cache(空);
返回enabletls12onprellollipop(client.build();
}
公共静态OkHttpClient.Builder启用TLS12ONPLELOLLIPOP(OkHttpClient.Builder客户端){
if(Build.VERSION.SDK_INT>=16&&Build.VERSION.SDK_INT<22){
试一试{
SSLContext sc=SSLContext.getInstance(“TLSv1.2”);
sc.init(null,null,null);
client.sslSocketFactory(新的Tls12SocketFactory(sc.getSocketFactory());
ConnectionSpec cs=新的ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.TlsVersion(TlsVersion.TLS_1_2)
.build();
列表规格=新的ArrayList();
增加规格(cs);
规格添加(连接规格兼容);
规范添加(连接规范明文);
客户连接规范(规范);
}捕获(异常exc){
Log.e(Constants.Tags.GENERAL,“设置TLS 1.2时出错”,exc);
}
}
返回客户;
}
你为什么要把问题贴两次@史蒂文:这个问题试图解决我的实际问题:拦截所有WebView通信,而另一个问题集中在处理WebView中的重定向。相同的代码片段,不同的焦点。