Recently, I met a requirement in a project. Since it is an international project, the computer room is deployed in a new country. The H5 domain name deployed in the computer room is different from the original one, requiring the client to intercept H5 and change the Host.

Several schemes have been tried as follows:

  1. Override the WebView loadUrl() method in which you change the Url.
    @Override
    public void loadUrl(String url) {... url = convertUrl(url); .// You must call super to let the system continue loading the new URL
        super.loadUrl(url);
    }
Copy the code

In the above scheme, it was found in the test that there was a jump to the secondary page in the H5 page, but it did not go.

  1. ShouldOverrideUrlLoading () overwrites WebViewClient shouldOverrideUrlLoading()
/**
     * Give the host application a chance to take over the control when a new
     * url is about to be loaded in the current WebView. If WebViewClient is not
     * provided, by default WebView will ask Activity Manager to choose the
     * proper handler for the url. If WebViewClient is provided, return true
     * means the host application handles the url, while return false means the
     * current WebView handles the url.
     * This method is not called for requests using the POST "method".
     *
     * @param view The WebView that is initiating the callback.
     * @param url The url to be loaded.
     * @return True if the host application wants to leave the current WebView
     *         and handle the url itself, otherwise return false.
     * @deprecated Use {@link #shouldOverrideUrlLoading(WebView, WebResourceRequest)
     *             shouldOverrideUrlLoading(WebView, WebResourceRequest)} instead.
     */
    @Deprecated
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }

    /** * Give the host application a chance to take over the control when a new * url is about to be loaded in the current WebView. If WebViewClient is not * provided, by default WebView will ask Activity Manager to choose the * proper handler for the url. If WebViewClient is provided, return true * means the host application handles the url, while return false means the * current WebView handles the url. * * <p>Notes: * <ul> * <li>This method is not called for requests using the POST &quot; method&quot; .</li> * <li>This method is also called for subframes with non-http schemes, thus it is * strongly disadvised to unconditionally call {@link WebView#loadUrl(String)}
     * with the request's url from inside the method and then return true,
     * as this will make WebView to attempt loading a non-http url, and thus fail.</li>
     * </ul>
     * </p>
     *
     * @param view The WebView that is initiating the callback.
     * @param request Object containing the details of the request.
     * @return True if the host application wants to leave the current WebView
     *         and handle the url itself, otherwise return false.
     */
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        return shouldOverrideUrlLoading(view, request.getUrl().toString());
    }
Copy the code

If the development does not set up the WebViewClient, the WebView will let the Activity Manager choose the appropriate processing method (possibly using a browser). If WebViewClient is set, this method returns true and the main program handles the URL change. If false, the current WebView handles the url change, which is the default. (does not execute the loadUrl method of WebView)

The initial idea was to change the URL in shouldOverrideUrlLoading(), but it turns out that it can be intercepted here, but the changed URL cannot be loaded by default. Only the main program shows the call loading.

    @Override
    public boolean shouldOverrideUrlLoading(final String url) {
        if (isInterceptUrlLoading(url)) {
            // Focus on secondary page hops
            // If you return false directly, it will be loaded by default, so you cannot change the URL, and it will not go into loadUrl. You cannot change the URL in this method
            getWebView().loadUrl(url);
            return true;
        }
        return false;
    }
Copy the code
  1. Look for other better solutions

The solution to method 2 above will change the way the ORIGINAL URL is loaded, so I looked for a better solution.

Rewrite the WebViewClient shouldInterceptRequest method.

/**
     * Notify the host application of a resource request and allow the
     * application to return the data.  If the return value is null, the WebView
     * will continue to load the resource as usual.  Otherwise, the return
     * response and data will be used.  NOTE:This method is called on a thread * other than the UI thread so clients should exercise caution * when accessing private  data or the view system. * *@param view The {@link android.webkit.WebView} that is requesting the
     *             resource.
     * @param url The raw url of the resource.
     * @return A {@link android.webkit.WebResourceResponse} containing the
     *         response information or null if the WebView should load the
     *         resource itself.
     * @deprecated Use {@link #shouldInterceptRequest(WebView, WebResourceRequest)
     *             shouldInterceptRequest(WebView, WebResourceRequest)} instead.
     */
    @Deprecated
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        return null;
    }

    /**
     * Notify the host application of a resource request and allow the
     * application to return the data.  If the return value is null, the WebView
     * will continue to load the resource as usual.  Otherwise, the return
     * response and data will be used.  NOTE:This method is called on a thread * other than the UI thread so clients should exercise caution * when accessing private  data or the view system. * *@param view The {@link android.webkit.WebView} that is requesting the
     *             resource.
     * @param request Object containing the details of the request.
     * @return A {@link android.webkit.WebResourceResponse} containing the
     *         response information or null if the WebView should load the
     *         resource itself.
     */
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        return shouldInterceptRequest(view, request.getUrl().toString());
    }
Copy the code

This method can intercept all requests, except Html pages, other resources JS, CSS will intercept.

With annotations, if null is returned, the WebView will still load the original URL by default. You need to create your own WebResourceResponse.

You can load resources offline here, but changing urls alone is not a good idea because you cannot create web Resources esponse.

  1. conclusion

Finally, a combination of method 1 and method 2 is used to deal with it.