Android 轻松实现 点击WebView链接中的图片同比例放大,长按保存本地

前言

现在纯原生应用已经越来越少 很多应用都是采用混合式开发 WebView 和 Javascript 进行交互
说到webView加载h5链接 很多时候都是h5写好了网页内容 android端只负责加载就完事了
最近在研究webView加载h5链接时,看到一张很好看的gif图 但是没有办法下载呀
因为内容是h5android无权限操作 苦于烦恼 怎么办呢?

怎么办 喜欢就保存起来啊 方便不时之需 如何操作 且看一步一步说明

2

效果

gif

忘记录相册了 太麻烦了 就不重新弄了 截一张图说明 下载成功的图
下面这张图就是刚刚从应用中的h5链接里下载的gif
1

代码实现

先说下思路 有2种方式可以实现 这里都会介绍到
第一种是 拦截httpurl的请求通过判断endsWith来取图片地址
但是这张方式有一种弊端 就是如果url不是以图片格式结尾 那么这个方法就没法使用
比如https://inews.gtimg.com/newsapp_bt/0/14526974555/1000这张地址

URL拦截实现

 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通信实现

我是用这种方法实现的 也比较简单 没有弊端 无论你是图片格式结尾还是hmtl
都可以使用glide直接加载

webView配置

 		webView = mBind.webView
        // 设置允许JS弹窗
        webView?.settings?.javaScriptCanOpenWindowsAutomatically = true
        webView?.settings?.defaultTextEncodingName = "UTF-8"//防止乱码
        webView?.settings?.javaScriptEnabled = true
        webView?.settings?.useWideViewPort = true
        webView?.settings?.loadWithOverviewMode = true
        webView?.settings?.setSupportMultipleWindows(true)
        webView?.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //设置滚动条样式
        // 最小缩放等级
        webView?.setInitialScale(100)

        //通过屏幕密度调整分辨率
        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 //设置字体号150%
        webView?.settings?.defaultZoom = zoomDensity

        //h5调用android
        webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")

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

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

通过webViewonPageFinished方法 我们对url作监听

 override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                //这段js函数的功能就是注册监听,遍历所有的img标签,并添加onClick函数,
                // 函数的功能是在图片点击的时候调用本地java接口并传递url过去
                webView?.loadUrl(
                    "javascript:(function(){"
                            + "var objs = document.getElementsByTagName(\"img\"); "
                            + "for(var i=0;i<objs.length;i++)  " + "{"
                            + "    objs[i].οnclick=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("当前图片地址:")
            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) 对应的,这样就实现通信了

展示及下载

通过上面的通信 我们从js那边拿到了图片的url 这样对于我们来说就是小菜一碟了
直接加载就完事了 具体看代码实现
这里要注意 我们需要把Activity改成dialog的形式 不然 一张图就占全屏 属实浪费 也不好看
你还记得android初学的问题 如何把activity改成dialog吗?

还要去掉activity的title 不然有个应用名的标题 看起来很奇怪

override fun initView(savedInstanceState: Bundle?) {
        title = null  //去标题
        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 = "下载进度:${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
        }

关于图片下载 我这里适配了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 {
                        //异常回调
                        downLoadError(it)
                    }.collect {
                        //成功回调
                        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 {
                        //异常回调
                        downLoadError(it)
                    }.collect {
                        //成功回调
                        downLoadSuccess.invoke(it)
                    }
            }
        }
    }

总结

学习是没有止境的 只要一点点进步 就不会被社会淘汰
2022 继续努力 ~
2

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕氏春秋i

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值