Android拦截并获取WebView内部POST请求参数

最开始想到的方案是直接拦截H5中所有的请求:

1
2
3
4
5
6
webView.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

}
});

但是通过此方法只能获取Get请求的参数(因为参数直接拼在URL链接中),对于Post请求的参数无可奈何

参考:https://github.com/KonstantinSchubert/request_data_webviewclient
参考:https://github.com/KeejOow/android-post-webview
参考:https://www.cnblogs.com/lanxingren/archive/2019/04/12/10697106.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public class MainActivity extends AppCompatActivity {

private String mUrl;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StatusBarUtil.setLightMode(this);
StatusBarUtil.setTransparent(this);
StatusBarUtil.setColor(this, Color.WHITE, 0);
mLinearLayout = this.findViewById(R.id.container);
mUrl = "https://checkout.appblog.cn/xxxxxx";
initView();
}

private void initView() {
Map<String, String> webviewHeader =new HashMap<>();
//此方法无效
webviewHeader.put("Referer", "www.appblog.cn");
webviewHeader.put("referrer", "www.appblog.cn");

WebView webView = findViewById(R.id.web_view);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
webSettings.setDomStorageEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setAppCacheEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setSavePassword(true);
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webSettings.setUseWideViewPort(true);

webView.setWebViewClient(new WriteHandlingWebViewClient(webView) {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WriteHandlingWebResourceRequest request) {
String url = request.getUrl().toString();
Log.i("yezhou", request.getUrl().toString());
if (url.contains("gateway")) {
return getNewResponse(request);
} else {
return super.shouldInterceptRequest(view, request);
}
}

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();
}
});

webView.loadUrl(mUrl, webviewHeader);
}

private WebResourceResponse getNewResponse(WriteHandlingWebResourceRequest resourceRequest) {
try {
OkHttpClient httpClient = new OkHttpClient();
String url = resourceRequest.getUrl().toString();

Request.Builder builder = new Request.Builder();
//Request request = new Request.Builder()
builder.url(url.trim());
if (url.contains("gateway")) {
builder.addHeader("referrer", "testpay.th.jiaozifin.com"); // Example header
}
if ("POST".equalsIgnoreCase(resourceRequest.getMethod())) {
builder.post(RequestBody.create(resourceRequest.getAjaxData().getBytes()));
}
Request request = builder.build();

Response response = httpClient.newCall(request).execute();

return new WebResourceResponse(
null,
response.header("content-encoding", "utf-8"),
response.body().byteStream()
);

} catch (Exception e) {
return null;
}

}
}

AjaxInterceptJavascriptInterface.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.io.IOException;
import org.jsoup.Jsoup;

import android.content.Context;
import android.webkit.JavascriptInterface;

class AjaxInterceptJavascriptInterface {

private static String interceptHeader = null;
private WriteHandlingWebViewClient mWebViewClient = null;

public AjaxInterceptJavascriptInterface(WriteHandlingWebViewClient webViewClient) {
mWebViewClient = webViewClient;
}

public static String enableIntercept(Context context, byte[] data) throws IOException {
if (interceptHeader == null) {
interceptHeader = new String(
Utils.consumeInputStream(context.getAssets().open("interceptheader.html"))
);
}

org.jsoup.nodes.Document doc = Jsoup.parse(new String(data));
doc.outputSettings().prettyPrint(true);

// Prefix every script to capture submits
// Make sure our interception is the first element in the
// header
org.jsoup.select.Elements element = doc.getElementsByTag("head");
if (element.size() > 0) {
element.get(0).prepend(interceptHeader);
}

String pageContents = doc.toString();
return pageContents;
}

@JavascriptInterface
public void customAjax(final String ID, final String body) {
mWebViewClient.addAjaxRequest(ID, body);
}
}

Utils.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

class Utils {

static byte[] consumeInputStream(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
for (int count; (count = inputStream.read(buffer)) != -1; ) {
byteArrayOutputStream.write(buffer, 0, count);
}
return byteArrayOutputStream.toByteArray();
}
}

WriteHandlingWebResourceRequest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import android.net.Uri;
import android.webkit.WebResourceRequest;
import java.util.Map;

