hejianhao
2026-08-21 33a3c48272eb5b0f57e952a539916db7a244bd02
feat0806: 退出直播间不清理缓存
1个文件已添加
2个文件已修改
353 ■■■■■ 已修改文件
traditionalApp/pages/settings/settings.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/webview/webview.vue 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/utils/webview-cache.js 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/settings/settings.vue
@@ -96,6 +96,7 @@
import { bindSettingsWechat, cancelSettingsAccount, getSettingsProfile, logoutSettingsAccount } from './service.js'
import { cacheSettingsProfile, clearSettingsLoginSession, isSuccessResponse, maskPhone, normalizeSettingsProfile } from './utils.js'
import { normalizeOptionalText } from '@/utils/utils.js'
import { clearWebViewData } from '@/utils/webview-cache.js'
interface WechatLoginResult {
    code?: string
@@ -291,105 +292,34 @@
}
/**
 * 清除 WebView 缓存和 localStorage。
 * 退出登录时清除本地存储与 WebView 缓存。
 * WebView 部分复用进入直播间前的彻底清理逻辑(含原生 Cookie/存储 API),保证登录态不残留。
 */
function clearWebViewCache() {
    console.log('[clearWebViewCache] 函数被调用')
    let logMessages = []
    logMessages.push('开始清除缓存')
    try {
        // 清除 uni.storage(所有环境通用)
        try {
            uni.clearStorageSync()
            console.log('[clearWebViewCache] uni.storage 已清除')
            logMessages.push('uni.storage 已清除')
        } catch (e) {
            console.error('[clearWebViewCache] 清除 uni.storage 失败:', e)
            logMessages.push('uni.storage 清除失败')
        }
        // #ifdef APP-PLUS
        console.log('[clearWebViewCache] APP-PLUS 环境,开始清除 WebView 缓存')
        logMessages.push('APP-PLUS 环境检测到')
        // 清除 plus.storage
        if (plus.storage) {
            plus.storage.clear()
            console.log('[clearWebViewCache] plus.storage 已清除')
            logMessages.push('plus.storage 已清除')
        }
        // 清除 WebView 缓存
        const currentWebview = plus.webview.currentWebview()
        if (currentWebview && typeof currentWebview.clearCache === 'function') {
            currentWebview.clearCache()
            console.log('[clearWebViewCache] 当前 WebView 缓存已清除')
            logMessages.push('当前 WebView 缓存已清除')
        }
        // 清除所有 WebView 的缓存
        const allWebviews = plus.webview.all()
        if (allWebviews && allWebviews.length > 0) {
            allWebviews.forEach((webview) => {
                try {
                    // 清除缓存
                    if (webview && typeof webview.clearCache === 'function') {
                        webview.clearCache()
                    }
                    // 清除 Cookie 和存储
                    if (webview && typeof webview.evalJS === 'function') {
                        webview.evalJS(`
                            try {
                                // 清除所有 Cookie
                                document.cookie.split(";").forEach(function(c) {
                                    document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
                                });
                                // 清除存储
                                if (window.localStorage) localStorage.clear();
                                if (window.sessionStorage) sessionStorage.clear();
                                console.log('[WebView.evalJS] Cookie 和存储已清除');
                            } catch (e) {
                                console.error('[WebView.evalJS] 清除失败:', e);
                            }
                        `)
                    }
                } catch (e) {
                    console.error('[clearWebViewCache] 处理 WebView 失败:', e)
                }
            })
            console.log('[clearWebViewCache] 所有 WebView 缓存和 Cookie 已清除,共 ' + allWebviews.length + ' 个')
            logMessages.push(`所有 WebView 已清除 (${allWebviews.length}个)`)
        try {
            if (plus.storage) {
                plus.storage.clear()
            }
        } catch (e) {
            console.error('[clearWebViewCache] 清除 plus.storage 失败:', e)
        }
        // #endif
        // #ifndef APP-PLUS
        console.log('[clearWebViewCache] 非 APP-PLUS 环境,已清除 uni.storage')
        logMessages.push('非 APP-PLUS 环境')
        // #endif
        // 显示清除结果
        uni.showToast({
            title: '缓存已清除',
            icon: 'success',
            duration: 2000
        })
        // 复用进入直播间前的彻底清理逻辑(Android CookieManager/WebStorage、iOS NSHTTPCookieStorage/WKWebsiteDataStore)
        clearWebViewData()
    } catch (error) {
        console.error('[clearWebViewCache] 清除缓存失败:', error)
        logMessages.push('异常: ' + error.message)
        uni.showToast({
            title: '缓存清除失败',
            icon: 'none',
            duration: 2000
        })
    }
    // 开发调试:显示详细日志
    console.log('[clearWebViewCache] 执行完成,日志:', logMessages.join(' | '))
}
/**
traditionalApp/pages/webview/webview.vue
@@ -10,6 +10,7 @@
<script setup lang="ts">
import { ref } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import { clearWebViewData } from '@/utils/webview-cache.js'
const webViewUrl = ref('')
let currentWebviewInstance: any = null
@@ -44,139 +45,11 @@
})
/**
 * 页面卸载时清除 WebView 缓存和 Cookie
 * 页面卸载时不再清理缓存:清理集中在进入直播间前与退出登录时执行。
 */
onUnload(() => {
    console.log('[WebView] 页面卸载,开始清除缓存')
    clearWebViewData()
    console.log('[WebView] 页面卸载')
})
/**
 * 清除所有 WebView 的缓存、Cookie 和存储数据。
 * 原生 API 可清掉 HttpOnly cookie 和按域名隔离的 localStorage;
 * evalJS 仅作为兜底,清掉非 HttpOnly cookie 和当前页 storage。
 */
function clearWebViewData() {
    try {
        // #ifdef APP-PLUS
        // 1. 原生 API 清理(核心:能清掉 HttpOnly cookie 和所有域名的 localStorage)
        const platform = String(uni.getSystemInfoSync().platform || '').toLowerCase()
        if (platform === 'android') {
            clearAndroidWebViewData()
        } else if (platform === 'ios') {
            clearIOSWebViewData()
        }
        // 2. plus.webview API 兜底:清 HTTP 资源缓存,并注入 JS 清当前页 cookie/storage
        try {
            const allWebviews = plus.webview.all()
            if (allWebviews && allWebviews.length > 0) {
                allWebviews.forEach((webview) => {
                    try {
                        if (webview && typeof webview.clearCache === 'function') {
                            webview.clearCache()
                        }
                        if (webview && typeof webview.evalJS === 'function') {
                            webview.evalJS(`
                                try {
                                    document.cookie.split(";").forEach(function(c) {
                                        document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
                                    });
                                    if (window.localStorage) localStorage.clear();
                                    if (window.sessionStorage) sessionStorage.clear();
                                } catch (e) {}
                            `)
                        }
                    } catch (e) {}
                })
                console.log('[WebView] 所有 WebView HTTP 缓存已清除,共 ' + allWebviews.length + ' 个')
            }
        } catch (e) {}
        // #endif
    } catch (error) {
        console.error('[WebView] 清除数据失败:', error)
    }
}
/**
 * Android 原生清理:清所有域名 Cookie(含 HttpOnly)+ WebStorage + 表单数据。
 */
function clearAndroidWebViewData() {
    try {
        // 清所有域名 Cookie(包括 HttpOnly),CookieManager 是全局按域名共享的
        const CookieManager = plus.android.importClass('android.webkit.CookieManager')
        if (CookieManager) {
            const cm = CookieManager.getInstance()
            try { cm.removeAllCookie() } catch (e) {}     // 老版本 API(API 21 以下)
            try { cm.flush() } catch (e) {}              // 立即写入磁盘
            console.log('[WebView][Android] CookieManager 已清所有 Cookie')
        }
        // 清所有域名的 localStorage / sessionStorage(WebStorage 是全局按域名共享的)
        const WebStorage = plus.android.importClass('android.webkit.WebStorage')
        if (WebStorage) {
            const ws = WebStorage.getInstance()
            try { ws.deleteAllData() } catch (e) {}
            console.log('[WebView][Android] WebStorage 已清所有 localStorage')
        }
        // 清表单数据和密码(可选)
        try {
            const WebViewDatabase = plus.android.importClass('android.webkit.WebViewDatabase')
            const context = plus.android.runtime.appContext
            if (WebViewDatabase && context) {
                const db = WebViewDatabase.getInstance(context)
                if (db && typeof db.clearFormData === 'function') {
                    db.clearFormData()
                }
            }
        } catch (e) {}
    } catch (e) {
        console.error('[WebView][Android] 原生清理失败:', e)
    }
}
/**
 * iOS 原生清理:清 NSHTTPCookieStorage 所有 Cookie;并用 WKWebsiteDataStore 清 WKWebView 数据。
 */
function clearIOSWebViewData() {
    // 1. NSHTTPCookieStorage.deleteAllCookies(UIWebView 与部分 WKWebView 共享)
    try {
        const NSHTTPCookieStorage = plus.ios.importClass('NSHTTPCookieStorage')
        if (NSHTTPCookieStorage) {
            const storage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
            if (storage) {
                try { plus.ios.invoke(storage, 'deleteAllCookies') } catch (e) {}
                console.log('[WebView][iOS] NSHTTPCookieStorage 已清所有 Cookie')
            }
        }
    } catch (e) {
        console.error('[WebView][iOS] NSHTTPCookieStorage 清理失败:', e)
    }
    // 2. WKWebsiteDataStore.removeDataOfTypes(iOS 9+,清 WKWebView 的 cookie/localStorage/cache)
    // block 部分用空 block 代替,调用 plus.ios.invoke
    try {
        const WKWebsiteDataStore = plus.ios.importClass('WKWebsiteDataStore')
        if (!WKWebsiteDataStore) {
            return
        }
        const allTypes = WKWebsiteDataStore.allWebsiteDataTypes()
        const defaultStore = WKWebsiteDataStore.defaultDataStore()
        const NSDate = plus.ios.importClass('NSDate')
        const distantPast = NSDate ? NSDate.distantPast() : null
        // completionHandler 传一个空 block,避免 native 崩溃
        const noopHandler = function () {}
        try {
            plus.ios.invoke(defaultStore, 'removeDataOfTypes:modifiedAt:completionHandler:', allTypes, distantPast, noopHandler)
            console.log('[WebView][iOS] WKWebsiteDataStore 已清所有数据')
        } catch (e) {
            console.error('[WebView][iOS] WKWebsiteDataStore 调用失败:', e)
        }
    } catch (e) {
        console.error('[WebView][iOS] WKWebsiteDataStore 初始化失败:', e)
    }
}
/**
 * 解码路由参数,异常时回退为空字符串。
traditionalApp/utils/webview-cache.js
New file
@@ -0,0 +1,128 @@
/**
 * 清除所有 WebView 的缓存、Cookie 和存储数据。
 * 原生 API 可清掉 HttpOnly cookie 和按域名隔离的 localStorage;
 * evalJS 仅作为兜底,清掉非 HttpOnly cookie 和当前页 storage。
 *
 * 进入微赞直播间前、退出登录时统一调用此函数,保证清理逻辑一致。
 */
export function clearWebViewData() {
    try {
        // #ifdef APP-PLUS
        // 1. 原生 API 清理(核心:能清掉 HttpOnly cookie 和所有域名的 localStorage)
        const platform = String(uni.getSystemInfoSync().platform || '').toLowerCase()
        if (platform === 'android') {
            clearAndroidWebViewData()
        } else if (platform === 'ios') {
            clearIOSWebViewData()
        }
        // 2. plus.webview API 兜底:清 HTTP 资源缓存,并注入 JS 清当前页 cookie/storage
        try {
            const allWebviews = plus.webview.all()
            if (allWebviews && allWebviews.length > 0) {
                allWebviews.forEach((webview) => {
                    try {
                        if (webview && typeof webview.clearCache === 'function') {
                            webview.clearCache()
                        }
                        if (webview && typeof webview.evalJS === 'function') {
                            webview.evalJS(`
                                try {
                                    document.cookie.split(";").forEach(function(c) {
                                        document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
                                    });
                                    if (window.localStorage) localStorage.clear();
                                    if (window.sessionStorage) sessionStorage.clear();
                                } catch (e) {}
                            `)
                        }
                    } catch (e) {}
                })
                console.log('[WebView] 所有 WebView HTTP 缓存已清除,共 ' + allWebviews.length + ' 个')
            }
        } catch (e) {}
        // #endif
    } catch (error) {
        console.error('[WebView] 清除数据失败:', error)
    }
}
/**
 * Android 原生清理:清所有域名 Cookie(含 HttpOnly)+ WebStorage + 表单数据。
 */
function clearAndroidWebViewData() {
    try {
        // 清所有域名 Cookie(包括 HttpOnly),CookieManager 是全局按域名共享的
        const CookieManager = plus.android.importClass('android.webkit.CookieManager')
        if (CookieManager) {
            const cm = CookieManager.getInstance()
            try { cm.removeAllCookie() } catch (e) {}     // 老版本 API(API 21 以下)
            try { cm.flush() } catch (e) {}              // 立即写入磁盘
            console.log('[WebView][Android] CookieManager 已清所有 Cookie')
        }
        // 清所有域名的 localStorage / sessionStorage(WebStorage 是全局按域名共享的)
        const WebStorage = plus.android.importClass('android.webkit.WebStorage')
        if (WebStorage) {
            const ws = WebStorage.getInstance()
            try { ws.deleteAllData() } catch (e) {}
            console.log('[WebView][Android] WebStorage 已清所有 localStorage')
        }
        // 清表单数据和密码(可选)
        try {
            const WebViewDatabase = plus.android.importClass('android.webkit.WebViewDatabase')
            const context = plus.android.runtime.appContext
            if (WebViewDatabase && context) {
                const db = WebViewDatabase.getInstance(context)
                if (db && typeof db.clearFormData === 'function') {
                    db.clearFormData()
                }
            }
        } catch (e) {}
    } catch (e) {
        console.error('[WebView][Android] 原生清理失败:', e)
    }
}
/**
 * iOS 原生清理:清 NSHTTPCookieStorage 所有 Cookie;并用 WKWebsiteDataStore 清 WKWebView 数据。
 */
function clearIOSWebViewData() {
    // 1. NSHTTPCookieStorage.deleteAllCookies(UIWebView 与部分 WKWebView 共享)
    try {
        const NSHTTPCookieStorage = plus.ios.importClass('NSHTTPCookieStorage')
        if (NSHTTPCookieStorage) {
            const storage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
            if (storage) {
                try { plus.ios.invoke(storage, 'deleteAllCookies') } catch (e) {}
                console.log('[WebView][iOS] NSHTTPCookieStorage 已清所有 Cookie')
            }
        }
    } catch (e) {
        console.error('[WebView][iOS] NSHTTPCookieStorage 清理失败:', e)
    }
    // 2. WKWebsiteDataStore.removeDataOfTypes(iOS 9+,清 WKWebView 的 cookie/localStorage/cache)
    // block 部分用空 block 代替,调用 plus.ios.invoke
    try {
        const WKWebsiteDataStore = plus.ios.importClass('WKWebsiteDataStore')
        if (!WKWebsiteDataStore) {
            return
        }
        const allTypes = WKWebsiteDataStore.allWebsiteDataTypes()
        const defaultStore = WKWebsiteDataStore.defaultDataStore()
        const NSDate = plus.ios.importClass('NSDate')
        const distantPast = NSDate ? NSDate.distantPast() : null
        // completionHandler 传一个空 block,避免 native 崩溃
        const noopHandler = function () {}
        try {
            plus.ios.invoke(defaultStore, 'removeDataOfTypes:modifiedAt:completionHandler:', allTypes, distantPast, noopHandler)
            console.log('[WebView][iOS] WKWebsiteDataStore 已清所有数据')
        } catch (e) {
            console.error('[WebView][iOS] WKWebsiteDataStore 调用失败:', e)
        }
    } catch (e) {
        console.error('[WebView][iOS] WKWebsiteDataStore 初始化失败:', e)
    }
}