android 拦截webview资源请求,Android WebView通过动态的修改js去拦截post请求参数实例...

Android WebView通过动态的修改js去拦截post请求参数实例

发布时间:2020-09-15 22:55:25

来源:脚本之家

阅读:280

作者:xp_code

需求背景:

需要在用户点击提交按钮的时候拦截用户提交的数据。

遇到的问题:

1.页面不是自家前端做的,不能修改网页中的代码

2.要拦截的请求不是get请求,而是一个post请求 (难点在于:如果拦截的请求是get请求的话,我只需要拿到url,将后面拼接的参数键值对取出来就好了,但是post请求的参数键值对我们是看不到的。。。)

解决重点:

重写webViewClient的shouldInterceptRequest这个方法

1.这个方法是API21以后才出现的,还有一个过时的方法也要重写,不要忘了!

2.在加载网页时,所有的资源都会经过shouldInterceptRequest这个方法,我们可以通过shouldInterceptRequest和抓包工具(Fidder,Charles)去获取你想要获取信息的网址和资源文件

3.这个方法是执行在子线程的,如果你想要更新UI的话,记得切换线程

解决方案:

我这里找到了两种解决方案(总有一款适合你)

方案A : 适合 精通js 的大大们

1.拦截页面上按钮的点击事件,将点击事件的操作进行替换

$('#J_submit').off('click'); //1.将id为J_submit的按钮点击事件关闭

$('#J_submit').on('click',function(){ //2.将id为J_submit的按钮点击事件重新打开,并执行function里的内容

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.获取到页面内的数据

$.ajax({ //4.ajax方式上传到服务器中

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.动态的加载一段js代码

mCommonWebView.setCommonWebViewClient(new CommonWebViewClient() { //添加自定义的 WebViewClient

@Override

public void onPageFinished(WebView view, String url) { //重写onPageFinished方法

super.onPageFinished(view, url);

//请求js的网址

runRemoteJs(Constant.QueryCarPrice.loadJsUrl_CarHome);

}

private void runJs(String remoteJs){ //把获取到的js代码添加到当前网页

if(TextUtils.isEmpty(remoteJs)) {

return;

}

String js = "javascript:"; //作用:指明字符串后面的都是js代码

js+= "var script = document.createElement('script');"; // 作用:创建script节点

js+= "script.type = 'text/javascript';";

js+=remoteJs;

mCommonWebView.callJsFunction(js); //加载js代码

}

private void runRemoteJs(String url) {//前端大大提供的一个网址,网址里面就是上面的js代码,将网页中的代码获取下来

RxRequest request = new RxRequest()

.setUrl(url)

.setMethod(Request.Method.GET);

RxHttpEngineWrapper.commonExec(request)

.subscribeOn(AndroidSchedulers.mainThread())

.subscribe(new UtilsRx.DefaultSubscriber(){

@Override

public void onNext(String s) {

runJs(s);

}

});

}

});

3.到时候只要前端的大大修改页面中的js就可以了

此方案的坑:

1.要加载的js代码中不能包含script节点

2.要加载的js代码中不能有注释

3.要加载的js代码一定要加上分号

*如果不满足上面的三点要求,要加载的js都不能正确的执行

方案B : 原生的Android方式,相对于上一种方案,这种方案比较麻烦

1.重写shouldInterceptRequest去拦截资源

2.将第三方网页上进行网络请求的js页面下载下来(就是把网页的所有下载下来,找到进行网络请求的js页),对js页进行修改

3.将处理好的js页加载到本地,以后加载时就利用本地的js替换第三方的js(我会在本地的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); //设置webview推荐使用的窗口,使html界面自适应屏幕

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 {

/*两个shouldInterceptRequest方法体中的内容大致相同,因为是demo,我也没有抽取方法*/

@Override

public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

//获取的请求参数的 Map 集合

HashMap params;

Uri uri=Uri.parse(url); //获取网址对应的Uri

if (rightUrl(uri.toString())) {

/*get请求获取参数*/

params=paramForGET(uri);

/*重头戏,post请求获取参数*/

/*

* 获取post请求参数的思路就是:

* 找到其网址中进行网络请求的js代码,对这段js代码进行替换

* 我采取的是拦截第三方网址上请求数据的js资源,将本地的资源提交上去替换原资源

*/

if (uri.toString().contains("index.js")) { //拦截该网页下对应的js资源并进行替换

try {

//WebResourceResponse的构造器三个参数作用 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) {

//获取的请求参数的 Map 集合

HashMap params;

String method=request.getMethod(); //当前网址的提交方式

Map requestHeaders = request.getRequestHeaders(); //获取请求头

Uri uri=request.getUrl(); //获取网址对应的Uri

if (rightUrl(uri.toString())) {

/*get请求获取参数*/

params=paramForGET(uri);

/*重头戏,post请求获取参数*/

/*

* 获取post请求参数的思路就是:

* 找到其网址中进行网络请求的js代码,对这段js代码进行替换

* 我采取的是拦截第三方网址上请求数据的js资源,将本地的资源提交上去替换原资源

*/

if (uri.toString().contains("index.js")) { //拦截该网页下对应的js资源并进行替换

try {

//WebResourceResponse的构造器三个参数作用 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)) //判断资源网址是否是我需要的

return true;

return false;

}

private HashMap paramForGET(Uri uri){

HashMap params=new HashMap<>();

Set paramNames = uri.getQueryParameterNames(); //获取此get请求中所有的参数名

/*我这里是将所有的参数都填了进去,大家在获取的时候可以进行筛选和过滤*/

for (String param : paramNames) {

params.put(param,uri.getQueryParameter(param)); //存储键值对

}

return params;

}

}

public class StubClass{

@JavascriptInterface

public void getData(String json){

Log.i("xxx","json -> "+json);

}

}

这是我本地的js,对原来的js进行了修改,添加了与Android通讯的桥梁,来截取数据。

补充知识:android WebView使用Post请求和设置浏览器弹框

这里要注意:post请求参数只能传byte数组,而且必须是键值对字符串形式的byte数组,其中的key是后台服务器接收key,后台规定key是什么值就是什么值,不能随意更改,没有key=value格式或者key不正确,都会请求不到数据网页打不开。

下面代码直接看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);

//获取传过来的支付参数

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");//设置网页默认编码

settings.setJavaScriptCanOpenWindowsAutomatically(true);

Log.d("TAG", "url:"+url);

//post请求(使用键值对形式,格式与get请求一样,key=value,多个用&连接)

urlParameter = "JSONpriKey=" +urlParameter;

webView.postUrl(url, urlParameter.getBytes());

// webView.loadUrl(url);//get

webView.setWebChromeClient(new MyWebChromeClient());// 设置浏览器可弹窗

//覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开

webView.setWebViewClient(new WebViewClient(){

@Override

public boolean shouldOverrideUrlLoading(WebView view, String url) {

//返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器

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);

//支付完成后,点返回关闭界面

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) {// 点击 ‘重新加载'

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通过动态的修改js去拦截post请求参数实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持亿速云。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值