嵌套/同域重叠路径PWA如何检测当前运行的应用实例?
场景说明
尽管web.dev官方文档不推荐在同一域名下部署多个PWA,但实际业务中存在嵌套PWA的部署场景:
- 外层全局应用A,作用域为
example.com - 内层子产品应用B,作用域为
example.com/m/subproduct
两个PWA均可以访问example.com/m/subproduct/test页面,需要在JavaScript环境中检测当前页面运行在应用A还是应用B实例中,以下思路已验证无法可靠实现检测:
- 暂未找到对应JS API可查询PWA安装时使用的manifest配置信息,例如
start-url字段 - 两个应用域名完全一致,
localStorage/sessionStorage的存储作用域完全相同,且存储数据可被用户清除,无法作为可靠判断依据 - 通过携带特殊GET参数的
start-url在sessionStorage中写入标记的方案,仅能识别从应用启动器打开的会话,无法覆盖应用内跳转、外部链接唤起等其他启动路径 - 两个应用已安装/激活的Service Worker完全一致,无法通过该特征区分
- 新版PWA AppID机制暂未提供JS上下文下的查询入口,无法获取对应ID做区分
- 可通过如下代码检测PWA是否运行在standalone独立显示模式:
但两个应用均配置为standalone模式,无法通过display属性差异做区分。matchMedia('(display-mode: standalone)').matches
可落地的可靠检测方案
1. 主题色媒体查询匹配法
给两个PWA的manifest文件配置不同的theme_color值(可选择视觉上几乎无差异、不会影响用户体验的相近色值,比如应用A配置#ffffff,应用B配置#fffffe),通过主题色媒体查询即可直接识别当前生效的manifest对应的PWA实例:
// 匹配应用A的主题色 const runningInAppA = window.matchMedia('(theme-color: #ffffff)').matches // 匹配应用B的主题色 const runningInAppB = window.matchMedia('(theme-color: #fffffe)').matches
注意:standalone模式下PWA窗口的主题色媒体查询优先匹配安装时manifest声明的theme_color,页面内动态修改<meta name="theme-color">不会改变该匹配结果,不会出现判断混淆。该方案不受存储清除、页面跳转路径、SW更新影响,兼容所有支持现代PWA能力的Chromium内核浏览器。
2. Service Worker响应头标记法
虽然两个应用使用的Service Worker核心逻辑一致,可在SW注册阶段针对不同作用域追加实例标记:在子应用B的SW注册逻辑中传入专属识别标识,SW的fetch事件监听中对所有匹配子应用作用域的请求,在响应头中追加自定义标识字段(例如X-PWA-Instance: B),页面加载时通过读取当前文档请求的响应头即可判断所属实例。该标记由激活状态的SW动态注入,不受用户手动清除站点存储影响,只要对应PWA实例的SW正常运行即可稳定返回正确标识。
3. 持久化存储兜底方案
针对上述两个方案暂不兼容的低版本浏览器,可做双层兜底:首次通过start_url中的特殊参数识别启动来源时,将实例标记写入IndexedDB持久化分区,同时配合SW在每次请求时校验补全标记,覆盖应用内跳转、外部链接唤起等非启动器入口场景,进一步提升检测准确率。
内容的提问来源于stack exchange,提问作者Riesling

