Intercept all requests in WebView and replace URL example in Android environment

  • 2021-12-04 19:53:08
  • OfStack

Requirement background

To receive such a demand, it is necessary to add a flag bit of xxx=1 to all network requests of WebView in the requested url.

For example, http://www.baidu.com with the flag bit becomes http://www.baidu.com? xxx=1

Find a solution

Beginning with Android API 11 (3.0), WebView began to provide one API within WebViewClient, as follows:


public WebResourceResponse shouldInterceptRequest(WebView view, String url) 

That is to say, just implement the shouldInterceptRequest method of WebViewClient and then call setWebViewClient of WebView.

However, above API21, the above API was abandoned and a new API was used, as follows:


public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) 

Well, in order to support as many versions as possible, it seems that both need to be implemented, and it turns out that String url, which is very easy to use at first sight, has become an WebResourceRequest request. WebResourceRequest is an interface and is defined as follows:


public interface WebResourceRequest { 
 Uri getUrl();
 boolean isForMainFrame();
 boolean hasGesture();
 String getMethod();
 Map<String, String> getRequestHeaders();
}

There is no way to directly replace the request.

Then I searched for a reference to him in Android code, and click me to search. Then it is found that the internal implementation of private static class WebResourceRequestImpl implements WebResourceRequest is only a simple entity. Then it is very easy to replace this thing. You can do it in three ways:

Dynamic agent Reflex Realization

Realization

The plan is determined, and the rest is simple. Go directly to the code.

The first is the method of adding that flag bit to the URL string


public static String injectIsParams(String url) { 
 if (url != null && !url.contains("xxx=") {
  if (url.contains("?")) {
   return url + "&xxx=1";
  } else {
   return url + "?xxx=1";
  }
 } else {
  return url;
 }
}

Then you have to intercept all requests


webView.setWebViewClient(new WebViewClient() {
 
 @SuppressLint("NewApi")
 @Override
 public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
  if (request != null && request.getUrl() != null) {
   String scheme = request.getUrl().getScheme().trim();
   if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
    return super.shouldInterceptRequest(view, new WebResourceRequest() {
     @Override
     public Uri getUrl() {
      return Uri.parse(injectIsParams(request.getUrl().toString()));
     }
 
     @SuppressLint("NewApi")
     @Override
     public boolean isForMainFrame() {
      return request.isForMainFrame();
     }
 
     @SuppressLint("NewApi")
     @Override
     public boolean hasGesture() {
      return request.hasGesture();
     }
 
     @SuppressLint("NewApi")
     @Override
     public String getMethod() {
      return request.getMethod();
     }
 
     @SuppressLint("NewApi")
     @Override
     public Map<String, String> getRequestHeaders() {
      return request.getRequestHeaders();
     }
    });
   }
  }
  return super.shouldInterceptRequest(view, request);
 }
 
 
 @Override
 public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
  if (!TextUtils.isEmpty(url) && Uri.parse(url).getScheme() != null) {
   String scheme = Uri.parse(url).getScheme().trim();
   if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
    return super.shouldInterceptRequest(view, injectIsParams(url));
   }
  }
  return super.shouldInterceptRequest(view, url);
 }
 
});

You're done.

Welcome to point out the problems in the code ~ ~ 1 learning progress

Note: Pay attention to protecting Scheme of URL, and filter http and https in the code.

Extension

The above API found that there are more ways to play, such as:

Replace WebResourceResponse and construct your own WebResourceResponse. For example, the following code replaces the network picture to be requested with the local file in 1 package.

WebResourceResponse response = null; 
if (url.contains("logo")) { 
 try {
  InputStream is = getAssets().open("test.png");
  response = new WebResourceResponse("image/png", "UTF-8", is);
 } catch (IOException e) {
  e.printStackTrace();
 }  
}
return response; 

WebResourceRequest interface is used in API 21 (5.0) and above, which can modify the requesting Header


@Override
public Map<String, String> getRequestHeaders() { 
 return request.getRequestHeaders();
}

GET requests and POST requests can be distinguished in API 21 (5.0) and above, and can be used in some cases when it is necessary to distinguish different kinds of AJAX requests.


Related articles: