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

231 阅读2分钟
原文链接: xiaozhuanlan.com

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

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

            }