Android中WebView中拦截所有请求并替换URL(支持AJAX的post请求类型)
需求背景
接到这样一个需求,需要在 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
// }
// }@Overridepublic 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;
// }@Overridepublic 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 bodyif (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 inputString charset = conn.getContentEncoding() != null ? conn.getContentEncoding() : Charset.defaultCharset().displayName();String mime = conn.getContentType();byte[] pageContents = IOUtils.InputStreamTOByte(conn.getInputStream());// Perform JS injectionif (mime.equals("text/html")) {pageContents = PostInterceptJavascriptInterface.enableIntercept(mContext, pageContents).getBytes(charset);}Log.d("888888",charset);// Convert the contents and returnInputStream 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 clarityFormEncoding.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// headerorg.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;}@JavascriptInterfacepublic 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)@JavascriptInterfacepublic 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/VFzY3y3
https://github.com/KeejOow/android-post-webview
感谢@zhangyong125的帮助。
Android中WebView中拦截所有请求并替换URL(支持AJAX的post请求类型)相关推荐
- Android开发-WebView中实现Android调用JS JS调用Android 【三】
老早之前就想总结下Webview相关的知识点了,因为互联网大潮中,很多APP都会使用到Webview,像那些不计其数的电商APP,无一例外的使用Webview:或者一些非电商APP中的像广告页面,注册 ...
- Android 在WebView中获取网页源码
原文链接:http://www.cnblogs.com/hibraincol/archive/2011/10/26/2224866.html 1. 使能javascript: 1 webView.ge ...
- android webview 加载本地pdf,android – 在WebView中打开PDF
我想在我的WebView中打开一个PDF,我在这个论坛上找到并组合了代码. 但是,虽然我安装了多个PDF应用程序,包括Adobe Reader,但它仍然可以找到"找不到PDF应用程序&quo ...
- Android在WebView中给图片设置点击事件
好久没有更新博客了,今天来个小知识点.我们知道在WebView中加载的是Html也面,在开发中都是Web前端人员写好以后给个链接我们去用webView进行loadUrl.但是有时突然产品想让你把加载回 ...
- Android—在WebView中下载Blob协议文件
之前有个需求是要下载Blob协议的gif,让我苦恼了好久.平时下载http协议的文件时直接获取输入流即可,但是Java无法获得Blob协议的文件流,无法直接处理.不过JavaScript处理Blob协 ...
- 微信小程序中WebView中原生组件限制问题解析
背景 在微信的文档中有一个章节说明了『 原生组件的使用限制 』有这么一段话 『由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:原生组件的层级是最高的,所以页面中的其他组件无论设 ...
- http模块中----------req请求对象-req.url req.method 与客户端请求相关
服务器收到客户端发送的请求,就会调用通过server.on() 为服务器绑定request事件处理函数 //监听客户端的请求 server.on('request',(req,res)=>{ ...
- ajax+php跨域请求数据库,基于jQuery的ajax跨域请求,PHP作为服务器端代码
ajax实现跨域请求有两种方式: 方法一:jsonp的方式 jsonp方式的关键点在客户请求以jsonp作为数据类型,服务器端接收jsonp的回调函数,并通过回调函数进行数据的传输.具体代码如下: 客 ...
- 在android的webview中跳转到微信支付和支付宝app支付
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) {// 如下方案可在非微信内部WebView的H ...
最新文章
- Node:非IO的异步API
- C++ Double-Ended Queues(双向队列)
- 深度学习训练中关于数据处理方式--原始样本采集以及数据增广
- BZOJ2240 : ural1676 Mortal Combat
- 【kafka】kafka 判断消费组死掉方案 group dead
- wifi管家android,WiFi管家—轻松连上好wifi
- 360服务器被劫持怎么修复,360浏览器网络劫持导致主页被改怎么办?360浏览器网络劫持导致主页被改的解决办法...
- 毕向东_Java基础
- 公园智慧路灯解决方案
- ArcGIS Server 切片数学关系阐释,小区域切图频繁出错解决方法
- 聚播群控微信二次开发sdk完整API
- 北京五险一金介绍及公积金领取办法
- 使用匿名函数求三个数的最大值
- 如何使用VisiPic消除重复的照片
- Python入门(廖雪峰老师)
- 我的Mysql 使用小册
- 微机 微型计算机,微型计算机杂志
- 控制两个div不换行
- [LOJ 6035] 洗衣服
- 排列组合之——全组合(c语言)