最近做项目,遇到一个需求,因为是国际化项目,在新的国家部署机房,在该机房部署的H5域名和原来的不一样,要求客户端拦截H5,并更改Host。
尝试了几种方案如下:
@Override public void loadUrl(String url) { ...... url = convertUrl(url); ...... // 必须调用super,让系统继续加载新的url super.loadUrl(url); } 复制代码
上面的方案,在测试中发现,H5页面中有跳转二级页面时,没有走。
/** * 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 "method".</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()); } 复制代码
如果开发没有设置WebViewClient,WebView会让Activity Manager选择合适的处理方法(可能使用浏览器)。如果设置了WebViewClient,该方法返回true,则主程序处理改url,如果返回false,则当前WebView处理,即系统默认处理。(不会执行WebView的loadUrl方法)
最开始的想法是在shouldOverrideUrlLoading()方法更改url,不过发现,这里可以拦截到,但更改后的url,无法让系统默认加载。只能主程序显示调用加载。
@Override public boolean shouldOverrideUrlLoading(final String url) { if (isInterceptUrlLoading(url)) { // 重点处理二级页面跳转的情况 // 如果直接返回false,会由系统默认加载,则无法改变url,且也不会走到loadUrl中,无法在该方法中更改url getWebView().loadUrl(url); return true; } return false; } 复制代码
上面方法2的解法,会改变原来url的加载方式,所以找了找有没有其他更好的办法。
重写WebViewClient的shouldInterceptRequest方法。
/** * 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()); } 复制代码
该方法可以拦截所有请求,除了Html的页面,其他资源js、css都会拦截到。
通过注释,如果返回null,则WebView还是会默认加载原来的url,需要自己创建WebResourceResponse。
可以在此处做离线资源的加载,但不适合只更改url,因为无法创建WebResourceResponse。
最后使用方法1和方法2的结合来处理的。