【记录】Android关于WebView无/有图模式切换实现方案

1,583 阅读3分钟

需求描述:使用WebView加载一个链接,实现有图、无图模式之间的切换

  • 关于无图模式的2种理解
  1. 阻塞图片的加载,网页上图片以一种灰底的形式存在
  2. 完全实现图片的隐藏

1. 阻塞图片的加载

这个就比较简单了,WebView本身提供了api,这种方式一般也会作为优化网页显示速率的一种方式

    // 阻塞图片加载
    wvWeb.settings.blockNetworkImage = true

2. 完全实现图片的隐藏

WebView本身并没有提供相关的方法,只能另寻出路,我们知道网页是以html语言编写的,我们只要拿到了网页源码,别说是图片隐藏了,简直可以为所欲为,既然方案出来了,就不要只限于想,一定要动手去淦。

在这里提供两种获取网页源码的方式

  1. 通过WebView加载一段js代码的方式获取
  2. 直接请求链接,下载其源码
2.1 通过WebView加载一段js代码的方式获取

直接上码

    dataBinding.wvWeb.addJavascriptInterface(InJavaScriptLocalObj(), "java_obj")
    dataBinding.wvWeb.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(
                view: WebView?,
                request: WebResourceRequest?
            ): Boolean {
                view?.loadUrl(request?.url.toString())
                return true
            }
            // 拦截当前链接内所有请求,其实在这个方式也可以实现 阻塞图片的加载
            // 问题是无法根据一个统一的规则去判断这个链接是否是图片(如果是加载的公司自己的h5,完全可以制定这种规则)
            override fun shouldInterceptRequest(
                view: WebView?,
                request: WebResourceRequest?
            ): WebResourceResponse? {
                Log.i(TAG, "shouldInterceptRequest: ${request?.url.toString()}")
                if (request?.url.toString()是图片)
                    return WebResourceResponse(null, null, null)
                else
                    return super.shouldInterceptRequest(view, request)
            }
            // 页面加载完成时的回调
            override fun onPageFinished(view: WebView?, url: String?) {
                view?.loadUrl("javascript:window.java_obj.getSource('<head>'+" +
                        "document.getElementsByTagName('html')[0].innerHTML+'</head>');")
                super.onPageFinished(view, url)
            }
        }

       inner class InJavaScriptLocalObj {
          @JavascriptInterface
          fun getSource(src: String?) {
              Log.i(TAG, "source: $src")
          }
       }
2.2 直接请求链接,下载其源码

完全可以使用当时项目中的请求框架去下载网页源码,这里使用的是jsoup三方库,这个库不仅可以获取源码,还可以解析处理html,提供了一整套非常省力的api,总之是一个好库,对于我这种对前端技术不咋熟悉还是非常nice的,具体使用自行google吧。 当我们拿到了html文本,就可以随心所欲了。 但是在测试过程中,微信公众号中的链接需要特殊处理。代码中有解释,请看👇

     // app >>> build.gradle中添加
    implementation 'org.jsoup:jsoup:1.13.1'
    /**
     * 切换显示模式
     * @param url 网页链接
     * @param hideImg  是否隐藏图片  true 隐藏  false 显示
     */
    private fun changeWvLoadMode(url: String, hideImg: Boolean) {
        lifecycleScope.launch(Dispatchers.Main) {

            dataBinding.btnSwitch.text = if (hideImg) "无图模式开启" else "无图模式关闭"
            // 适配微信公众号的了解加载有图模式
            // 原因:微信可能对公众号中的图片有保护机制,使用loadDataWithBaseUR()的方式加载图片加载不成功,需要使用loadUrl的方式
            if (是微信公众号链接 && !hideImg) {
                dataBinding.wvWeb.loadUrl(url)
                return@launch
            }
            if (document == null) {
                withContext(Dispatchers.IO) {
                    document = Jsoup.connect(url).timeout(3000).get()
                }
            }

            // 这里拿到所有img标签,返回的是一个Elements对象
            val imgTags = document?.getElementsByTag("img")
            Log.i(TAG, "imgTags: ${imgTags}")
            for (element in imgTags!!) {
                // 适配个别网页中获取的图片链接不完整的问题
                val src = element.attr("src")
                if (!src.startsWith("http"))
                    element.attr("src", "https:$src")

                // 适配PC端链接在手机端显示问题
                element.attr("width", "100%")
                element.attr("height", "100%")

                // 添加or移除隐藏属性,实现有图or无图模式(隐藏属性好像还有其他的,可以和公司前端小姐姐深入交流一下)
                if (hideImg)
                    element.attr("hidden", "hidden")
                else
                    element.removeAttr("hidden")
            }

           dataBinding.wvWeb.loadDataWithBaseURL(null,document.toString(),"text/html","utf-8", null)
        }
    }

Ending..... 如果各位大佬有更好的方法,还请评论区赐教。