webview添加参数与修改请求头的user-agent

article/2025/9/29 5:55:35

前言

最近公司项目需求,在项目中嵌入h5页面,一般原生,看着感觉跟往常一样,一个地址就完全ok了,如果是这样那就没有这个博文的必要了!

项目的登录使用的token登录,在移动端的登录是原生的,但是h5也是有登录页面,这就需要控制token的过期时间了,但是想达到的网页访问使用网页的cookie,app登录使用的是app原生的登录token,在网页的cookie登录过期的时候,网页是可以正常退回登录页面,而在app嵌入的h5也需要根据token是否过期,决定是否返回登录页。

那么,问题就是在此产生了,token过期的时候app端是如何知道呢?这篇博文记录解决方案:

正常使用

按照正常程序走的话,我们使用

webView.loadUrl(url);

这样就可以解决平时之间访问一个网页的需求。或者在url的后面拼接上我们需要的token去验证登录状态,也可以拼接其他参数做一些特殊的处理。

但是如果仅仅是拼接token过去,在当前页面(一级页面)是可以正常判断过期时间,但是如果在此页面(一级页面)有按钮点击进入二级页面,这样在二级页面是没有token的拼接的,如果在一级页面token过期了,还是能正常进入二级页面,所以在二级页面还是处于登录的状态,但是实际在一级页面的时候token已经是过期的了,所以正常来说二级页面也是处于退出登录状态才对,但是由于token是在一级页面的时候进行拼接的,所以能正常判断,但是二级页面我们没有拼接,所以无法判断。

总结:此方法不适合所有登录页面都需要判断登录状态的h5

添加请求头

在加载h5的时候添加请求头

在度娘上有很多都是直接使用webView.loadUrl(url,header);直接添加请求头(header),但是这种方法与step1中的没有多大的区别,也只是在一级页面的时候生效,二级页面的header还是变成了之前的默认的了。

同步cookie

使用cookie,同步网页的cookie,这种方法可以是可以,但是并不能使用很多情况,如果你是半原生,半h5,而你原生的登录的登录使用的是token进行登录的验证的话,cookie的这种方法也不是一个很好的方法。cookie的同步就不介绍了,在度娘上可以找到。

修改user-agent、访问url都拼接token

因为我们的需求的进行多端登录,进行不同设备的判断,所以我们移动端的h5页面要告诉服务端,这个是访问是我们app访问的,所以我们需要解决的是让服务端如何知道这个网页的访问是移动端访问的。

在http请求头中,有user-agent,服务端可以根据请求头的user-agent来判断当前是什么设备访问的,所以我们要跟服务端规定好给服务端传一个特殊的字符串,默认这是我们app访问的,这样服务端就知道是谁访问的了,然后进行相关的操作。

而webview中也刚好提供了方法进行user-agent的设置,具体使用下面再进行介绍。在请求头里的作用可自行百度。

解决了身份的判断了,就剩下解决退出登录的通知了。

上面也说了,如果是直接使用拼接参数的方法是可以验证是否登录过期的,但是对二级页面是不生效的,因为二级页面是没有进行拼接的,但是如果我们的二级页面也进行了拼接呢?是否可以正常验证呢?

下面我们使用的就是在所有的二级或者三级等页面上都拼接上我们的token:

在介绍解决方法之前先介绍几个方法:

@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {return super.shouldInterceptRequest(view, request);
}@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {return super.shouldInterceptRequest(view, url);
}

方法一shouldInterceptRequest(WebView view, WebResourceRequest request)和方法二shouldInterceptRequest(WebView view, String url)其实左右是一样的,但是方法二在在API级别21中已弃用。但是我们未来兼容版本,所以两方法还是都要使用。

上图是Google的官方文档,我们可以知道,在h5中发起的所有的加载资源的url,都会再此方法中拦截,然后我们拦截到所以得url进行我们需要的操作。所以在所有的二级、三级等页面拼接参数就在此方法中拼接。

同时再看两个方法:

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {return super.shouldOverrideUrlLoading(view, request);
}@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {return super.shouldOverrideUrlLoading(view, url);
}

 

在这里,我们可以处理重定向,变成我们需要显示的效果,具体的使用可就不详细介绍了。主要是shouldOverrideUrlLoading()方法的使用介绍。

解决方案:

1、修改user-agent

在webview中,提供了一个方法setUserAgentString(),可以修改user-agent,使用方法如下:

mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString().concat("Android-APP"));

Android-APP就是配置特殊字符串,服务端可以根据你的user-agent包含了Android-APP来判断你是使用app进行访问的。

但是在设置user-agent的时候,使用一下设置方法;

mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString()+"Android-APP");

这样设置的话服务端怎么都拿不到Android-APP,这个问题我还没搞明白是这么回事。有知道的朋友可以帮忙解惑一下,非常感谢!!!

第一种设置方法就是在user-agent的基础上在后面拼接上Android-APP,这样app访问的话,服务端就会知道是app访问的,就会想要对应的操作。

2、拼接参数

 

/*** * @param view* @param request* @return*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {if (request != null && request.getUrl() != null && request.getMethod().equalsIgnoreCase("get")) {String scheme = request.getUrl().getScheme().trim();if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {if (request.getUrl().toString().contains(".html")) {try {LogUtil.e("------->" + request.getUrl().toString());URL url = new URL(injectIsParams(request.getUrl().toString()));URLConnection connection = url.openConnection();if (connection.getInputStream().toString().length() < 120) {String value = IOUtils.toString(connection.getInputStream(), "UTF-8");LogUtil.e(value);if (value.startsWith("{")) {HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);if (httpResult != null) {LogUtil.e(httpResult.toString());if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {LoginActivity.startAction(getActivity());SPUtils.put(getActivity(), Constants.ACCESS_TOKEN, "");getActivity().finish();}}}} else {connection.getInputStream().close();}return null;} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}}return null;
}/*** * @param view* @param url* @return*/
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {if (url.contains(".html")) {try {URL url1 = new URL(injectIsParams(url));URLConnection connection = url1.openConnection();if (connection.getInputStream().toString().length() < 120) {String value = IOUtils.toString(connection.getInputStream(), "UTF-8");LogUtil.e(value);if (value.startsWith("{")) {HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);if (httpResult != null) {LogUtil.e(httpResult.toString());if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {LoginActivity.startAction(getActivity());SPUtils.put(getActivity(), Constants.ACCESS_TOKEN, "");getActivity().finish();}}}} else {connection.getInputStream().close();}return null;} catch (IOException e) {e.printStackTrace();}}return null;
}

 

/*** 注入参数** @param url* @return*/
public static String injectIsParams(String url) {if (url != null && !url.contains("app=true&access_token=")) {if (url.contains("?")) {return url + "&app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");} else {return url + "?app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");}} else {return url;}
}

因为在shouldInterceptRequest()中拦截的是所有的加载资源文件的url,想加载图片,加载视频,加载js等url都会再此拦截,所以我们拼接参数的话,是要过滤掉这些的,我这里只要是包含了.html的url都进行参数拼接。

URL url = new URL(injectIsParams(request.getUrl().toString()));
URLConnection connection = url.openConnection();

这里是对进行了拼接参数的url进行连接,连接完成之后,我们要获取页面的时间,使用一下方法去获取:

connection.getInputStream()

以上的方法获取的是整个页面的数据,如果是网页的话,会把整个网页的代码获取下来,但是我们需要的并不是要网页的代码,我们是要获取登录失败的消息。

在此,我们已服务端协商,在token失效后,给我们返回跟接口一样的json字符串,如果是处于登录失效的时候,我们使用connection.getInputStream()获取的就是一串json字符串,因为token并不是都是过期的,所以connection.getInputStream()获取的可以是一个网页的代码,这就需要我们进行过滤了。

json字符串是以大括号开始的,并且以大括号结束,这样我们就可以区分是代码还是json字符串了。

拿到json字符串之后就进行解析,执行我们的退出登录操作。至此,完美解决token失效的问题!!!

下面就贴出整个页面的代码,如果有需要的可以去除错误部分,毕竟是从项目中抽出来的,只是做一个参考作用:

/*** @author Administrator*/
public class WebViewActivity extends BaseAbstractSimpleActivity implements IActivityStatusBar {private String url = "";private AgentWeb mAgentWeb;private LinearLayout mLinearLayoutWebView;private DownloadingService mDownloadingService;private WebView mWebView;private long mTime;private LinearLayout mLinearLayoutSplash;private ValueCallback<Uri[]> mUploadCallbackAboveFive;private ValueCallback<Uri> mUploadMessage;private final int RESULT_CODE_IMAGE = 1005;private File userImgFile;/*** 请求开启定位*/public static int REQUEST_CODE_ENABLE_LOCATION = 100;public static int REQUEST_CODE_ACCESS_LOCATION_PERMISSION = 101;private LocationWebChromeClient mWebChromeClient;public static void startAction(Activity context, @NonNull String url) {Intent intent = new Intent(context, WebViewActivity.class);intent.putExtra("url", url);context.startActivityForResult(intent, Constants.LOGIN_OUT_REQUEST);}@Overrideprotected int getLayout() {return R.layout.activity_web_view;}@Overrideprotected void initEventAndData() {mWebChromeClient = new LocationWebChromeClient();mAgentWeb = AgentWeb.with(this).setAgentWebParent(mLinearLayoutWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)).useDefaultIndicator(-1, 3).setAgentWebWebSettings(getSettings()).setWebViewClient(mWebViewClient).setWebChromeClient(mWebChromeClient).setSecurityType(AgentWeb.SecurityType.STRICT_CHECK).setMainFrameErrorView(R.layout.agentweb_error_page, -1).setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.DISALLOW).interceptUnkownUrl().createAgentWeb().ready().go(url);mWebView = mAgentWeb.getWebCreator().getWebView();mAgentWeb.getJsInterfaceHolder().addJavaObject("aaa", new JavaScriptInterface(this));if (url.contains("<html>")) {mWebView.loadDataWithBaseURL(null, url.toString(), "text/html", "utf-8", null);}mAgentWeb.getWebCreator().getWebView().setDownloadListener(new DownloadListener() {@Overridepublic void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {Uri uri = Uri.parse(url);Intent intent = new Intent(Intent.ACTION_VIEW, uri);startActivity(intent);}});}@Overrideprotected void initView() {url = getIntent().getStringExtra("url");mLinearLayoutWebView = findViewById(R.id.linear_layout_webview);new RxPermissions(this).requestEach(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_PHONE_STATE).subscribe(new SubscriberCallBack<>(new ApiCallback<Permission>() {@Overridepublic void onSuccess(Permission model) {if (model.granted) {} else {Toast.makeText(WebViewActivity.this, "请允许打开需要的权限", Toast.LENGTH_SHORT).show();finish();}}@Overridepublic void onFailure(String msg) {}}));}/*** @return IAgentWebSettings*/public IAgentWebSettings getSettings() {return new AbsAgentWebSettings() {private AgentWeb mAgentWeb;@Overrideprotected void bindAgentWebSupport(AgentWeb agentWeb) {this.mAgentWeb = agentWeb;}/*** AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库,* 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 ,* 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter* 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。* @param webView* @param downloadListener* @return WebListenerManager*/@Overridepublic WebListenerManager setDownloader(WebView webView, android.webkit.DownloadListener downloadListener) {return super.setDownloader(webView,DefaultDownloadImpl.create((Activity) webView.getContext(),webView,mDownloadListenerAdapter,mDownloadListenerAdapter,this.mAgentWeb.getPermissionInterceptor()));}};}protected DownloadListenerAdapter mDownloadListenerAdapter = new DownloadListenerAdapter() {@Overridepublic boolean onStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength, AgentWebDownloader.Extra extra) {extra.setOpenBreakPointDownload(true).setIcon(R.drawable.ic_file_download_black_24dp).setConnectTimeOut(6000).setBlockMaxTime(2000).setDownloadTimeOut(60L * 5L * 1000L).setAutoOpen(true).setForceDownload(false);return false;}@Overridepublic void onBindService(String url, DownloadingService downloadingService) {super.onBindService(url, downloadingService);mDownloadingService = downloadingService;LogUtils.i("TAG", "onBindService:" + url + "  DownloadingService:" + downloadingService);}@Overridepublic void onUnbindService(String url, DownloadingService downloadingService) {super.onUnbindService(url, downloadingService);mDownloadingService = null;LogUtils.i("TAG", "onUnbindService:" + url);}@Overridepublic void onProgress(String url, long loaded, long length, long usedTime) {int mProgress = (int) ((loaded) / Float.valueOf(length) * 100);LogUtils.i("TAG", "onProgress:" + mProgress);super.onProgress(url, loaded, length, usedTime);}@Overridepublic boolean onResult(String path, String url, Throwable throwable) {if (null == throwable) {//do you work} else {}return false;}};private WebViewClient mWebViewClient = new WebViewClient() {@Overridepublic void onPageStarted(WebView view, String url, Bitmap favicon) {LogUtil.e("加载地址--》" + url);}@Overridepublic void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);}@Overridepublic void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {handler.proceed();}/**** @param view* @param request* @return*/@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overridepublic WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {if (request != null && request.getUrl() != null && request.getMethod().equalsIgnoreCase("get")) {String scheme = request.getUrl().getScheme().trim();if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {if (request.getUrl().toString().contains(".html")) {try {LogUtil.e("------->" + request.getUrl().toString());URL url = new URL(injectIsParams(request.getUrl().toString()));URLConnection connection = url.openConnection();if (connection.getInputStream().toString().length() < 120) {String value = IOUtils.toString(connection.getInputStream(), "UTF-8");LogUtil.e(value);if (value.startsWith("{")) {HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);if (httpResult != null) {LogUtil.e(httpResult.toString());if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {setResult(LOGIN_OUT_RESULT);finish();}}}} else {connection.getInputStream().close();}return null;} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}}return null;}/**** @param view* @param url* @return*/@Overridepublic WebResourceResponse shouldInterceptRequest(WebView view, String url) {if (url.contains(".html")) {try {URL url1 = new URL(injectIsParams(url));URLConnection connection = url1.openConnection();if (connection.getInputStream().toString().length() < 120) {String value = IOUtils.toString(connection.getInputStream(), "UTF-8");LogUtil.e(value);if (value.startsWith("{")) {HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);if (httpResult != null) {LogUtil.e(httpResult.toString());if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {setResult(LOGIN_OUT_RESULT);finish();}}}} else {connection.getInputStream().close();}return null;} catch (IOException e) {e.printStackTrace();}}return null;}};/*** 注入参数** @param url* @return*/public static String injectIsParams(String url) {if (url != null && !url.contains("app=true&access_token=")) {if (url.contains("?")) {return url + "&app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");} else {return url + "?app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");}} else {return url;}}@Overridepublic int getStatusBarColor() {return ContextCompat.getColor(this, R.color.colorPrimary);}@Overrideprotected void onResume() {mAgentWeb.getWebLifeCycle().onResume();super.onResume();}@Overrideprotected void onPause() {mAgentWeb.getWebLifeCycle().onPause();super.onPause();}@Overrideprotected void onDestroy() {AgentWebConfig.clearDiskCache(this);mWebView.clearCache(true);mAgentWeb.getWebLifeCycle().onDestroy();super.onDestroy();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);Log.e("TAG", "结果码-->" + resultCode + "\n请求码--》" + requestCode);if (resultCode == 0) {if (mUploadCallbackAboveFive != null) {mUploadCallbackAboveFive.onReceiveValue(null);mUploadCallbackAboveFive = null;}if (mUploadMessage != null) {mUploadMessage.onReceiveValue(null);mUploadMessage = null;}return;}switch (requestCode) {//拍照case GET_PICTURE_TAKE_PHOTO:userImgFile = ImageSelector.cutPicture(this, userImgFile);break;//选择照片case GET_PICTURE_SELECT_PHOTO:userImgFile = ImageSelector.getPhotoFromIntent(data, this);userImgFile = ImageSelector.cutPicture(this, userImgFile);break;//裁剪照片case CUT_PHOTO:if (resultCode == Activity.RESULT_OK) {compressImage(userImgFile);}break;default:break;}}/*** 压缩图片** @param file*/public void compressImage(File file) {List<File> list = new ArrayList<>();list.add(file);BitmapUtil.compressFiles(list, new ICompressImageResponse() {@Overridepublic void onSuccess(List<File> images) {File imgFile = images.get(0);Uri result = ImageSelector.toURI(WebViewActivity.this, imgFile);Log.e("TAG", "文件URI-->" + result);if (null != mUploadMessage && null == mUploadCallbackAboveFive) {mUploadMessage.onReceiveValue(result);mUploadMessage = null;}if (null == mUploadMessage && null != mUploadCallbackAboveFive) {mUploadCallbackAboveFive.onReceiveValue(new Uri[]{result});mUploadCallbackAboveFive = null;}}@Overridepublic void onMarch() {}@Overridepublic void onFail() {}@Overridepublic void onFinish() {}});}/*** 显示图片选择器** @param context* @param view*/public void showSelector(final Activity context, View view) {PopupGetPictureView popupGetPictureView = new PopupGetPictureView(context, newPopupGetPictureView.GetPicture() {@Overridepublic void takePhoto(View v) {if (PermissionUtils.checkTakePhotoPermission(context)) {userImgFile = ImageSelector.takePicture(context, GET_PICTURE_TAKE_PHOTO);}}@Overridepublic void selectPhoto(View v) {if (PermissionUtils.checkAlbumStroagePermission(context)) {ImageSelector.photoPick(context, GET_PICTURE_SELECT_PHOTO);}}@Overridepublic void cancel(PopupWindow popupWindow) {if (popupWindow.isShowing()) {if (mUploadCallbackAboveFive != null) {mUploadCallbackAboveFive.onReceiveValue(null);mUploadCallbackAboveFive = null;}if (mUploadMessage != null) {mUploadMessage.onReceiveValue(null);mUploadMessage = null;}popupWindow.dismiss();}}});popupGetPictureView.showPop(view);}class LocationWebChromeClient extends WebChromeClient {private LocationWebChromeClientListener mLocationWebChromeClientListener;private GeolocationPermissions.Callback mGeolocationPermissionsCallback;private String mOrigin;private boolean mShowRequestPermissionRationale = false;public LocationWebChromeClient() {mLocationWebChromeClientListener = new LocationWebChromeClientListener() {@Overridepublic boolean onReturnFromLocationSetting(int requestCode) {if (requestCode == REQUEST_CODE_ENABLE_LOCATION) {if (mGeolocationPermissionsCallback != null) {if (isEnabledLocationFunction()) {mGeolocationPermissionsCallback.invoke(mOrigin, true, true);} else {//显然,从设置界面回来还没有开启定位服务,肯定是要拒绝定位了Toast.makeText(WebViewActivity.this, "您拒绝了定位请求", Toast.LENGTH_SHORT).show();mGeolocationPermissionsCallback.invoke(mOrigin, false, false);}}return true;}return false;}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {boolean pass = true;for (Integer result : grantResults) {if (result == PackageManager.PERMISSION_DENIED) {pass = false;break;}}if (pass) {onAccessLocationPermissionGranted();} else {onAccessLocationPermissionRejected();}}public void onAccessLocationPermissionGranted() {doJudgeLocationServiceEnabled();}public void onAccessLocationPermissionRejected() {if (mShowRequestPermissionRationale) {Toast.makeText(WebViewActivity.this, "您拒绝了定位请求", Toast.LENGTH_SHORT).show();mGeolocationPermissionsCallback.invoke(mOrigin, false, false);} else {doRequestAppSetting();}}};}@Overridepublic void onProgressChanged(WebView view, int newProgress) {//do you work}@SuppressWarnings("unused")public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType, String capture) {this.openFileChooser(uploadMsg);}@SuppressWarnings("unused")public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType) {this.openFileChooser(uploadMsg);}public void openFileChooser(ValueCallback<Uri> uploadMsg) {mUploadMessage = uploadMsg;showSelector(WebViewActivity.this, mWebView);}@Overridepublic boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {mUploadCallbackAboveFive = filePathCallback;showSelector(WebViewActivity.this, mWebView);return true;}private void doRequestAppSetting() {AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);builder.setTitle("温馨提示");builder.setMessage(String.format("您禁止了应用获取当前位置的权限,是否前往开启?", mOrigin));builder.setPositiveButton("是", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {Intent mIntent = new Intent();mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);if (Build.VERSION.SDK_INT >= 9) {mIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");mIntent.setData(Uri.fromParts("package", getPackageName(), null));} else if (Build.VERSION.SDK_INT <= 8) {mIntent.setAction(Intent.ACTION_VIEW);mIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");mIntent.putExtra("com.android.settings.ApplicationPkgName", getPackageName());}startActivity(mIntent);}});builder.setNegativeButton("否", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {mGeolocationPermissionsCallback.invoke(mOrigin, false, false);}});builder.create().show();}public LocationWebChromeClientListener getLocationWebChromeClientListener() {return mLocationWebChromeClientListener;}@Overridepublic void onGeolocationPermissionsHidePrompt() {super.onGeolocationPermissionsHidePrompt();}@Overridepublic voidonGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback geolocationPermissionsCallback) {this.mOrigin = origin;this.mGeolocationPermissionsCallback = geolocationPermissionsCallback;//是否拥有定位权限if (hasAccessLocationPermission()) {doJudgeLocationServiceEnabled();} else {//请求定位requestAccessLocationPermission();}}private void doJudgeLocationServiceEnabled() {//是否开启定位if (isEnabledLocationFunction()) {AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);builder.setTitle("温馨提示");builder.setMessage(String.format("网站%s,正在请求使用您当前的位置,是否许可?", mOrigin));builder.setPositiveButton("许可", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {mGeolocationPermissionsCallback.invoke(mOrigin, true, true);}});builder.setNegativeButton("不许可", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {mGeolocationPermissionsCallback.invoke(mOrigin, false, false);}});builder.create().show();} else {//请求开启定位功能requestEnableLocationFunction(mOrigin, mGeolocationPermissionsCallback);}}/*** 请求开启定位服务*/private void requestEnableLocationFunction(final String origin, final GeolocationPermissions.Callback geolocationPermissionsCallback) {AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);builder.setTitle("温馨提示");builder.setMessage(String.format("网站%s,正在请求使用您当前的位置,是否前往开启定位服务?", origin));builder.setPositiveButton("前往开启", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);startActivityForResult(intent, REQUEST_CODE_ENABLE_LOCATION);}});builder.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {geolocationPermissionsCallback.invoke(origin, false, false);}});builder.create().show();}private boolean isEnabledLocationFunction() {int locationMode = 0;String locationProviders;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {try {locationMode = Settings.Secure.getInt(WebViewActivity.this.getContentResolver(), Settings.Secure.LOCATION_MODE);} catch (Settings.SettingNotFoundException e) {e.printStackTrace();return false;}return locationMode != Settings.Secure.LOCATION_MODE_OFF;} else {locationProviders = Settings.Secure.getString(WebViewActivity.this.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);return !TextUtils.isEmpty(locationProviders);}}private boolean hasAccessLocationPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {return checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)== PackageManager.PERMISSION_GRANTED;} else {return ContextCompat.checkSelfPermission(WebViewActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)== PackageManager.PERMISSION_GRANTED;}}private void requestAccessLocationPermission() {// 是否要显示问什么要获取权限的解释界面/*** 什么情况下 shouldShowRequestPermissionRationale会返回true?* - 首次请求权限,但是用户禁止了,但是没有勾选“禁止后不再询问”,这样,之后的请求都会返回true* 什么情况下,shouldShowRequestPermissionRationale会返回false?* - 首次请求权限或者请求权限时,用户勾选了“禁止后不再询问”,之后的请求都会返回false*/if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {//请求过定位权限,但是被用户拒绝了(但是没有勾选“禁止后不再询问”)// 显示解释权限用途的界面,然后再继续请求权限mShowRequestPermissionRationale = true;} else {mShowRequestPermissionRationale = false;}} else {mShowRequestPermissionRationale = false;}AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);builder.setTitle("温馨提示");builder.setMessage(String.format("网站%s,正在请求使用您当前的位置,是否许可应用获取当前位置权限?", mOrigin));builder.setPositiveButton(" 是 ", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_CODE_ACCESS_LOCATION_PERMISSION);} else {//额,版本低,正常情况下,安装默认许可,然鹅,国产ROM各种魔改,有阔轮提前实现了单独授权doRequestAppSetting();}}});builder.setNegativeButton(" 否 ", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {mGeolocationPermissionsCallback.invoke(mOrigin, false, false);}});builder.create().show();}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (mWebChromeClient != null && mWebChromeClient.getLocationWebChromeClientListener() != null) {mWebChromeClient.getLocationWebChromeClientListener().onRequestPermissionsResult(requestCode, permissions, grantResults);}}interface LocationWebChromeClientListener {/*** 用户从开启定位页面回来了*/boolean onReturnFromLocationSetting(int requestCode);/*** 请求权限结果*/void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults);}private final class JavaScriptInterface {public Activity activity;public JavaScriptInterface(Activity activity) {this.activity = activity;}@JavascriptInterfacepublic void scanCode() {}@JavascriptInterfacepublic void androidGoBack() {activity.finish();}@JavascriptInterfacepublic void call(String phone) {Intent intent = new Intent();intent.setAction(Intent.ACTION_CALL);intent.setData(Uri.parse("tel:" + phone));//开启系统拨号器activity.startActivity(intent);}}
}

特别说明:使用shouldInterceptRequest()方法拼接参数,并不是修改了访问的网页url,只不过是在加载资源的时候对页面进行了一层是否登陆的验证,验证通过则进行加载页面,不通过执行相对于的操作。如果页面有重定向的,则需要在处理重定向的方法中进行验证,验证成功,则加载重定向,验证不成功,不加载,然后执行我们的操作即可。

以上使用的webview是AgentWeb,导入依赖方法:

//agentweb 下载文件、选择文件
implementation 'com.just.agentweb:download:4.0.2'
// (可选)
implementation 'com.just.agentweb:agentweb:4.0.2'
implementation 'com.just.agentweb:filechooser:4.0.2'

使用的解析库是阿里fastJson解析库:

//阿里fastJson解析库
implementation 'com.alibaba:fastjson:1.2.55'

使用的io装换库:

// https://mvnrepository.com/artifact/commons-io/commons-io
implementation group: 'commons-io', name: 'commons-io', version: '2.6'

 

 


http://chatgpt.dhexx.cn/article/wK5LyW93.shtml

相关文章

Android | 如何电脑调试APP中的webview 如何查看webview原web项目的console.log/控制台报错

目录 一、浏览器调试二、WebChromeClient onConsoleMessage()三、腾讯TBS Studio四、参考文献 最近一直在vueAndroid同时合作开发一个功能&#xff0c;我一个小小安卓开发迈向web开发真就处处是难关 一、浏览器调试 浏览器&#xff1a;chrome、Edge 说明&#xff1a;chrome是…

Android之 WebView的使用

一 简介 1.1 WebView是用来展示网页的控件&#xff0c;底层是google的WebKit的引擎。 比起苹果的WebView&#xff0c;webkit一些不足地方&#xff1a; 不能支持word等文件的预览纯标签加载&#xff0c;并不支持所有标签的加载不支持文件的下载&#xff0c;图片的放大&#xf…

Android:WebView 使用漏洞详解与解决方案

目录 1. 类型 WebView中&#xff0c;主要漏洞有三类&#xff1a; 任意代码执行漏洞密码明文存储漏洞域控制不严格漏洞 2. 具体分析 2.1 WebView 任意代码执行漏洞 出现该漏洞的原因有三个&#xff1a; WebView 中 addJavascriptInterface&#xff08;&#xff09; 接口WebVie…

android webview页面下方有input输入框,键盘弹起上滑无法拖动,导致输入内容也无法看到...

在手机端页面中有input输入框&#xff0c;输入框聚焦的时候会弹出键盘&#xff0c;如果input在页面的中下部&#xff0c;弹出的键盘会覆盖住input输入框&#xff0c;这个时候输入内容通常都是看不见的&#xff0c;用户看不到自己输入自己已经输入的内容这种体验非常的不好&…

Google上架因为WebView被拒

原因&#xff1a;在WebViewClient的回调方法onReceivedSslError里只单纯的写了handler.proceed();没给出明确的原因 两种解决方法&#xff1a; 1、去掉WebViewClient的回调方法onReceivedSslError 2、修改onReceivedSslError如下所示 Override public void onReceivedSslEr…

Android 使用Webview加载PDF文件

一、核心代码 protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_pdf_renderer);WebSettings webSettings weContainer.getSettings();webSettings.setJavaScriptEnabled(true);// 设置WebView是否允…

Android中解决ScrollView嵌套WebView底部留白太多和高度问题

前言&#xff1a; Android中WebView的坑很多&#xff0c;比如低版本内核不支持&#xff0c;加载速度慢&#xff0c;重定向等等&#xff0c;当使用ScrollView嵌套WebView时坑更多&#xff0c;有人说为啥要嵌套&#xff1f;单独使用WebView或者ScrollView不行吗&#xff1f;答案…

webview适配(一):文件选择,相机拍照,相册选择

说起来android适配webview就是比较烦人&#xff0c;本人遇到过很多坑&#xff0c;但是之前从来没有过记录&#xff0c;例如&#xff1a;文件选择框&#xff0c;toast弹框&#xff0c;视频不正常播放&#xff0c;视频各种不全屏&#xff08;网上说的方法都不行时候就崩溃了&…

Android跟web哪个好,比系统自带的WebView更好用 | AgentWeb

名称 AgentWeb 语言 Android 平台 GitHub 作者 Justson 在混合化开发大行其道的今天&#xff0c;安卓开发经常会用到WebView&#xff0c;用于加载网页。系统自带的WebView性能和流畅度都一般&#xff0c;今天给大家推荐一款第三方WebView&#xff0c;性能比系统自带的要好&…

X5 浏览器内核调研报告

