Android 点击WebView链接中的图片同比例放大,长按保存本地
前言
现在纯原生应用已经越来越少,很多应用都是采用混合式开发 WebView 和 Javascript 进行交互,说到webView加载h5链接,很多时候都是h5写好了网页内容,android端只负责加载就完事了。
最近在研究webView加载h5链接时,看到一张很好看的gif图 但是没有办法下载呀,因为内容是h5的 android无权限操作 苦于烦恼 怎么办呢?
效果

代码实现
先说下思路:有2种方式可以实现,这里都会介绍到,第一种是拦截http的url的请求通过判断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 = truewebView?.settings?.defaultTextEncodingName = "UTF-8"//防止乱码webView?.settings?.javaScriptEnabled = truewebView?.settings?.useWideViewPort = truewebView?.settings?.loadWithOverviewMode = truewebView?.settings?.setSupportMultipleWindows(true)webView?.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //设置滚动条样式// 最小缩放等级webView?.setInitialScale(100)//通过屏幕密度调整分辨率val screenDensity = resources.displayMetrics.densityDpivar zoomDensity = ZoomDensity.MEDIUMwhen (screenDensity) {DisplayMetrics.DENSITY_LOW -> zoomDensity = ZoomDensity.CLOSEDisplayMetrics.DENSITY_MEDIUM -> zoomDensity = ZoomDensity.MEDIUMDisplayMetrics.DENSITY_HIGH -> zoomDensity = ZoomDensity.FAR}webView?.settings?.textSize = WebSettings.TextSize.LARGER //设置字体号150%webView?.settings?.defaultZoom = zoomDensity//h5调用androidwebView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")if (vurLink != null) {webView?.loadUrl(vurLink)}
主要代码是这句 webview与js通信:
webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")通过webView的onPageFinished方法 我们对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)这句代码的imagelistner与openImageUrlwebView?.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.JavascriptInterfacefun 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") //接受urlif (url != null) {Glide.with(this).load(url).transition(DrawableTransitionOptions.withCrossFade(500)).into(mBind.imageShow)}//长按下载图片mBind.imageShow.setOnLongClickListener {try {if (url != null) {mViewModel.uploadPhotoUrl = urlmViewModel.downLoad({//下载中mBind.tvDownNumber.visibility = View.VISIBLEmBind.tvDownNumber.text = "下载进度:${it.progress}%"}, {//下载完成mBind.tvDownNumber.visibility = View.GONEshowDialogMessage("下载成功,路径为:${it}")}, {//下载失败mBind.tvDownNumber.visibility = View.GONEshowDialogMessage(it.msg)})}} catch (ex: Exception) {ToastUtils.show("save pic error:$ex")}true}
关于图片下载 我这里适配了android10及以上版本 代码参考一下
/*** 下载* @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)}}}}
这里提供思路,具体实现各位可以尝试一下,到这里就结束啦。
评论
