Android 点击WebView链接中的图片同比例放大,长按保存本地
共 7175字,需浏览 15分钟
·
2022-11-17 16:18
前言
现在纯原生应用已经越来越少,很多应用都是采用混合式开发 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 = 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)
}
主要代码是这句 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与openImageUrl
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及以上版本 代码参考一下
/**
* 下载
* @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)
}
}
}
}
这里提供思路,具体实现各位可以尝试一下,到这里就结束啦。