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

前言

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

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

2

效果

webview保存图片.gif

代码实现

先说下思路 有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].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("当前图片地址:")
            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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容