Webview 重定向和 net::ERR_UNKNOWN_URL_SCHEME 解析及解决方案

产生原因

       首先来说下 webview重定向,其定义没有明确的官方解释,发生的原因是请求的链接(url)在加载完成后发生了变化 (eg.比如你的代码中设置webview加载的是网页A,打开后发现加载的是网页B); 关于 net::ERR_UNKNOWN_URL_SCHEME (如下图所示),因为webview只能识别http和https协议,遇到图中这种"wvhzpj://"开头的自定义协议时就无法识别,便会提示ERR_UNKNOWN_URL_SCHEME这样的错误。

 
如何解决

       需要重写WebviewClient类中的 shouldOverriderUrlLoading 方法( 选取方法参数为(Webview view , String url )的那种,如下图),该方法可以对webview将要加载的url 进行处理,我们在此处对 会发生重定向的 url 和 不以 "http://"、"https//" 开头的自定义协议 进行拦截处理。该方法的返回值为boolean 类型,表示是否阻止webview继续加载url,默认值为 false。当返回false,表示不进行阻止,webview认为当前的url需要进行处理,会继续加载;返回 true,表示阻止webview继续加载url,等待我们进行处理

       那么如何判断 webview 将要加载的url会不会发生重定向呢?WebView中有个静态类 HitTestResult,这个类中有一些被 final 修饰的 int 变量,这些变量表示webview加载的url所属的网页类型。还有两个get方法 getType() getExtra() , getType() 表示获取加载url的网页类型; getExtra() 表示根据url打开的网页类型,返回一个extra信息,如果打开类型为 UNKNOWN_TYPE(打开的内容未知) ,此时 url 就会通过requestFocusNodeHref(Message)方法异步重定向,则extra就没有返回值,为null。经过上面分析,我们可以对getType() 和 getExtra() 获取到的返回值进行判断,当 getType()==0 (打开内容未知) 或者 getExtra() 为 null 时,就认为webview加载的url会发生重定向,我们此时就在shouldOverriderUrlLoading方法中对其进行处理。

下表为上图 HitTestResult 类中变量值所对应打开的网页类型

好的,我们接下来看看如何判定加载的url是非 http/https 的自定义协议。很简单,对shouldOverriderUrlLoading方法中的参数 String url进行判断,url.startsWith("http://")||url.startsWith("https://") 即表示加载的url是 http/https 协议,不对其进行拦截处理,反之则进行拦截处理。(见下图)

解决方案
 

       下面贴出我在代码中关于网页重定向和加载自定义协议链接的解决方案,我对会发生重定向和自定义协议的网址进行拦截,调用手机系统浏览器打开网页(我没有获取将要重定向url的最终加载地址,比较麻烦,有便捷方式的朋友可以留言指出)。博主集成的是腾讯X5webview,和webview用法是一样的。该注释说明的地方我尽量标注了,仅供参考,直接复制粘贴需要替换webview控件和Content,请自行处理。

@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {

    WebView.HitTestResult hit = view.getHitTestResult();
    //hit.getExtra()为null或者hit.getType() == 0都表示即将加载的URL会发生重定向,需要做拦截处理
    if (TextUtils.isEmpty(hit.getExtra()) || hit.getType() == 0) {
        //通过判断开头协议就可解决大部分重定向问题了,有另外的需求可以在此判断下操作
        Log.e("重定向", "重定向: " + hit.getType() + " && EXTRA()" + hit.getExtra() + "------");
        Log.e("重定向", "GetURL: " + view.getUrl() + "\n" +"getOriginalUrl()"+ view.getOriginalUrl());
        Log.d("重定向", "URL: " + url);
    }

    if (url.startsWith("http://") || url.startsWith("https://")) { //加载的url是http/https协议地址
        view.loadUrl(url);
        return false; //返回false表示此url默认由系统处理,url未加载完成,会继续往下走

    } else { //加载的url是自定义协议地址
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

}

此外,webview在加载的url为下载链接时需要再做下处理,需要用到 setDownloadListener() 方法,在回调监听中设置当打开的url为下载链接时调用手机浏览器打开下载链接。

/**
 * setDownloadListener()是对加载的url是下载地址时的回调
 */
tencentWeb.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
 
        // 上面的参数中,url对应文件下载地址,mimetype对应下载文件的MIME类型
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri = Uri.parse(url);
        intent.addCategory(Intent.CATEGORY_BROWSABLE);
        intent.setData(uri);
        context.startActivity(intent);
    }
});

关于webview更多的探索博主仍在探寻中,本文有不对的地方欢迎指出

————————————————
转载于:https://blog.csdn.net/qq_41188773/article/details/89669354

猜你喜欢

转载自blog.csdn.net/weixin_42602900/article/details/132871142
今日推荐