iOS Safari添加PWA到主屏后缓存丢失问题求助
问题描述
使用VueJS+Ionic开发PWA,已安装@vue/cli-plugin-pwa插件,需求是:用户访问网站时存储URL中的ref参数,待PWA安装到主屏后读取该参数。
当前实现:
- 在
registerServiceWorker.js的ready钩子中通过Cache API存储ref参数:
import { register } from 'register-service-worker' import { store } from './store/index.js' if (process.env.NODE_ENV === 'production') { register(`${process.env.BASE_URL}service-worker.js`, { registrationOptions: { scope: '.' }, async ready () { // 获取ref参数 const queryString = window.location.search const urlParams = new URLSearchParams(queryString) const ref = urlParams.get('ref') console.log(ref) // 缓存参数 try { if (ref !== null && ref !== '' && ref !== undefined && ref !== 'undefined') { const cache = await caches.open("ref") const responseBody = JSON.stringify({ref: ref}) const response = new Response(responseBody) await cache.put("/ref-code", response) } } catch { console.log('referral code not saved') } finally { store.commit("moduleMain/setInstallReady", true) } }, registered () { console.log('registered') }, cached () { console.log('Content has been cached for offline use.') }, updatefound () { console.log('New content is downloading.') }, updated () { console.log('New content is available; please refresh.') }, offline () { console.log('No internet connection found. App is running in offline mode.') }, error (error) { console.error('Error during service worker registration:', error) } }) }
- 在Ionic页面的
ionViewWillEnter钩子中读取缓存:
try { const cache = await caches.open("ref"); const response = await cache.match("/ref-code") if (response) { const responseBody = await response.json() this.$store.commit('moduleHome/setCode', responseBody["ref"]) this.$store.commit('moduleSettings/setCode', responseBody["ref"]) } } catch (error) { console.log("getToken error:", { error }); }
问题:Chrome浏览器测试正常,但iOS Safari添加到主屏后,缓存中的ref参数丢失。
解决方案
核心原因
iOS Safari的主屏PWA与浏览器共享隔离的缓存上下文:Cache API属于Service Worker的缓存空间,主屏启动的PWA会使用独立的Service Worker实例或缓存环境,导致无法读取浏览器中存储的缓存内容。而localStorage是基于域名的存储,同一域名下的浏览器和主屏PWA可共享该数据,是更可靠的选择。
方案1:改用localStorage存储参数
修改存储逻辑(registerServiceWorker.js)
将Cache API替换为localStorage:
async ready () { const queryString = window.location.search const urlParams = new URLSearchParams(queryString) const ref = urlParams.get('ref') console.log(ref) try { if (ref !== null && ref !== '' && ref !== undefined && ref !== 'undefined') { // 存储到localStorage localStorage.setItem('referral_ref', ref); } } catch { console.log('referral code not saved') } finally { store.commit("moduleMain/setInstallReady", true) } },
修改读取逻辑(页面钩子)
直接从localStorage读取:
try { const ref = localStorage.getItem('referral_ref'); if (ref) { this.$store.commit('moduleHome/setCode', ref); this.$store.commit('moduleSettings/setCode', ref); // 可选:读取后清除参数,避免重复使用 localStorage.removeItem('referral_ref'); } } catch (error) { console.log("getToken error:", { error }); }
方案2:优化存储时机(结合beforeinstallprompt事件)
为确保参数在安装前完成存储,可监听beforeinstallprompt事件(用户触发安装提示时):
// 在main.js或全局组件中添加 let deferredPrompt; window.addEventListener('beforeinstallprompt', (e) => { e.preventDefault(); deferredPrompt = e; // 存储ref参数 const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const ref = urlParams.get('ref'); if (ref) { localStorage.setItem('referral_ref', ref); } // 显示安装按钮 store.commit("moduleMain/setInstallReady", true); }); // 当用户点击安装按钮时触发 // 示例:在组件中调用 async handleInstall() { if (deferredPrompt) { deferredPrompt.prompt(); const { outcome } = await deferredPrompt.userChoice; if (outcome === 'accepted') { console.log('用户已安装PWA'); } deferredPrompt = null; } }
方案3:改用IndexedDB存储(复杂场景)
如果需要存储更多数据或有异步存储需求,IndexedDB是更强大的选择,它在iOS PWA中的支持更稳定:
- 存储时使用IndexedDB API写入
ref参数 - 读取时从IndexedDB中查询对应数据
内容的提问来源于stack exchange,提问作者dexter
相关产品推荐
相关产品推荐

