您好,登錄后才能下訂單哦!
需求背景:
需要在用戶點(diǎn)擊提交按鈕的時(shí)候攔截用戶提交的數(shù)據(jù)。
遇到的問題:
1.頁面不是自家前端做的,不能修改網(wǎng)頁中的代碼
2.要攔截的請(qǐng)求不是get請(qǐng)求,而是一個(gè)post請(qǐng)求 (難點(diǎn)在于:如果攔截的請(qǐng)求是get請(qǐng)求的話,我只需要拿到url,將后面拼接的參數(shù)鍵值對(duì)取出來就好了,但是post請(qǐng)求的參數(shù)鍵值對(duì)我們是看不到的。。。)
解決重點(diǎn):
重寫webViewClient的shouldInterceptRequest這個(gè)方法
1.這個(gè)方法是API21以后才出現(xiàn)的,還有一個(gè)過時(shí)的方法也要重寫,不要忘了!
2.在加載網(wǎng)頁時(shí),所有的資源都會(huì)經(jīng)過shouldInterceptRequest這個(gè)方法,我們可以通過shouldInterceptRequest和抓包工具(Fidder,Charles)去獲取你想要獲取信息的網(wǎng)址和資源文件
3.這個(gè)方法是執(zhí)行在子線程的,如果你想要更新UI的話,記得切換線程
解決方案:
我這里找到了兩種解決方案(總有一款適合你)
方案A : 適合 精通js 的大大們
1.攔截頁面上按鈕的點(diǎn)擊事件,將點(diǎn)擊事件的操作進(jìn)行替換
$('#J_submit').off('click'); //1.將id為J_submit的按鈕點(diǎn)擊事件關(guān)閉 $('#J_submit').on('click',function(){ //2.將id為J_submit的按鈕點(diǎn)擊事件重新打開,并執(zhí)行function里的內(nèi)容 if ($(this).hasClass("btn-disabled")) { // ----- 此處為原頁面代碼,不做解釋 ----- return; } try { trackDealerEvent('dlr_order_page_form_submit_click', { 'esfrom': _mediaId, 'business': 'songshu', 'series': _seriesId, 'city': _cityId }); } catch (e) { console.log(e); } // ----- 此處為原頁面代碼,不做解釋 ----- var pageFormData = validateAllField(alertDiv); if (pageFormData) { //3.獲取到頁面內(nèi)的數(shù)據(jù) $.ajax({ //4.ajax方式上傳到服務(wù)器中 url: 'https://gouche.jxedt.com/gouche/clue/submit', data: { cityid: _cityId, brandid: _brandId, seriesid: _seriesId, classesid: _specId, name: $("[name='userName']").val(), phone: $('#phoneNumber').val(), type: 4 } }); postOrder(pageFormData); } })
2.動(dòng)態(tài)的加載一段js代碼
mCommonWebView.setCommonWebViewClient(new CommonWebViewClient() { //添加自定義的 WebViewClient @Override public void onPageFinished(WebView view, String url) { //重寫onPageFinished方法 super.onPageFinished(view, url); //請(qǐng)求js的網(wǎng)址 runRemoteJs(Constant.QueryCarPrice.loadJsUrl_CarHome); } private void runJs(String remoteJs){ //把獲取到的js代碼添加到當(dāng)前網(wǎng)頁 if(TextUtils.isEmpty(remoteJs)) { return; } String js = "javascript:"; //作用:指明字符串后面的都是js代碼 js+= "var script = document.createElement('script');"; // 作用:創(chuàng)建script節(jié)點(diǎn) js+= "script.type = 'text/javascript';"; js+=remoteJs; mCommonWebView.callJsFunction(js); //加載js代碼 } private void runRemoteJs(String url) {//前端大大提供的一個(gè)網(wǎng)址,網(wǎng)址里面就是上面的js代碼,將網(wǎng)頁中的代碼獲取下來 RxRequest<String> request = new RxRequest<String>() .setUrl(url) .setMethod(Request.Method.GET); RxHttpEngineWrapper.commonExec(request) .subscribeOn(AndroidSchedulers.mainThread()) .subscribe(new UtilsRx.DefaultSubscriber<String>(){ @Override public void onNext(String s) { runJs(s); } }); } });
3.到時(shí)候只要前端的大大修改頁面中的js就可以了
此方案的坑:
1.要加載的js代碼中不能包含script節(jié)點(diǎn)
2.要加載的js代碼中不能有注釋
3.要加載的js代碼一定要加上分號(hào)
*如果不滿足上面的三點(diǎn)要求,要加載的js都不能正確的執(zhí)行
方案B : 原生的Android方式,相對(duì)于上一種方案,這種方案比較麻煩
1.重寫shouldInterceptRequest去攔截資源
2.將第三方網(wǎng)頁上進(jìn)行網(wǎng)絡(luò)請(qǐng)求的js頁面下載下來(就是把網(wǎng)頁的所有下載下來,找到進(jìn)行網(wǎng)絡(luò)請(qǐng)求的js頁),對(duì)js頁進(jìn)行修改
3.將處理好的js頁加載到本地,以后加載時(shí)就利用本地的js替換第三方的js(我會(huì)在本地的js頁面中添加與webview溝通的橋梁)
//以下為具體操作,我把具體的方法貼了上去,如果不太懂的可以看看代碼,我寫了注釋 //初始化WebView private void initWebView() { mWebView.getSettings().setDomStorageEnabled(true); mWebView.getSettings().setDefaultTextEncodingName("utf-8"); if(Build.VERSION.SDK_INT >=21){//Added in API level 21 mWebView.getSettings().setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setUseWideViewPort(true); //設(shè)置webview推薦使用的窗口,使html界面自適應(yīng)屏幕 mWebView.getSettings().setLoadWithOverviewMode(true); mWebView.getSettings().setGeolocationEnabled(true); mWebView.getSettings().setAllowFileAccess(true); if (Build.VERSION.SDK_INT >= 16) { //屏蔽Webview的跨域漏洞 mWebView.getSettings().setAllowFileAccessFromFileURLs(false); mWebView.getSettings().setAllowUniversalAccessFromFileURLs(false); } mWebView.getSettings().setPluginState(WebSettings.PluginState.ON); if (Build.VERSION.SDK_INT >= 11) { mWebView.getSettings().setAllowContentAccess(true); } mWebView.loadUrl(currUrl); mWebView.setWebViewClient(new MyWebViewClient()); //與js通訊的橋梁 mWebView.addJavascriptInterface(new StubClass(),"stub"); } public class MyWebViewClient extends WebViewClient { /*兩個(gè)shouldInterceptRequest方法體中的內(nèi)容大致相同,因?yàn)槭莇emo,我也沒有抽取方法*/ @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { //獲取的請(qǐng)求參數(shù)的 Map 集合 HashMap<String,String> params; Uri uri=Uri.parse(url); //獲取網(wǎng)址對(duì)應(yīng)的Uri if (rightUrl(uri.toString())) { /*get請(qǐng)求獲取參數(shù)*/ params=paramForGET(uri); /*重頭戲,post請(qǐng)求獲取參數(shù)*/ /* * 獲取post請(qǐng)求參數(shù)的思路就是: * 找到其網(wǎng)址中進(jìn)行網(wǎng)絡(luò)請(qǐng)求的js代碼,對(duì)這段js代碼進(jìn)行替換 * 我采取的是攔截第三方網(wǎng)址上請(qǐng)求數(shù)據(jù)的js資源,將本地的資源提交上去替換原資源 */ if (uri.toString().contains("index.js")) { //攔截該網(wǎng)頁下對(duì)應(yīng)的js資源并進(jìn)行替換 try { //WebResourceResponse的構(gòu)造器三個(gè)參數(shù)作用 String mimeType:指定替換資源的類型 String encoding:字符集 InputStream input:輸入流 return new WebResourceResponse("application/x-javascript","UTF-8",getAssets().open("index.js")); } catch (IOException e) { e.printStackTrace(); } } } return super.shouldInterceptRequest(view, url); } //API21及21以后才支持此方法 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { //獲取的請(qǐng)求參數(shù)的 Map 集合 HashMap<String,String> params; String method=request.getMethod(); //當(dāng)前網(wǎng)址的提交方式 Map<String, String> requestHeaders = request.getRequestHeaders(); //獲取請(qǐng)求頭 Uri uri=request.getUrl(); //獲取網(wǎng)址對(duì)應(yīng)的Uri if (rightUrl(uri.toString())) { /*get請(qǐng)求獲取參數(shù)*/ params=paramForGET(uri); /*重頭戲,post請(qǐng)求獲取參數(shù)*/ /* * 獲取post請(qǐng)求參數(shù)的思路就是: * 找到其網(wǎng)址中進(jìn)行網(wǎng)絡(luò)請(qǐng)求的js代碼,對(duì)這段js代碼進(jìn)行替換 * 我采取的是攔截第三方網(wǎng)址上請(qǐng)求數(shù)據(jù)的js資源,將本地的資源提交上去替換原資源 */ if (uri.toString().contains("index.js")) { //攔截該網(wǎng)頁下對(duì)應(yīng)的js資源并進(jìn)行替換 try { //WebResourceResponse的構(gòu)造器三個(gè)參數(shù)作用 String mimeType:指定替換資源的類型 String encoding:字符集 InputStream input:輸入流 return new WebResourceResponse("application/x-javascript","UTF-8",getAssets().open("index.js")); } catch (IOException e) { e.printStackTrace(); } } } return super.shouldInterceptRequest(view, request); } private boolean rightUrl(String url){ if (url.contains(COLLECT_URL)) //判斷資源網(wǎng)址是否是我需要的 return true; return false; } private HashMap<String,String> paramForGET(Uri uri){ HashMap<String,String> params=new HashMap<>(); Set<String> paramNames = uri.getQueryParameterNames(); //獲取此get請(qǐng)求中所有的參數(shù)名 /*我這里是將所有的參數(shù)都填了進(jìn)去,大家在獲取的時(shí)候可以進(jìn)行篩選和過濾*/ for (String param : paramNames) { params.put(param,uri.getQueryParameter(param)); //存儲(chǔ)鍵值對(duì) } return params; } } public class StubClass{ @JavascriptInterface public void getData(String json){ Log.i("xxx","json -> "+json); } }
這是我本地的js,對(duì)原來的js進(jìn)行了修改,添加了與Android通訊的橋梁,來截取數(shù)據(jù)。
補(bǔ)充知識(shí):android WebView使用Post請(qǐng)求和設(shè)置瀏覽器彈框
這里要注意:post請(qǐng)求參數(shù)只能傳byte數(shù)組,而且必須是鍵值對(duì)字符串形式的byte數(shù)組,其中的key是后臺(tái)服務(wù)器接收key,后臺(tái)規(guī)定key是什么值就是什么值,不能隨意更改,沒有key=value格式或者key不正確,都會(huì)請(qǐng)求不到數(shù)據(jù)網(wǎng)頁打不開。
下面代碼直接看initWebView()方法就好
package com.xxxxx.xxx.activity.banksign; import org.json.JSONException; import org.json.JSONObject; import android.app.AlertDialog; import android.content.DialogInterface; import android.graphics.Bitmap; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import com.xinzong.etc.R; import com.xinzong.xx.base.BaseGestureActivty; import com.xinzong.xxx.utils.ShowReloadUtil; /** * * @author * */ public class WebViewActivity extends BaseGestureActivty implements OnClickListener{ private ShowReloadUtil reloadUtil; private String url = "http://120.1.1.1/xx/xxxx"; private WebView webView; private String urlParameter = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_webview); findViewById(R.id.ibBack).setOnClickListener(this); //獲取傳過來的支付參數(shù) urlParameter = getIntent().getStringExtra("urlParameter"); Log.i("TAG", urlParameter); //初始化重新加載框 reloadUtil = new ShowReloadUtil(this); reloadUtil.setReloadView(this, R.id.ll_show_data_mc, R.id.rl_reload_parent_mc); //刷新界面,加載webview refresh(); } private void refresh() { if(isNetworkConnected()){ findView(R.id.webview1).setVisibility(View.VISIBLE); reloadUtil.showDataView(); initWebView(); }else{ findView(R.id.webview1).setVisibility(View.GONE); reloadUtil.showReload(); } } private void initWebView() { webView = (WebView) findViewById(R.id.webview1); //初始化webview //啟用支持javascript WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true);//支持javaScript settings.setDefaultTextEncodingName("utf-8");//設(shè)置網(wǎng)頁默認(rèn)編碼 settings.setJavaScriptCanOpenWindowsAutomatically(true); Log.d("TAG", "url:"+url); //post請(qǐng)求(使用鍵值對(duì)形式,格式與get請(qǐng)求一樣,key=value,多個(gè)用&連接) urlParameter = "JSONpriKey=" +urlParameter; webView.postUrl(url, urlParameter.getBytes()); // webView.loadUrl(url);//get webView.setWebChromeClient(new MyWebChromeClient());// 設(shè)置瀏覽器可彈窗 //覆蓋WebView默認(rèn)使用第三方或系統(tǒng)默認(rèn)瀏覽器打開網(wǎng)頁的行為,使網(wǎng)頁用WebView打開 webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //返回值是true的時(shí)候控制去WebView打開,為false調(diào)用系統(tǒng)瀏覽器或第三方瀏覽器 Log.d("TAG", "url:"+url); view.loadUrl(url); return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { Log.d("TAG", "onPageStarted--url:"+url); //支付完成后,點(diǎn)返回關(guān)閉界面 if(url.endsWith("http://120.1.1.1/xxx/xx/xxx")){ finish(); } super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } }); } @Override public void onClick(View v) { if (v.getId() == R.id.btnReload) {// 點(diǎn)擊 ‘重新加載' reloadUtil.showClickloadingView(); Log.d("TAG", "RELOAD"); if (this.isNetworkConnected()) { webView.loadUrl(url); } else { reloadUtil.showReload(); } }else if(v.getId() == R.id.ibBack){ if(webView !=null && webView.canGoBack()){ webView.goBack(); }else{ finish(); } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK && webView !=null && webView.canGoBack()){ webView.goBack(); return true; } return super.onKeyDown(keyCode, event); } /** * 瀏覽器可彈窗 * * @author Administrator * */ final class MyWebChromeClient extends WebChromeClient { @Override public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(CTX) .setTitle("App Titler") .setMessage(message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { result.cancel(); } }).create().show(); return true; } } }
以上這篇Android WebView通過動(dòng)態(tài)的修改js去攔截post請(qǐng)求參數(shù)實(shí)例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。