您的位置:首页 > 移动开发

Android中WebView中拦截所有请求并替换URL(支持AJAX的post请求类型)

2016-05-17 18:41 1841 查看


需求背景

接到这样一个需求,需要在 WebView 的所有网络请求中,在请求的url中,加上一个sign=xxxx 的标志位,同时添加手机本地的数据比如 sessionToken=sd54f5sd4ffsdf45454564
、deviceId=863970025919887
后端主要函数
如下是http://192.168.1.52/web/post.html的html数据,由于是局域网链接,大家连不上
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
</head>
<script src="jquery-2.1.4.min.js"></script>
<script>
/**
sign:"1bb6b8e28acb46e2801d352e0fb59b6e"
**//**
$.getJSON("http://192.168.1.52/gateway/testBindBankCard?sessionToken=abfda&userId=12&bankname=中国银行&branchBank=中国>银>行北京分行&bankCode=24839&bankCardNo=63238941329210832819&shortMsgCode=23&cardOwner=王腾飞" ,function(data){
if(data.errcode=='0'){
$("#g1").text("恭喜你GET成功了!");
}else
$("#g1").text(data.errmsg);
});
**/
$.getJSON("http://192.168.1.52/gateway/testBindBankCard?bankCardNo=63238941329210832819&bankCode=4839&bankname=中国银行&branchBank=中银行北京分行&cardOwner=王腾飞&shortMsgCode=23&userId=12" ,function(data){
if(data.errcode=='0'){
$("#g1").text("恭喜你GET成功了!");
}else
$("#g1").text(data.errmsg);
});$.ajax({
type: 'POST',
url: "http://192.168.1.52/gateway/testBindBankCard" ,
data: {
userId:"12",
bankname:"中国银行",
branchBank:"中银行北京分行",
bankCode:"4839",
bankCardNo:"63238941329210832819",
shortMsgCode:"23",
cardOwner:"王腾飞"
},
success: function function_name (data) {
if(data.errcode=='0'){
$("#div").text("恭喜你POST成功了!");
}else
$("#div").text(data.errmsg);
}
});</script>
<body>
<h1>测试页面</h1>
本次测试结果为:
<div id="div" style="font-size:28px;color:red;"></div>
<div id="g1" style="font-size:28px;color:red;">
<div>
</body>
</html>

html中是aiax中的post请求如下:

