拦截WebView

时间:2017-10-08 23:06:50

标签: android webview android-webview okhttp3 intercept

我希望能够站在WebView和服务器之间,观察和修改任何进出的数据。这需要在主机应用程序中发生

我想拦截一切 - 不仅仅是代表页面加载的简单GET请求。我希望能够查看所有请求,无论动词如何,例如HTML表单触发的POST请求。我想看到重定向。

有什么用例:

  • 将附加标题附加到请求
  • 阅读回复标题
  • 每个请求的证书固定

我已经阅读了我在网上找到的所有内容。我的结论是,没有自定义的WebView实现,我可以插入我的应用程序并满足我的需求。我到目前为止最接近的是使用WebViewClient.shouldInterceptRequest。我自己在一个自定义的HTTP客户端(OkHttpClient)中执行请求,并将响应返回给WebView。

这不起作用的一些关键原因:无法处理在HTML中执行的请求;即使我设法处理它们,当它是POST时我也无法抓住请求体;我无法处理重定向。最后一点在another question by me扩展。

I read that shouldInterceptRequest was never intended for full network communication interception。 目前我在问我是否可以在其他地方插入我的HTTP客户端,这样我就不会打扰WebView的功能。

这是我的代码:

WebViewClient:

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

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

0 个答案:

没有答案