如何清除 WebView 的缓存、Cookie 和历史记录?

解读

面试官抛出此题,往往不是为了让你背几行 API,而是考察:

  1. 对 WebView 双缓存模型(内存+磁盘)与 Cookie 持久化机制的理解深度;
  2. 能否区分“应用级”与“系统级”数据,避免误删全局 Cookie 导致用户在其他 App 登录态失效;
  3. 是否具备线上灰度与兼容意识,例如国内 ROM 对 WebView 实现差异、TargetSdk≥33 对分区存储的影响;
  4. 能否把“清除”动作与业务场景(退出账号、切换儿童模式、WebView 热修复)结合,给出可灰度、可回滚、可监控的完整方案。

知识点

  1. WebView 缓存分类
    1.1 内存缓存:位于当前进程,随 Activity/Fragment 销毁而释放,无需手动清。
    1.2 磁盘缓存:/data/data/包名/app_webview/ 目录下的 Cache、Code Cache、GPU Cache;WebView 自身实现为 Chromium 的 Simple Cache 或 Blockfile Cache。
  2. Cookie 存储
    2.1 旧版:/data/data/包名/app_webview/Cookies(SQLite)。
    2.2 新版:/data/data/包名/app_webview/Default/Cookies(Chromium 93+)。
    2.3 系统级 CookieManager 单例,跨进程由 com.android.webview 服务托管,国内部分 ROM 会魔改路径。
  3. 历史记录
    3.1 WebBackForwardList 仅保存在内存,进程被杀即消失;
    3.2 若业务自己把访问记录持久化到本地 DB,则不在 WebView 职责范围内,需业务自己删。
  4. 关键 API
    WebView.clearCache(true) // true 同时清磁盘
    WebView.clearHistory() // 仅清内存列表
    CookieManager.removeAllCookies(ValueCallback)
    WebStorage.deleteAllData() // LocalStorage、IndexedDB、WebSQL
    ServiceWorkerController.getInstance().clearCache() // 部分国产 ROM 需反射
  5. 国内合规点
    工信部 164 号文要求“双清单”+“一键清除”,必须在隐私政策中明示;
    小米/华为/OPPO 上架检测会扫描 /sdcard/Android/data/包名 下是否残留 webview 缓存图片,若发现直接驳回。
  6. 性能与灰度
    清除磁盘缓存会触发 200~400 ms 文件 IO,主线程调用易丢帧;
    建议放 WorkManager 后台任务,并通过 AB Test 验证对 DAU 与二次启动耗时的影响。

答案

线上稳健方案分三步:
步骤一:异步清理,避免 ANR

val wm = WorkManager.getInstance(context)
wm.enqueueUniqueWork(
    "clear_webview",
    ExistingWorkPolicy.REPLACE,
    OneTimeWorkRequestBuilder<ClearWebViewWorker>()
        .setInitialDelay(0, TimeUnit.SECONDS)
        .build()
)

步骤二:Worker 内按顺序清除

class ClearWebViewWorker(ctx: Context, params: WorkerParameters) :
    CoroutineWorker(ctx, params) {

    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        // 1. 停掉所有 WebView 实例
        WebViewPool.destroyAll()

        // 2. Cookie
        val latch = CountDownLatch(1)
        CookieManager.getInstance().apply {
            removeAllCookies { latch.countDown() }
            flush()
        }
        latch.await(5, TimeUnit.SECONDS)

        // 3. 缓存与存储
        WebStorage.getInstance().deleteAllData()
        ServiceWorkerController.getInstance().clearCache()

        // 4. 磁盘缓存
        WebView(applicationContext).apply {
            clearCache(true)   // true 表示同时清磁盘
            clearHistory()
            destroy()
        }

        // 5. 兜底删目录,兼容国产 ROM
        val webviewDir = File(applicationContext.filesDir.parentFile, "app_webview")
        if (webviewDir.exists()) {
            deleteRecursively(webviewDir)
        }

        Result.success()
    }
}

步骤三:回调与埋点
Worker 返回 Result.success() 后,通过 LiveData 通知 UI 层弹出“清理成功”Toast;
同时埋点 key=webview_cache_clear,带上耗时与目录大小,供后台校验是否真正清掉。

拓展思考

  1. 多进程场景:若应用采用 :web 子进程加载 WebView,清除动作必须在主进程执行,否则无法删除已被子进程 mmap 的缓存文件;可通过 AIDL 回调主进程统一清理。
  2. 热修复与版本升级:Chromium 内核升级后缓存格式可能变化,建议在首次启动新 APK 版本时强制触发一次清理,防止旧缓存解析崩溃。
  3. 隐私沙盒适配:Android 13 引入 Privacy Sandbox,广告相关 WebView 数据将迁移到 SDK Runtime,未来需调用 AdServices 的 clearAdServicesData(),而非直接删文件。
  4. 折叠屏与多窗口:同一应用可在两块屏幕各持一个 WebView,清除时需遍历所有窗口的 WebView 实例,防止漏清。
  5. 国内合规脚本:上架前使用华为/小米提供的本地检测工具,命令行运行
    adb shell pm clear 包名 && adb shell find /sdcard/Android/data -name "*cache*" -type f | grep 包名
    确认无残留,可一次性通过隐私专项审核。