$.ajax({
type: 'POST',
url: "http://192.168.1.52/gateway/testBindBankCard" ,
data: {
userId:"12",
bankname:"中国银行",
branchBank:"中银行北京分行",
bankCode:"4839",
bankCardNo:"63238941329210832819",
shortMsgCode:"23",
cardOwner:"王腾飞",
sessionToken:"43248329"
}
html中 data中的数据是post请求的body体,我需要将该链接中body体进行拦截并加上自带标志和参数"&deviceId="+MyApplication.device_id+"&sessionToken="+"43248329"+"&sign="+sign
http://192.168.1.52/gateway/testBindBankCard?userId=12&bankname=中国银行&branchBank=中银行北京分行&bankCode=4839&bankCardNo=6323894132921089&shortMsgCode=23&cardOwner=王腾飞&deviceId=863970025919887&sessionToken=43248329&sign=fc806225b90b38ee9d7394870afc2b4f
//get请求 需求类似Android主要函数InterceptingWebViewClient.Java重写WebViewClient类,进行相应的url拦截、回调
package com.cloudhome.webview_intercept;import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;import com.squareup.mimecraft.FormEncoding;import org.json.JSONArray;
import org.json.JSONObject;import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;import okhttp3.OkHttpClient;public class InterceptingWebViewClient extends WebViewClient {
public static final String TAG = "InterceptingWebViewClient";private Context mContext = null;
private WebView mWebView = null;
private PostInterceptJavascriptInterface mJSSubmitIntercept = null;
private OkHttpClient client = new OkHttpClient();public InterceptingWebViewClient(Context context, WebView webView) {
mContext = context;
mWebView = webView;
mJSSubmitIntercept = new PostInterceptJavascriptInterface(this);
mWebView.addJavascriptInterface(mJSSubmitIntercept, "interception");}// @Override
// public void onPageStarted(WebView view, String url, Bitmap favicon){
// if (url.startsWith("https://")) { //NON-NLS
//
// mNextAjaxRequestContents = null;
// mNextFormRequestContents = null;
// view.stopLoading();
// // DO SOMETHING
// }
// }@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mNextAjaxRequestContents = null;
mNextFormRequestContents = null;view.loadUrl(url);
return true;
}
// @TargetApi(Build.VERSION_CODES.LOLLIPOP)
// @Override
// public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
// if (request != null && request.getUrl() != null) {
//
// String scheme = request.getUrl().getScheme().trim();
// if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
// URL url;
// URLConnection connection;
// HttpURLConnection conn ;
//
// try {
// if (request.getMethod().equals("POST")) {
// url= new URL(request.getUrl().toString());
// connection = url.openConnection();
// conn = (HttpURLConnection) connection;
// Log.d("7777776",request.getUrl().toString());
// conn.setRequestMethod( "POST");
// OutputStream os = conn.getOutputStream();
// if (mNextAjaxRequestContents != null) {
//
// Log.d("777777","44444");
// writeBody(os);
// } else {
//
// Log.d("777777","5555");
// writeForm(os);
// }
// os.close();
//
//
//
// // Read input
// String charset = conn.getContentEncoding() != null ? conn.getContentEncoding() : Charset.defaultCharset().displayName();
// String mime = conn.getContentType();
// byte[] pageContents = IOUtils.readFully(connection.getInputStream());
//
// // Perform JS injection
// if (mime.equals("text/html")) {
// pageContents = PostInterceptJavascriptInterface
// .enableIntercept(mContext, pageContents)
// .getBytes(charset);
// }
//
// // Convert the contents and return
// InputStream isContents = new ByteArrayInputStream(pageContents);
//
// return new WebResourceResponse(mime, charset,
// isContents);
//
//
// }else{
// url = new URL(injectIsParams(request.getUrl().toString()));
// connection = url.openConnection();
// Log.d("7777779",request.getUrl().toString());
// }
//
//
//
//
//
// // Write body
// if (request.getMethod().equals("GET")) {
//
// String contentType = connection.getContentType();
// // If got a contentType header
// if(contentType != null) {
//
// String mimeType = contentType;
//
// // Parse mime type from contenttype string
// if (contentType.contains(";")) {
// mimeType = contentType.split(";")[0].trim();
// }
//
//
// return new WebResourceResponse(mimeType, connection.getContentEncoding(), connection.getInputStream());
// }
//
// }
//
//
//
//
// } catch (MalformedURLException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
// return null;
// }@Override
public WebResourceResponse shouldInterceptRequest(final WebView view, final String urlstr) {
try {
// Our implementation just parses the response and visualizes it. It does not properly handle
// redirects or HTTP errors at the moment. It only serves as a demo for intercepting POST requests
// as a starting point for supporting multiple types of HTTP requests in a full fletched browserURL url = null;if (isPOST()) {
url = new URL(urlstr);
Log.d("77777post",urlstr);
} else {
Log.d("77777get", urlstr);
url = new URL(injectIsParams(urlstr));}
Log.d("77777get",url.toString());URLConnection rulConnection = url.openConnection();
HttpURLConnection conn = (HttpURLConnection) rulConnection;
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");conn.setRequestMethod(isPOST() ? "POST" : "GET");// Write body
if (isPOST()) {
OutputStream os = conn.getOutputStream();
if (mNextAjaxRequestContents != null) {
writeBody(os);
} else {
writeForm(os);
}
os.close();
}// else{
// String contentType = rulConnection.getContentType();
// // If got a contentType header
// if(contentType != null) {
//
// String mimeType = contentType;
//
// // Parse mime type from contenttype string
// if (contentType.contains(";")) {
// mimeType = contentType.split(";")[0].trim();
// }
//
//
// return new WebResourceResponse(mimeType, rulConnection.getContentEncoding(), rulConnection.getInputStream());
// }
//
// }// Read input
String charset = conn.getContentEncoding() != null ? conn.getContentEncoding() : Charset.defaultCharset().displayName();
String mime = conn.getContentType();
byte[] pageContents = IOUtils.InputStreamTOByte(conn.getInputStream());// Perform JS injection
if (mime.equals("text/html")) {
pageContents = PostInterceptJavascriptInterface
.enableIntercept(mContext, pageContents)
.getBytes(charset);
}Log.d("888888",charset);
// Convert the contents and return
InputStream isContents = new ByteArrayInputStream(pageContents);mNextAjaxRequestContents=null;
return new WebResourceResponse(mime, charset,
isContents);} catch (FileNotFoundException e) {
Log.w("Error 404","Error 404:" + e.getMessage());
e.printStackTrace();return null; // Let Android try handling things itself
} catch (Exception e) {
e.printStackTrace();return null; // Let Android try handling things itself
}
}private boolean isPOST() {
return (mNextAjaxRequestContents!=null&&mNextAjaxRequestContents.method.equals("POST"));
}private void writeBody(OutputStream out) {
try {
Log.d("777773", mNextAjaxRequestContents.body);
out.write(mNextAjaxRequestContents.body.getBytes("UTF-8"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}protected void writeForm(OutputStream out) {
try {
JSONArray jsonPars = new JSONArray(mNextFormRequestContents.json);// We assume to be dealing with a very simple form here, so no file uploads or anything
// are possible for reasons of clarity
FormEncoding.Builder m = new FormEncoding.Builder();
for (int i = 0; i < jsonPars.length(); i++) {
JSONObject jsonPar = jsonPars.getJSONObject(i);m.add(jsonPar.getString("name"), jsonPar.getString("value"));
// jsonPar.getString("type");
// TODO TYPE?
}
m.build().writeBodyTo(out);
} catch (Exception e) {
throw new RuntimeException(e);
}
}public String getType(Uri uri) {
String contentResolverUri = mContext.getContentResolver().getType(uri);
if (contentResolverUri == null) {
contentResolverUri = "*/*";
}
return contentResolverUri;
}private PostInterceptJavascriptInterface.FormRequestContents mNextFormRequestContents = null;public void nextMessageIsFormRequest(PostInterceptJavascriptInterface.FormRequestContents formRequestContents) {
mNextFormRequestContents = formRequestContents;
}private PostInterceptJavascriptInterface.AjaxRequestContents mNextAjaxRequestContents = null;public void nextMessageIsAjaxRequest(PostInterceptJavascriptInterface.AjaxRequestContents ajaxRequestContents) {
mNextAjaxRequestContents= ajaxRequestContents;
}/**
* 当GET请求时,修改url的函数位置
*/public static String injectIsParams(String url) throws UnsupportedEncodingException {//此处省略拼接函数
......
}}
PostInterceptJavascriptInterface.Java 用来识别url请求是GET请求还是POST请求
package com.cloudhome.webview_intercept;import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.webkit.JavascriptInterface;import org.jsoup.Jsoup;import java.io.IOException;
import java.io.UnsupportedEncodingException;public class PostInterceptJavascriptInterface {
public static final String TAG = "PostInterceptJavascriptInterface";private static String mInterceptHeader = null;
private InterceptingWebViewClient mWebViewClient = null;public PostInterceptJavascriptInterface(InterceptingWebViewClient webViewClient) {
mWebViewClient = webViewClient;
}public static String enableIntercept(Context context, byte[] data) throws IOException {
if (mInterceptHeader == null) {
mInterceptHeader = new String(IOUtils.InputStreamTOByte(context.getAssets().open("www/interceptheader.html")), "utf-8");
}Log.d("4444", data.toString());
org.jsoup.nodes.Document doc = Jsoup.parse(new String(data, "utf-8"));
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 el = doc.getElementsByTag("head");
if (el.size() > 0) {
el.get(0).prepend(mInterceptHeader);
}String pageContents = doc.toString();Log.d("777777", pageContents);return pageContents;
}/**
* 当POST请求时,修改url的函数位置
*/
public static String injectIsParams(String url) throws UnsupportedEncodingException {//此处省略拼接函数
......
return urlEncode;}@JavascriptInterface
public void customAjax(final String method, final String body) throws UnsupportedEncodingException {
Log.i(TAG, "Submit data: " + method + " " + body);// Log.i("77777",url);
// injectIsParams(body);mWebViewClient.nextMessageIsAjaxRequest(new AjaxRequestContents(method, injectIsParams(body + "")));
}@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@JavascriptInterface
public void customSubmit(String json, String method, String enctype) {
Log.i(TAG, "Submit data: " + json + "\t" + method + "\t" + enctype);
mWebViewClient.nextMessageIsFormRequest(
new FormRequestContents(method, json, enctype));
}public class FormRequestContents {
public String method = null;
public String json = null;
public String enctype = null;public FormRequestContents(String method, String json, String enctype) {
this.method = method;
this.json = json;
this.enctype = enctype;
}
}public class AjaxRequestContents {
public String method = null;
public String body = null;public AjaxRequestContents(String method, String body) {
this.method = method;
this.body = body;
}
}}
在android assets / www文件夹中 添加interceptheader.html 获取url请求header和body等参数
<script language="JavaScript">
HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = interceptor;window.addEventListener('submit', function(e) {
interceptor(e);
}, true);function interceptor(e) {
var frm = e ? e.target : this;interceptor_onsubmit(frm);
frm._submit();
}function interceptor_onsubmit(f) {
var jsonArr = [];
for (i = 0; i < f.elements.length; i++) {
var parName = f.elements[i].name;
var parValue = f.elements[i].value;
var parType = f.elements[i].type;jsonArr.push({
name : parName,
value : parValue,
type : parType
});
}interception.customSubmit(JSON.stringify(jsonArr),
f.attributes['method'] === undefined ? null
: f.attributes['method'].nodeValue,
f.attributes['enctype'] === undefined ? null
: f.attributes['enctype'].nodeValue);
}lastXmlhttpRequestPrototypeMethod = null;
XMLHttpRequest.prototype.reallyOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
lastXmlhttpRequestPrototypeMethod = method;
this.reallyOpen(method, url, async, user, password);
};
XMLHttpRequest.prototype.reallySend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(body) {
interception.customAjax(lastXmlhttpRequestPrototypeMethod, body);
lastXmlhttpRequestPrototypeMethod = null;
this.reallySend(body);
};
</script>
webview 请求访问前webview 请求访问后注意:恭喜你GET成功了!恭喜你POST成功了!不是webview直接访问得到的结果,而是拦截webview访问中另外两个网络请求,拼接自带的参数通过后台验证得到的结果。我的demo下载参考资料http://www.tuicool.com/articles/VFzY3y3https://github.com/KeejOow/android-post-webview感谢@zhangyong125的帮助。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: