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

前言

最近公司项目需求,在项目中嵌入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);
 }

 @Override
 protected int getLayout() {
  return R.layout.activity_web_view;
 }

 @Override
 protected 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() {
   @Override
   public 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);
   }
  });
 }

 @Override
 protected 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>() {
     @Override
     public void onSuccess(Permission model) {
      if (model.granted) {

      } else {
       Toast.makeText(WebViewActivity.this, "请允许打开需要的权限", Toast.LENGTH_SHORT).show();
       finish();
      }
     }

     @Override
     public void onFailure(String msg) {

     }
    }));
 }

 /**
  * @return IAgentWebSettings
  */
 public IAgentWebSettings getSettings() {
  return new AbsAgentWebSettings() {
   private AgentWeb mAgentWeb;

   @Override
   protected 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
    */
   @Override
   public 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() {

  @Override
  public 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;
  }

  @Override
  public void onBindService(String url, DownloadingService downloadingService) {
   super.onBindService(url, downloadingService);
   mDownloadingService = downloadingService;
   LogUtils.i("TAG", "onBindService:" + url + " DownloadingService:" + downloadingService);
  }

  @Override
  public void onUnbindService(String url, DownloadingService downloadingService) {
   super.onUnbindService(url, downloadingService);
   mDownloadingService = null;
   LogUtils.i("TAG", "onUnbindService:" + url);
  }

  @Override
  public 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);
  }

  @Override
  public boolean onResult(String path, String url, Throwable throwable) {
   if (null == throwable) {
    //do you work
   } else {

   }
   return false;
  }
 };
 private WebViewClient mWebViewClient = new WebViewClient() {
  @Override
  public void onPageStarted(WebView view, String url, Bitmap favicon) {
   LogUtil.e("加载地址--》" + url);
  }

  @Override
  public void onPageFinished(WebView view, String url) {
   super.onPageFinished(view, url);
  }

  @Override
  public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
   handler.proceed();
  }

  /**
   *
   * @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())) {
           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
   */
  @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())) {
         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;
  }
 }
 @Override
 public int getStatusBarColor() {
  return ContextCompat.getColor(this, R.color.colorPrimary);
 }
 @Override
 protected void onResume() {
  mAgentWeb.getWebLifeCycle().onResume();
  super.onResume();
 }
 @Override
 protected void onPause() {
  mAgentWeb.getWebLifeCycle().onPause();
  super.onPause();
 }
 @Override
 protected void onDestroy() {
  AgentWebConfig.clearDiskCache(this);
  mWebView.clearCache(true);
  mAgentWeb.getWebLifeCycle().onDestroy();
  super.onDestroy();
 }
 @Override
 protected 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() {
   @Override
   public 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;
    }
   }

   @Override
   public void onMarch() {

   }

   @Override
   public void onFail() {

   }

   @Override
   public void onFinish() {

   }
  });
 }

 /**
  * 显示图片选择器
  *
  * @param context
  * @param view
  */
 public void showSelector(final Activity context, View view) {
  PopupGetPictureView popupGetPictureView = new PopupGetPictureView(context, new
    PopupGetPictureView.GetPicture() {
     @Override
     public void takePhoto(View v) {
      if (PermissionUtils.checkTakePhotoPermission(context)) {
       userImgFile = ImageSelector.takePicture(context, GET_PICTURE_TAKE_PHOTO);
      }
     }

     @Override
     public void selectPhoto(View v) {
      if (PermissionUtils.checkAlbumStroagePermission(context)) {
       ImageSelector.photoPick(context, GET_PICTURE_SELECT_PHOTO);
      }
     }

     @Override
     public 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() {
    @Override
    public 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;
    }

    @Override
    public 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();
     }
    }
   };
  }

  @Override
  public 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);
  }

  @Override
  public 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() {
    @Override
    public 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() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
     mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
    }
   });
   builder.create().show();
  }
  public LocationWebChromeClientListener getLocationWebChromeClientListener() {
   return mLocationWebChromeClientListener;
  }
  @Override
  public void onGeolocationPermissionsHidePrompt() {
   super.onGeolocationPermissionsHidePrompt();
  }
  @Override
  public void
  onGeolocationPermissionsShowPrompt(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() {
     @Override
     public void onClick(DialogInterface dialogInterface, int i) {
      mGeolocationPermissionsCallback.invoke(mOrigin, true, true);
     }
    });
    builder.setNegativeButton("不许可", new DialogInterface.OnClickListener() {
     @Override
     public 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() {
    @Override
    public 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() {
    @Override
    public 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() {
    @Override
    public 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() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
     mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
    }
   });
   builder.create().show();
  }

 }

 @Override
 public 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;
  }

  @JavascriptInterface
  public void scanCode() {

  }

  @JavascriptInterface
  public void androidGoBack() {
   activity.finish();
  }

  @JavascriptInterface
  public 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'

以上这篇webview添加参数与修改请求头的user-agent实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Android WebView拦截iframe标签内部跳转教程

    最近项目里有个广告位需要动态配置,后台给了一段 html 嵌套iframe标签的代码,需要Android拦截iframe内部的跳转,自己做处理. 比如,下面是一段html代码,嵌套这iframe标签,src就是跳转地址,我现在就要当你点击该网址的时候做拦截,自己做处理而不是跳转. <html> <iframe src="https://www.jb51.net/" frameborder='0' scrolling='no' width='100%' height='

  • Android WebView userAgent 设置为桌面UA实例

    最近一个大屏项目中使用到支付宝扫码支付,但是webview加载扫码支付链接时会自动跳转到移动版页面,网上查找怎么设置,没找到解决方案.于是自己随便试了下 webview.getSettings().setUserAgentString("PC"): 或 webview.getSettings().setUserAgentString("电脑"): 竟然真的可以. userAgent可以设置浏览器标识,Android/iphone/ipod/ipad/PC等,这个应该

  • 解决webview内的iframe中的事件不可用的问题

    最近做Android的Webview开发,使用iframe中嵌入了很多页面,嵌入的页面却不可用,最后发现是 webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return super.shouldOverrideUrlLoading(view, url); } 不要覆写 shouldOverride

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

    前言 最近公司项目需求,在项目中嵌入h5页面,一般原生,看着感觉跟往常一样,一个地址就完全ok了,如果是这样那就没有这个博文的必要了! 项目的登录使用的token登录,在移动端的登录是原生的,但是h5也是有登录页面,这就需要控制token的过期时间了,但是想达到的网页访问使用网页的cookie,app登录使用的是app原生的登录token,在网页的cookie登录过期的时候,网页是可以正常退回登录页面,而在app嵌入的h5也需要根据token是否过期,决定是否返回登录页. 那么,问题就是在此产生

  • SpringCloud Feign转发请求头(防止session失效)的解决方案

    微服务开发中经常有这样的需求,公司自定义了通用的请求头,需要在微服务的调用链中转发,比如在请求头中加入了token,或者某个自定义的信息uniqueId,总之就是自定义的一个键值对的东东,A服务调用B服务,B服务调用C服务,这样通用的东西如何让他在一个调用链中不断地传递下去呢?以A服务为例: 方案1 最傻的办法,在程序中获取,调用B的时候再转发,怎么获取在Controller中国通过注解获取,或者通过request对象获取,这个不难,在请求B服务的时候,通过注解将值放进去即可:简代码如下: 获取

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

    需求背景: 需要在用户点击提交按钮的时候拦截用户提交的数据. 遇到的问题: 1.页面不是自家前端做的,不能修改网页中的代码 2.要拦截的请求不是get请求,而是一个post请求 (难点在于:如果拦截的请求是get请求的话,我只需要拿到url,将后面拼接的参数键值对取出来就好了,但是post请求的参数键值对我们是看不到的...) 解决重点: 重写webViewClient的shouldInterceptRequest这个方法 1.这个方法是API21以后才出现的,还有一个过时的方法也要重写,不要忘

  • java swagger ui 添加header请求头参数的方法

    我用到的swagger 主要有三款产品,swagger editor,swagger ui 和swagger codegen. swagger editor:主要是一个本地客户端,用来自己添加api,自己来测试,相当于一个api的可视化测试工具和定义工具吧. swagger ui:主要用户嵌入到项目中,将所有的接口生成一个可视化的页面,方便前后端联调 swagger codegen:主要用于通过swagger来自动生成代码 我用的swagger ui主要在java项目中.将所有的http接口提供

  • vue+axios全局添加请求头和参数操作

    走登录的接口都会返回一个token值,然后存起来方便之后调接口的时候给后台传过去,传给后台的方式有两种:(具体使用哪种需要和后台商量) 1.放在请求头中 2.放在接口的参数中 1.放在请求头中 下面代码是从本地cookie中拿token VueCookie:一个用于处理浏览器cookies的简单Vue.js插件. // 在封装axios的文件中添加拦截器 // 添加请求拦截器,在请求头中加token service.interceptors.request.use( config => { //

  • 如何通过zuul添加或修改请求参数

    zuul添加或修改请求参数 一.为什么要用到这个 在基于 springcloud 构建的微服务系统中,通常使用网关zuul来进行一些用户验证等过滤的操作,比如 用户在 header 或者 url 参数中存放了 token ,网关层需要 用该 token 查出用户 的 userId ,并存放于 request 中,以便后续微服务可以直接使用而避免再去用 token 查询. 二.基础知识 在 zuul 中最大的用法的除了路由之外,就是过滤器了,自定义过滤器需实现接口 ZuulFilter ,在 ru

  • SpringCloud中分析讲解Feign组件添加请求头有哪些坑梳理

    目录 分析 解决 按官方修改的示例: #MidServerClient.java import feign.Param; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @FeignCl

  • 使用Feign调用时添加验证信息token到请求头方式

    目录 Feign调用添加验证信息token到请求头 1.这是最简单的一个方法 2.这个方法是网上大多数人的用法 3.第三种方法就是大神的方法了 Feign中增加请求头 最近遇到项目在调用 Feign调用添加验证信息token到请求头 1.这是最简单的一个方法 但是需要对每个调用都一一添加,就是使用@RequestHeader注解添加参数到请求头中去 @FeignClient(name = "capability-register", fallback = ApiServiceClien

  • python爬虫添加请求头代码实例

    这篇文章主要介绍了python爬虫添加请求头代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 request import requests headers = { # 'Accept': 'application/json, text/javascript, */*; q=0.01', # 'Accept': '*/*', # 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7

  • Python headers请求头如何实现快速添加

    1.为什么要设置headers? 在请求网页爬取的时候,输出的text信息中会出现抱歉,无法访问等字眼,这就是禁止爬取,需要通过反爬机制去解决这个问题. headers是解决requests请求反爬的方法之一,相当于我们进去这个网页的服务器本身,假装自己本身在爬取数据. 对反爬虫网页,可以设置一些headers信息,模拟成浏览器取访问网站 . 2. headers在哪里找? 谷歌或者火狐浏览器,在网页面上点击:右键–>检查–>剩余按照图中显示操作,需要按Fn+F5刷新出网页来 有的浏览器是点击

随机推荐