You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android WebView重载后如何清除视频缓存强制拉取最新视频资源

问题根因

你当前实现的webView.clearCache(true) + WebSettings.LOAD_NO_CACHE + webView.reload()逻辑,仅能覆盖普通网页静态资源(HTML、JS、普通图片等)的缓存清理,无法处理视频资源缓存的核心原因如下:

  • 安卓系统WebView基于Chromium内核,视频流等大体积媒体资源存储在内核独立的媒体缓存目录,不属于clearCache()接口的覆盖范围
  • 你已开启DOM存储权限,主流视频站点普遍会将视频分片索引、已加载分片元数据存储在LocalStorage、IndexedDB中,这部分存储未被纳入清理范围
  • 直接调用reload()时,内核会优先复用内存中已缓存的视频分片、已初始化的媒体解码器实例,不会触发完整的源站资源拉取流程
  • 多数视频站点会配置Service Worker实现资源离线缓存,这部分缓存独立于WebView常规缓存体系,常规清理逻辑无法触达
  • 你当前在调用reload()后立刻关闭下拉刷新状态,会导致清理逻辑未执行完成就进入重载流程,同时若视频处于播放状态,缓存文件会被内核占用加锁,直接删除缓存目录会失效

可落地实现方案

1. 实现全量缓存清理方法

覆盖所有WebView关联的存储路径和存储类型,注意方法需在主线程调用:

private fun fullCleanWebViewCache(webView: WebView) {
    // 释放页面内所有视频实例的文件占用
    webView.evaluateJavascript("""
        document.querySelectorAll('video').forEach(v => {
            v.pause();
            v.removeAttribute('src');
            v.load();
        });
    """.trimIndent(), null)

    // 清理常规网页缓存、历史、表单数据
    webView.clearCache(true)
    webView.clearHistory()
    webView.clearFormData()

    // 清理DOM存储、WebSQL等前端持久化存储
    WebStorage.getInstance().deleteAllData()

    // 清理Service Worker缓存
    ServiceWorkerController.getInstance().storage.deleteAllData()
    ServiceWorkerController.getInstance().serviceWorkerWebSettings.cacheMode = WebSettings.LOAD_NO_CACHE

    // 手动删除内核所有缓存目录,覆盖不同系统版本、不同内核实现的路径差异
    val cacheDirs = listOf(
        File(cacheDir, "org.chromium.android_webview"),
        File(cacheDir, "WebView"),
        File(filesDir, "webview"),
        File(dataDir, "app_webview")
    )
    cacheDirs.forEach { dir ->
        if (dir.exists()) {
            dir.deleteRecursively()
        }
    }
}

2. 替换原有reload逻辑,强制无缓存加载

不要直接调用reload(),改用主动添加无缓存请求头的加载方式,同时可拼接随机时间戳参数彻底绕过URL级缓存命中:

// 替换原有webView.reload()逻辑
val currentUrl = webView.url ?: return@setOnRefreshListener
val noCacheHeaders = mapOf(
    "Cache-Control" to "no-cache, no-store, must-revalidate",
    "Pragma" to "no-cache",
    "Expires" to "0"
)
// 拼接随机时间戳,彻底绕过CDN、内核的URL匹配缓存
val reloadUrl = if (currentUrl.contains("?")) {
    "$currentUrl&_t=${System.currentTimeMillis()}"
} else {
    "$currentUrl?_t=${System.currentTimeMillis()}"
}
webView.loadUrl(reloadUrl, noCacheHeaders)

3. 修正下拉刷新的状态控制逻辑

不要在触发重载后立刻关闭刷新动画,要等页面完全加载完成后再停止动画,避免打断清理和加载流程:

// 初始化WebView时补充onPageFinished回调
webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(
        view: WebView?,
        request: WebResourceRequest?
    ): Boolean {
        return !request?.url.toString().startsWith("http")
    }

    override fun onPageFinished(view: WebView?, url: String?) {
        super.onPageFinished(view, url)
        // 页面加载完成后再关闭下拉刷新动画
        findViewById<SwipeRefreshLayout>(R.id.pullToRefresh).isRefreshing = false
    }
}

// 下拉刷新最终逻辑
findViewById<SwipeRefreshLayout>(R.id.pullToRefresh).apply {
    setOnRefreshListener {
        fullCleanWebViewCache(webView)
        val currentUrl = webView.url ?: return@setOnRefreshListener
        val noCacheHeaders = mapOf(
            "Cache-Control" to "no-cache, no-store, must-revalidate",
            "Pragma" to "no-cache",
            "Expires" to "0"
        )
        val reloadUrl = if (currentUrl.contains("?")) {
            "$currentUrl&_t=${System.currentTimeMillis()}"
        } else {
            "$currentUrl?_t=${System.currentTimeMillis()}"
        }
        webView.loadUrl(reloadUrl, noCacheHeaders)
    }
}

验证注意事项
  • 测试前先强制停止应用,冷启动后验证效果,避免之前残留的缓存进程影响结果
  • Android 10及以上设备无需额外存储权限即可清理应用私有目录下的缓存文件,不需要动态申请权限
  • 部分定制ROM会对系统WebView做二次修改,若上述逻辑在特定机型失效,可在清理缓存后调用webView.destroy()重新初始化WebView实例,可100%绕过所有内存和本地缓存

内容的提问来源于stack exchange,提问作者youxiong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:45:08