您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

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

时间:02-10来源:作者:点击数:

需求背景

接到这样一个需求,需要在 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 browser

            URL 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访问中另外两个网络请求,拼接自带的参数通过后台验证得到的结果。

https://github.com/KeejOow/android-post-webview

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门