关于这份调研报告&#xff0c;不是从技术角度深入探索&#xff0c;重点是从产品本身分析&#xff0c;通俗易懂才是重点。主要是为了锻炼平时做技术调研和竞品分析的能力&#xff0c;以及业务拓展的技术储备。内容有点多&#xff0c;下面 **X5 **内核调研报告将分为三个环节&…

南京理工大学计算机考研资料汇总

南京理工大学研究生院 http://gs.njust.edu.cn/ 南京理工大学计算机科学与工程学院 http://cs.njust.edu.cn/ 南京理工大学计算机科学与工程学院始建于1953年创办的哈尔滨军事工程学院模拟计算机研究组&#xff0c;先后经历了炮兵工程学院计算机教研室&#xff08;1960年&a…

上海海洋大学计算机考研资料汇总

上海海洋大学研招网 上海海洋大学信息学院 上海海洋大学&#xff08;Shanghai Ocean University&#xff09;是上海市人民政府与国家海洋局、农业农村部共建高校&#xff0c;国家“双一流”世界一流学科建设高校&#xff0c;入选国家卓越农林人才教育培养计划、国家建设高水平…

2024东华大学计算机考研信息汇总

最新数据见&#xff1a;东华大学_信息汇总_N诺计算机考研 东华大学计算机科学与技术学院官网&#xff1a;http://cst.dhu.edu.cn/ 东华大学&#xff08;Donghua University&#xff09;&#xff0c;简称“东华”&#xff0c;地处中国上海&#xff0c;是教育部直属、国家“211工…

西南石油大学计算机考研资料汇总

西南石油大学&#xff08;Southwest Petroleum University&#xff09;&#xff0c;简称“西南石大”&#xff0c;坐落于四川省成都市&#xff0c;是经中华人民共和国教育部备案的一所中央与地方共建、以四川省人民政府管理为主的高等院校&#xff0c;是世界一流学科建设高校、…

2023东北大学计算机考研信息汇总

完整内容见&#xff1a;东北大学 东北大学计算机科学与工程学院 东北大学软件学院 东北大学秦皇岛分校 东北大学&#xff08;Northeastern University&#xff09;&#xff0c;简称东大&#xff08;NEU&#xff09;&#xff0c;中华人民共和国教育部直属的高水平研究型全国…

2023上海海洋大学计算机考研信息汇总

上海海洋大学研招网 上海海洋大学信息学院 上海海洋大学&#xff08;Shanghai Ocean University&#xff09;是上海市人民政府与国家海洋局、农业农村部共建高校&#xff0c;国家“双一流”世界一流学科建设高校&#xff0c;入选国家卓越农林人才教育培养计划、国家建设高水平…

东北大学计算机考研资料汇总

东北大学计算机科学与工程学院 东北大学软件学院 东北大学秦皇岛分校 东北大学&#xff08;Northeastern University&#xff09;&#xff0c;简称东大&#xff08;NEU&#xff09;&#xff0c;中华人民共和国教育部直属的高水平研究型全国重点大学&#xff0c;坐落于东北…

2023北京大学计算机考研信息汇总

原文转载于&#xff1a;北京大学 N诺小程序 - 计算机学习考研必备神器 北京大学信息科学技术学院 北京大学软件与微电子学院 北京大学前沿交叉学科研究院 北京大学信息工程学院 北大研究生院 北京大学&#xff08;Peking University&#xff09;简称“北大”&#…

北京大学计算机考研资料汇总

北京大学信息科学技术学院 北京大学软件与微电子学院 北京大学前沿交叉学科研究院 北京大学信息工程学院 北大研究生院 北京大学&#xff08;Peking University&#xff09;简称“北大”&#xff0c;诞生于1898年&#xff0c;初名京师大学堂&#xff0c;是中国近代第…

2023西南石油大学计算机考研信息汇总

西南石油大学&#xff08;Southwest Petroleum University&#xff09;&#xff0c;简称“西南石大”&#xff0c;坐落于四川省成都市&#xff0c;是经中华人民共和国教育部备案的一所中央与地方共建、以四川省人民政府管理为主的高等院校&#xff0c;是世界一流学科建设高校、…