feat: 实现隐私弹窗全链路功能,支持本地配置与远程patch融合
- 新增隐私管理器核心逻辑,支持URL路由规则匹配、远程patch签名校验与融合 - 实现启动期资源等待机制,确保弹窗在i18n、主题配置就绪后触发 - 新增启动进度条组件,展示启动阶段进度与状态 - 重构隐私弹窗组件生命周期,修复事件丢失问题并支持规则动态重评估 - 适配多端平台隐私检查逻辑,支持微信小程序、鸿蒙元服务与H5 - 支持uniacid租户隔离的持久化规则存储
This commit is contained in:
@@ -64,25 +64,10 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 调试: 记录本实例的 ID 和当前总数
|
||||
this.listenPrivacySettingChange()
|
||||
this.curPageShow()
|
||||
|
||||
// 监听全局隐私弹窗事件(由 App.vue boot 完成后通过 PrivacyManager.show() 触发)
|
||||
uni.$on('privacy:show', this.handlePrivacyShow)
|
||||
|
||||
// 监听关闭事件: 其他实例弹窗时通知本实例关闭
|
||||
uni.$on('privacy:forceClose', this.handleForceClose)
|
||||
|
||||
// 补偿: 若 PrivacyManager.show() 在本组件 mounted 之前 emit 了事件
|
||||
// 事件已丢失,此处通过 consumePendingShow 补偿弹窗
|
||||
if (PrivacyManager.consumePendingShow()) {
|
||||
this.$nextTick(() => {
|
||||
this.showPrivacyPopup()
|
||||
})
|
||||
}
|
||||
},
|
||||
// 关键: 把 listener 注册放到 created (而非 mounted),
|
||||
// 提前一个 microtask, 让 PrivacyManager.show() emit 的 privacy:show 不会丢
|
||||
// showPrivacyPopup() 内部访问 this.showPop 等响应式属性, 必须等到 mounted,
|
||||
// 所以 listener 可在 created 注册, 但 callback 仍要 nextTick 渲染
|
||||
created() {
|
||||
try {
|
||||
// #ifdef MP-WEIXIN
|
||||
@@ -90,7 +75,7 @@ export default {
|
||||
success: (res) => {
|
||||
this.platformContractName = res.privacyContractName || ''
|
||||
}
|
||||
});
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef QUICKAPP-WEBVIEW
|
||||
@@ -108,10 +93,28 @@ export default {
|
||||
// #ifdef MP-HARMONY
|
||||
// 鸿蒙元服务: 隐私授权由系统管理, 无需应用层查询 privacyContractName
|
||||
// #endif
|
||||
|
||||
// 提前注册 listener (晚于 created 早于 mounted, 减少事件丢失窗口)
|
||||
uni.$on('privacy:show', this.handlePrivacyShow)
|
||||
uni.$on('privacy:forceClose', this.handleForceClose)
|
||||
uni.$on('privacy:re-evaluate', this.handleReEvaluate)
|
||||
} catch (e) {
|
||||
console.error("=========低版本基础库==========", e)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 调试: 记录本实例的 ID 和当前总数
|
||||
this.listenPrivacySettingChange()
|
||||
this.curPageShow()
|
||||
|
||||
// 补偿: 若 PrivacyManager.show() 在本组件 mounted 之前 emit 了事件
|
||||
// listener 在 created 已注册, 大部分情况能直接命中, 但有些竞态导致 consumePendingShow 兜底
|
||||
if (PrivacyManager.consumePendingShow()) {
|
||||
this.$nextTick(() => {
|
||||
this.showPrivacyPopup()
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 接收全局隐私弹窗事件
|
||||
@@ -135,6 +138,43 @@ export default {
|
||||
this.disPopUp()
|
||||
},
|
||||
|
||||
/**
|
||||
* 接收规则重评估事件 (由 PrivacyManager.applyMergedRules 在远程 patch 之后触发)
|
||||
* action: 'show' → 当前不该弹 (白名单未命中) 但新规则要弹 → 重弹
|
||||
* action: 'dismiss' → 当前在弹 (白名单命中) 但新规则不该弹 → 关闭
|
||||
* action: 'noop' → 已同意, 无操作
|
||||
* 互斥: 只有第一个响应事件的实例真正处理, 避免多实例同时响应
|
||||
*
|
||||
* 关键: 这个函数会被所有已 mounted 的实例同时调用 (uni.$on 全局)
|
||||
* 必须用互斥机制保证只有一个实例实际弹窗/关窗。
|
||||
*
|
||||
* 设计: 复用 PrivacyManager 的 _pendingShow/_pendingHide 作为互斥 token:
|
||||
* - show: 只有消费到 token 的实例才能 popUp
|
||||
* - dismiss: 任何实例都允许 disPopUp (无副作用, 但要避免重复 emit forceClose)
|
||||
*/
|
||||
handleReEvaluate(info) {
|
||||
if (!info) return
|
||||
if (info.action === 'show') {
|
||||
// 新规则要弹 → 互斥消费 token
|
||||
if (!this.showPop) {
|
||||
// 仿 consumePendingShow 行为: 只有 _pendingShow=true 才能弹
|
||||
// 直接通过 showPrivacyPopup 内部 emit forceClose 通知其他实例
|
||||
if (PrivacyManager.consumePendingShow()) {
|
||||
this.showPrivacyPopup()
|
||||
} else {
|
||||
// 没有 token → 不弹 (被另一个实例接管了)
|
||||
}
|
||||
}
|
||||
} else if (info.action === 'dismiss') {
|
||||
// 新规则不该弹 → 只关闭已经弹窗的实例
|
||||
// 通过 forceClose 协议做: 关闭所有已经显示的实例
|
||||
if (this.showPop) {
|
||||
this.disPopUp()
|
||||
}
|
||||
}
|
||||
// noop: 用户已同意, 不动
|
||||
},
|
||||
|
||||
/**
|
||||
* 统一弹窗 + 关闭其他页面的弹窗
|
||||
* 通过 uni.$emit('privacy:forceClose') 通知其他实例关闭
|
||||
@@ -382,10 +422,14 @@ export default {
|
||||
// $lang() 返回真实翻译(效果与 H5 一致)
|
||||
this.prepareI18n();
|
||||
this.showPop = true;
|
||||
// 通知 PrivacyManager 弹窗实际显示状态 (用于 rules-updated 双阶段重评估)
|
||||
try { uni.$emit && uni.$emit('privacy:popup-state', { showing: true }) } catch (e) {}
|
||||
},
|
||||
|
||||
disPopUp() {
|
||||
this.showPop = false;
|
||||
// 通知 PrivacyManager 弹窗实际显示状态 (用于 rules-updated 双阶段重评估)
|
||||
try { uni.$emit && uni.$emit('privacy:popup-state', { showing: false }) } catch (e) {}
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
@@ -393,6 +437,7 @@ export default {
|
||||
// 移除全局事件监听
|
||||
uni.$off('privacy:show', this.handlePrivacyShow)
|
||||
uni.$off('privacy:forceClose', this.handleForceClose)
|
||||
uni.$off('privacy:re-evaluate', this.handleReEvaluate)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user