前言
現(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)容是h5的android無權(quán)限操作 苦于煩惱 怎么辦呢?
怎么辦 喜歡就保存起來啊 方便不時之需 如何操作 且看一步一步說明
效果

代碼實(shí)現(xiàn)
先說下思路 有2種方式可以實(shí)現(xiàn) 這里都會介紹到
第一種是 攔截http的url的請求通過判斷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)
}
主要代碼是這句
webview與js通信
webView?.addJavascriptInterface(JavaScriptInterface(this), "imagelistner")
通過webView的onPageFinished方法 我們對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)
這句代碼的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("當(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ù)努力 ~

