IM使用的网页浏览器以及交互架构

这一章说的是网页浏览器。

app时常会使用到自定义WebView。但是想做成一个高可用性的WebView配置其实很有技巧。这节就给一个完整自定义WebView的配置。这里包括对浏览器的适配,还有一些浏览器的地址验证。
```
/**
* 初始化WebView
*/
fun initWeb() {
mProgress = findViewById(R.id.web_progress)
mProgress!!.setColorSchemeResources(R.color.common_pink_5, R.color.common_light_green_2, R.color.common_blue_3)

    web = findViewById(R.id.web)
    web!!.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
    val webSettings = web!!.settings

    webSettings.javaScriptEnabled = true
    //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)

    //设置自适应屏幕,两者合用
    webSettings.useWideViewPort = true  //将图片调整到适合webview的大小
    webSettings.loadWithOverviewMode = true // 缩放至屏幕的大小

    webSettings.displayZoomControls = false //隐藏原生的缩放控件

    webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN //支持内容重新布局
    webSettings.supportMultipleWindows()  //多窗口
    // webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);  //关闭webview中缓存
    webSettings.allowFileAccess = true  //设置可以访问文件
    webSettings.setNeedInitialFocus(true) //当webview调用requestFocus时为webview设置节点
    webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
    webSettings.loadsImagesAutomatically = true  //支持自动加载图片

    webSettings.defaultTextEncodingName = "UTF-8"


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        webSettings.allowFileAccessFromFileURLs = false
        webSettings.allowUniversalAccessFromFileURLs = false
    }

    // 设置可以支持缩放
    webSettings.setSupportZoom(true)
    // // 设置出现缩放工具
    webSettings.builtInZoomControls = true

    // 自适应屏幕
    webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL

    //缓存相关
    webSettings.setAppCacheEnabled(true)
    webSettings.domStorageEnabled = true

    //开启定位
    webSettings.setGeolocationEnabled(true)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
    }

    web!!.webViewClient = object : BridgeWebViewClient(web!!) {
        override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
            Logger.e("网页链接加载失败:" + description + "->" + failingUrl + ",当前网页:" + view.url)

            try {
                //                String host = Uri.parse(failingUrl).getHost();
                val scheme = Uri.parse(failingUrl).scheme
                if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
                    if (TextUtils.equals(failingUrl, view.url)) {

                    }
                }
            } catch (ex: Exception) {
                Logger.e("", ex)
            }

            //            showError();
        }

        @RequiresApi(api = Build.VERSION_CODES.M)
        override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) {
            Logger.e("网页链接加载失败:" + error.errorCode + "->" + request.url + ",当前网页:" + view.url)
            try {
                //                String host = request.getUrl().getHost();
                val scheme = request.url.scheme
                if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
                    if (TextUtils.equals(request.url.toString(), view.url)) {

                    }
                }
            } catch (ex: Exception) {
                Logger.e("", ex)
            }

            //            showError();
        }

        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)
            mProgress?.visibility = View.GONE
            mTextSwitcher?.setText(view?.title)

        }

        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
            super.onPageStarted(view, url, favicon)
            mProgress?.visibility = View.VISIBLE
        }

        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
         override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
            Logger.d("网页重写地址:" + request?.url)
            try {
                request ?: return super.shouldOverrideUrlLoading(view, request)
                val host = request.url.host
                val scheme = request.url.scheme
                if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
                    return checkInvalidAddressV4(host)
                }
            } catch (ex: Exception) {
                Logger.e("网页重加载失败", ex)
            }

            return super.shouldOverrideUrlLoading(view, request)
        }

        override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
           Logger.d("网页重写地址:" + url)
            if (TextUtils.isEmpty(url)) {
                return true
            }

            val uri = Uri.parse(url)
            try {
                val host = uri.host
                val scheme = uri.scheme
                if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
                    if (checkInvalidAddressV4(host)) {
                        return false
                    } else {
                        return false
                    }
                }
            } catch (ex: Exception) {
                Logger.e("网页重加载失败", ex)
            }
            return super.shouldOverrideUrlLoading(view, url)
        }

        override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) {
            try {
                handler.proceed()
            } catch (ex: Exception) {
                Logger.e("处理网页SSL证书失败", ex)
            }

        }

    }

    web!!.webChromeClient = object : WebChromeClient() {
        override fun onProgressChanged(view: WebView, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
        }

    }
    val url = baseIntent!!.getStringExtra(ARouterConstants.PARAM.WEB_URL)
    JavaScriptInterface.inject(this, url, web!!)  //添加jsbridge框架
    web!!.loadUrl(url)  //加载网页
}

/**
* 检测是否不可用地址
* @param addressString(ipv4)
* @return
*/
fun checkInvalidAddressV4(addressString: String): Boolean {
try {

        val addressStrings = addressString.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        val address = ByteArray(addressStrings.size)
        for (i in address.indices) {
            address[i] = java.lang.Byte.valueOf(addressStrings[i])!!
        }
        if (address.size == 4) {
            val b0 = address[0]
            val b1 = address[1]
            //127.x.x.x
            val SECTION_0 = 0x7F.toByte()
            //10.x.x.x/8
            val SECTION_1 = 0x0A.toByte()
            //172.16.x.x/12--172.31.x.x
            val SECTION_2 = 0xAC.toByte()
            val SECTION_3 = 0x10.toByte()
            val SECTION_4 = 0x1F.toByte()
            //192.168.x.x/16
            val SECTION_5 = 0xC0.toByte()
            val SECTION_6 = 0xA8.toByte()
            when (b0) {
                SECTION_0 -> return true
                SECTION_1 -> return true
                SECTION_2 -> if (b1 >= SECTION_3 && b1 <= SECTION_4) {
                    return true
                }
                SECTION_5 -> if (b1 == SECTION_6) {
                    return true
                }
                else -> return false
            }
top Created with Sketch.