| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- /**
- * App 端内置浏览器(plus.webview)数据同步:
- *
- * 1) 登录:writeTokenToEmbeddedBrowser(token)
- * 把原始 JWT 写入 https://api.hnyunzhu.com/ 源下的 localStorage(key = "token")。
- * localStorage 严格按 origin 隔离,必须在同源 WebView 内 evalJS,故用一个不可见的后台
- * webview 加载该 origin 后写入,完成再关闭。仅在「应用设置」选择「用内置浏览器打开链接」
- * (getOpenUrlInSystemBrowser() === false)时同步,系统浏览器偏好下写入无意义。
- *
- * 2) 退出:clearAllEmbeddedBrowserData()
- * 不再区分站点——直接清空 WebView 所有 origin 的 localStorage / IndexedDB / SessionStorage /
- * WebSQL / Cookies 以及 App 层 HTTP 缓存。通过原生 API(Android: CookieManager + WebStorage +
- * WebViewDatabase;iOS: WKWebsiteDataStore)调用,无需加载任何页面,不受偏好 gate。
- */
- import { getOpenUrlInSystemBrowser } from './openUrlPreference'
- const ORIGIN = 'https://api.hnyunzhu.com/'
- const TOKEN_KEY = 'token'
- const WEBVIEW_ID = 'yz-embedded-storage-writer'
- /** 内置 WebView 首次加载 api.hnyunzhu.com 的最长等待时间(弱网兜底) */
- const LOADED_TIMEOUT_MS = 4000
- /**
- * 在隐藏的 api.hnyunzhu.com webview 中执行一段 JS。
- * - 同一时刻仅保留一个后台 webview;如已存在则直接复用 + evalJS
- * - loaded / titleUpdate 任一事件先到先执行;均未回调时由超时兜底
- * @param {string} js 要 evalJS 的脚本
- */
- function runOnOrigin(js) {
- // #ifdef APP-PLUS
- try {
- if (getOpenUrlInSystemBrowser()) return
- if (typeof plus === 'undefined' || !plus.webview) return
- const existing = plus.webview.getWebviewById(WEBVIEW_ID)
- if (existing) {
- try {
- existing.evalJS(js)
- } catch (e) {}
- return
- }
- const wv = plus.webview.create(ORIGIN, WEBVIEW_ID, {
- visible: false,
- width: '1px',
- height: '1px',
- top: '-9999px',
- left: '-9999px',
- background: 'transparent'
- })
- let fired = false
- const runAndClose = () => {
- if (fired) return
- fired = true
- try {
- wv.evalJS(js)
- } catch (e) {}
- // 给 evalJS 一点时间落盘再关闭,避免异步写入被打断
- setTimeout(() => {
- try {
- wv.close('none')
- } catch (e) {}
- }, 300)
- }
- try {
- wv.addEventListener('loaded', runAndClose, false)
- } catch (e) {}
- // 部分机型 loaded 触发偏晚;titleUpdate 早于 loaded,兜底一次
- try {
- wv.addEventListener('titleUpdate', runAndClose, false)
- } catch (e) {}
- // 弱网 / 无响应兜底:到点照样尝试 evalJS
- setTimeout(runAndClose, LOADED_TIMEOUT_MS)
- } catch (e) {}
- // #endif
- }
- /**
- * 登录成功后把原始 JWT 写入 api.hnyunzhu.com 源下的 localStorage(key 为 "token")
- * @param {string} token 原始 JWT
- */
- export function writeTokenToEmbeddedBrowser(token) {
- const safe = JSON.stringify(String(token || ''))
- const key = JSON.stringify(TOKEN_KEY)
- runOnOrigin(`try{localStorage.setItem(${key}, ${safe})}catch(e){}`)
- }
- // #ifdef APP-PLUS
- /**
- * Android:CookieManager + WebStorage + WebViewDatabase 全清
- * - CookieManager.removeAllCookies(ValueCallback) 为 API 21+;旧机降级 removeAllCookie()
- * - WebStorage.deleteAllData() 清所有 origin 的 LocalStorage / IndexedDB / WebSQL / AppCache
- * - WebViewDatabase 清表单 & HTTP Basic 凭证
- */
- function clearAllAndroidWebViewData() {
- try {
- const CookieManager = plus.android.importClass('android.webkit.CookieManager')
- const cm = CookieManager.getInstance()
- try {
- cm.removeAllCookies(null)
- } catch (e) {
- try {
- cm.removeAllCookie()
- } catch (e2) {}
- }
- try {
- cm.removeSessionCookies(null)
- } catch (e) {
- try {
- cm.removeSessionCookie()
- } catch (e2) {}
- }
- try {
- cm.flush()
- } catch (e) {}
- } catch (e) {}
- try {
- const WebStorage = plus.android.importClass('android.webkit.WebStorage')
- WebStorage.getInstance().deleteAllData()
- } catch (e) {}
- try {
- const WebViewDatabase = plus.android.importClass('android.webkit.WebViewDatabase')
- const main = plus.android.runtimeMainActivity()
- const db = WebViewDatabase.getInstance(main)
- try {
- db.clearFormData()
- } catch (e) {}
- try {
- db.clearHttpAuthUsernamePassword()
- } catch (e) {}
- } catch (e) {}
- }
- /**
- * iOS:WKWebsiteDataStore 一次清除所有类型数据(localStorage/IndexedDB/Cookies/Cache 等)
- * selector 自 iOS 9 起稳定:removeDataOfTypes:modifiedSince:completionHandler:
- */
- function clearAlliOSWebViewData() {
- try {
- const WKWebsiteDataStore = plus.ios.importClass('WKWebsiteDataStore')
- const NSDate = plus.ios.importClass('NSDate')
- const types = plus.ios.invoke(WKWebsiteDataStore, 'allWebsiteDataTypes')
- const store = plus.ios.invoke(WKWebsiteDataStore, 'defaultDataStore')
- const since = plus.ios.invoke(NSDate, 'distantPast')
- plus.ios.invoke(
- store,
- 'removeDataOfTypes:modifiedSince:completionHandler:',
- types,
- since,
- null
- )
- } catch (e) {}
- }
- // #endif
- /**
- * 退出登录时:清空 WebView 所有站点的缓存与存储(LocalStorage/IndexedDB/SessionStorage/WebSQL/Cookies),
- * 外加 App 层 HTTP 缓存。不受「内置浏览器」偏好 gate,只要 App 端退出就清。
- */
- export function clearAllEmbeddedBrowserData() {
- // #ifdef APP-PLUS
- try {
- if (typeof plus === 'undefined') return
- let platform = ''
- try {
- platform = uni.getSystemInfoSync().platform
- } catch (e) {}
- if (platform === 'android') {
- clearAllAndroidWebViewData()
- } else if (platform === 'ios') {
- clearAlliOSWebViewData()
- }
- try {
- if (plus.cache && typeof plus.cache.clear === 'function') {
- plus.cache.clear()
- }
- } catch (e) {}
- } catch (e) {}
- // #endif
- }
|