public class WriteHandlingWebResourceRequest implements WebResourceRequest {
final private Uri uri;
final private WebResourceRequest originalWebResourceRequest;
final private String requestBody;

WriteHandlingWebResourceRequest(
WebResourceRequest originalWebResourceRequest,
String requestBody,
Uri uri
){
this.originalWebResourceRequest = originalWebResourceRequest;
this.requestBody = requestBody;
if (uri!=null) {
this.uri = uri;
}else{
this.uri = originalWebResourceRequest.getUrl();
}
}

@Override
public Uri getUrl() {
return this.uri;
}

@Override
public boolean isForMainFrame() {
return originalWebResourceRequest.isForMainFrame();
}

@Override
public boolean isRedirect() {
throw new UnsupportedOperationException();
}

@Override
public boolean hasGesture() {
return originalWebResourceRequest.hasGesture();
}

@Override
public String getMethod() {
return originalWebResourceRequest.getMethod();
}

@Override
public Map<String, String> getRequestHeaders() {
return originalWebResourceRequest.getRequestHeaders();
}
public String getAjaxData(){
return requestBody;
}

public boolean hasAjaxData(){
return requestBody != null;
}
}

WriteHandlingWebViewClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import android.content.Context;
import android.net.Uri;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class WriteHandlingWebViewClient extends WebViewClient {

private final String MARKER = "AJAXINTERCEPT";
private Map<String, String> ajaxRequestContents = new HashMap<>();


public WriteHandlingWebViewClient(WebView webView) {
AjaxInterceptJavascriptInterface ajaxInterface = new AjaxInterceptJavascriptInterface(this);
webView.addJavascriptInterface(ajaxInterface , "interception");
}

/*
This here is the "fixed" shouldInterceptRequest method that you should override.
It receives a WriteHandlingWebResourceRequest instead of a WebResourceRequest.
*/
public WebResourceResponse shouldInterceptRequest(
final WebView view,
WriteHandlingWebResourceRequest request
){
return null;
}

@Override
public final WebResourceResponse shouldInterceptRequest(
final WebView view,
WebResourceRequest request
) {

String requestBody = null;
Uri uri = request.getUrl();
if (isAjaxRequest(request)){
requestBody = getRequestBody(request);
uri = getOriginalRequestUri(request, MARKER);
}
WebResourceResponse webResourceResponse = shouldInterceptRequest(
view,
new WriteHandlingWebResourceRequest(request, requestBody, uri)
);
if (webResourceResponse == null){
return webResourceResponse;
} else {
return injectIntercept(webResourceResponse, view.getContext());
}
}

void addAjaxRequest(String id, String body){
ajaxRequestContents.put(id, body);
}

private String getRequestBody(WebResourceRequest request){
String requestID = getAjaxRequestID(request);
return getAjaxRequestBodyByID(requestID);
}

private boolean isAjaxRequest(WebResourceRequest request){
return request.getUrl().toString().contains(MARKER);
}

private String[] getUrlSegments(WebResourceRequest request, String divider){
String urlString = request.getUrl().toString();
return urlString.split(divider);
}

private String getAjaxRequestID(WebResourceRequest request) {
return getUrlSegments(request, MARKER)[1];
}

private Uri getOriginalRequestUri(WebResourceRequest request, String marker){
String urlString = getUrlSegments(request, marker)[0];
return Uri.parse(urlString);
}

private String getAjaxRequestBodyByID(String requestID){
String body = ajaxRequestContents.get(requestID);
ajaxRequestContents.remove(requestID);
return body;
}

private WebResourceResponse injectIntercept(WebResourceResponse response, Context context){
String encoding = response.getEncoding();
String mime = response.getMimeType();
InputStream responseData = response.getData();
InputStream injectedResponseData = injectInterceptToStream(
context,
responseData,
mime,
encoding
);
return new WebResourceResponse(mime, encoding, injectedResponseData);
}

private InputStream injectInterceptToStream(
Context context,
InputStream is,
String mime,
String charset
) {
try {
byte[] pageContents = Utils.consumeInputStream(is);
if (mime.equals("text/html")) {
pageContents = AjaxInterceptJavascriptInterface
.enableIntercept(context, pageContents)
.getBytes(charset);
}

return new ByteArrayInputStream(pageContents);
} catch (Exception e){
throw new RuntimeException(e.getMessage());
}
}
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2021 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :