Android 點(diǎn)擊WebView鏈接中的圖片同比例放大,長按保存本地

前言

現(xiàn)在純原生應(yīng)用已經(jīng)越來越少 很多應(yīng)用都是采用混合式開發(fā) WebView 和 Javascript 進(jìn)行交互
說到webView加載h5鏈接 很多時候都是h5寫好了網(wǎng)頁內(nèi)容 android端只負(fù)責(zé)加載就完事了
最近在研究webView加載h5鏈接時,看到一張很好看的gif圖 但是沒有辦法下載呀
因?yàn)閮?nèi)容是h5android無權(quán)限操作 苦于煩惱 怎么辦呢?

怎么辦 喜歡就保存起來啊 方便不時之需 如何操作 且看一步一步說明

2

效果

webview保存圖片.gif

代碼實(shí)現(xiàn)

先說下思路 有2種方式可以實(shí)現(xiàn) 這里都會介紹到
第一種是 攔截httpurl的請求通過判斷endsWith來取圖片地址
但是這張方式有一種弊端 就是如果url不是以圖片格式結(jié)尾 那么這個方法就沒法使用
比如https://inews.gtimg.com/newsapp_bt/0/14526974555/1000這張地址

URL攔截實(shí)現(xiàn)

 webView?.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
                if (url.endsWith(".jpg") || url.endsWith(".jpeg") || url.endsWith(".png")
                    || url.endsWith(".JPG") || url.endsWith(".JPEG") || url.endsWith(".PNG")
                ) {
                    openImageActivity(url)
                    return true
                }
                return super.shouldOverrideUrlLoading(view, url)
            }
        }

這里的openImageActivity

   private fun openImageActivity(url: String) {
        val bundle = Bundle()
        bundle.putString("imgUrl", url)
        toStartActivity(ShowWebImageActivity::class.java, bundle)
    }

與JS通信實(shí)現(xiàn)

我是用這種方法實(shí)現(xiàn)的 也比較簡單 沒有弊端 無論你是圖片格式結(jié)尾還是hmtl
都可以使用glide直接加載

webView配置

        webView = mBind.webView
        // 設(shè)置允許JS彈窗
        webView?.settings?.javaScriptCanOpenWindowsAutomatically = true
        webView?.settings?.defaultTextEncodingName = "UTF-8"http://防止亂碼
        webView?.settings?.javaScriptEnabled = true
        webView?.settings?.useWideViewPort = true
        webView?.settings?.loadWithOverviewMode = true
        webView?.settings?.setSupportMultipleWindows(true)
        webView?.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //設(shè)置滾動條樣式
        // 最小縮放等級
        webView?.setInitialScale(100)

        //通過屏幕密度調(diào)整分辨率
        val screenDensity = resources.displayMetrics.densityDpi
        var zoomDensity = ZoomDensity.MEDIUM
        when (screenDensity) {
            DisplayMetrics.DENSITY_LOW -> zoomDensity = ZoomDensity.CLOSE
            DisplayMetrics.DENSITY_MEDIUM -> zoomDensity = ZoomDensity.MEDIUM
            DisplayMetrics.DENSITY_HIGH -> zoomDensity = ZoomDensity.FAR
        }
        webView?.settings?.textSize = WebSettings.TextSize.LARGER //設(shè)置字體號150%
        webView?.settings?.defaultZoom = zoomDensity

        //h5調(diào)用android
        webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")

        if (vurLink != null) {
            webView?.loadUrl(vurLink)
        }

主要代碼是這句 webviewjs通信
webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")

通過webViewonPageFinished方法 我們對url作監(jiān)聽

 override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                //這段js函數(shù)的功能就是注冊監(jiān)聽,遍歷所有的img標(biāo)簽,并添加onClick函數(shù),
                // 函數(shù)的功能是在圖片點(diǎn)擊的時候調(diào)用本地java接口并傳遞url過去
                webView?.loadUrl(
                    "javascript:(function(){"
                            + "var objs = document.getElementsByTagName(\"img\"); "
                            + "for(var i=0;i<objs.length;i++)  " + "{"
                            + "    objs[i].onclick=function()  " + "    {  "
                            + "        window.imagelistner.openImageUrl(this.src);  "
                            + "    }  " + "}" + "})()"
                );

            }

上述這段代碼 我們需要注意window.imagelistner.openImageUrl(this.src)
這句代碼的imagelistneropenImageUrl
webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")定義的方法名,
openImage就是我們自定義的 JavaScriptInterface 中的 openImage 方法

接下來我們定義JS接口

     // js通信接口
    class JavaScriptInterface internal constructor(context: Context) {
        private var mContext: Context = context

        //https://inews.gtimg.com/newsapp_bt/0/14526974536/1000
        @android.webkit.JavascriptInterface
        fun openImageUrl(img: String?) {
            img.logE("當(dāng)前圖片地址:")
            val intent = Intent(mContext, ShowWebImageActivity::class.java)
            intent.putExtra("img", img)
            ContextCompat.startActivity(mContext, intent, null)
        }
    }

這里的 JavascriptInterface 就是和 webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner"), 中的 new JavascriptInterface(this) 對應(yīng)的,這樣就實(shí)現(xiàn)通信了

展示及下載

通過上面的通信 我們從js那邊拿到了圖片的url 這樣對于我們來說就是小菜一碟了
直接加載就完事了 具體看代碼實(shí)現(xiàn)
這里要注意 我們需要把Activity改成dialog的形式 不然 一張圖就占全屏 屬實(shí)浪費(fèi) 也不好看
你還記得android初學(xué)的問題 如何把a(bǔ)ctivity改成dialog嗎?

還要去掉activity的title 不然有個應(yīng)用名的標(biāo)題 看起來很奇怪

override fun initView(savedInstanceState: Bundle?) {
        title = null  //去標(biāo)題
        val url = intent.getStringExtra("img") //接受url
        if (url != null) {
            Glide.with(this)
                .load(url)
                .transition(DrawableTransitionOptions.withCrossFade(500))
                .into(mBind.imageShow)

        }

        //長按下載圖片
        mBind.imageShow.setOnLongClickListener {
            try {
                if (url != null) {
                    mViewModel.uploadPhotoUrl = url
                    mViewModel.downLoad({
                        //下載中
                        mBind.tvDownNumber.visibility = View.VISIBLE
                        mBind.tvDownNumber.text = "下載進(jìn)度:${it.progress}%"
                    }, {
                        //下載完成
                        mBind.tvDownNumber.visibility = View.GONE
                        showDialogMessage("下載成功,路徑為:${it}")
                    }, {
                        //下載失敗
                        mBind.tvDownNumber.visibility = View.GONE
                        showDialogMessage(it.msg)
                    })
                }
            } catch (ex: Exception) {
                ToastUtils.show("save pic error:$ex")
            }
            true
        }

關(guān)于圖片下載 我這里適配了android10及以上版本 代碼參考一下


2
 /**
     * 下載
     * @param downLoadData Function1<ProgressT<String>, Unit>
     * @param downLoadSuccess Function1<String, Unit>
     * @param downLoadError Function1<Throwable, Unit>
     */
    fun downLoad(downLoadData: (Progress) -> Unit = {}, downLoadSuccess: (String) -> Unit, downLoadError: (Throwable) -> Unit = {}) {
        viewModelScope.launch {
            if (checkedAndroid_Q()) {
                //android 10 以上
                val factory = Android10DownloadFactory(appContext, "${System.currentTimeMillis()}")
                RxHttp.get(uploadPhotoUrl)
                    .toFlow(factory) {
                        downLoadData.invoke(it)
                    }.catch {
                        //異?;卣{(diào)
                        downLoadError(it)
                    }.collect {
                        //成功回調(diào)
                        downLoadSuccess.invoke(UriUtils.getFileAbsolutePath(appContext,it)?:"")
                    }
            } else {
                //android 10以下
                val localPath = appContext.externalCacheDir!!.absolutePath + "/${System.currentTimeMillis()}"
                RxHttp.get(uploadPhotoUrl)
                    .toFlow(localPath) {
                        downLoadData.invoke(it)
                    }.catch {
                        //異?;卣{(diào)
                        downLoadError(it)
                    }.collect {
                        //成功回調(diào)
                        downLoadSuccess.invoke(it)
                    }
            }
        }
    }

總結(jié)

學(xué)習(xí)是沒有止境的 只要一點(diǎn)點(diǎn)進(jìn)步 就不會被社會淘汰
2022 繼續(xù)努力 ~


2
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容