前言:
近期收到了微信小程序对于隐私协议的整改,在下午体验了下官方demo后整理下方案,需要的开发者可直接复制代码, 在IDE里调试加__usePrivacyCheck__就不说了,直接开整。
第一步: 实现一个隐私协议弹窗:
新建隐私协议弹窗组件:privacyDialog
// 组件wxml
<view class="privacy-dialog {{visible ? 'active' : ''}}">
<view class="privacy-back {{visible ? 'active' : ''}}"></view>
<view class="privacy-container {{visible ? 'active' : ''}} {{useSafeArea ? 'change' : ''}}">
<view class="privacy-info">
<image src="{{mini_logo}}" mode="widthFix" class="privacy-logo" />
<text class="privacy-name">{{mini_name}}</text>
</view>
<view class="privacy-text">在您使用【{{mini_name}}】服务之前,请仔细阅读<text bindtap="openPrivacyContract">《{{mini_name}}隐私保护指引》</text>。如您同意,《{{mini_name}}隐私保护指引》,请点击“同意”开始使用【{{mini_name}}】</view>
<view class="privacy-btns">
<view id="disagree-btn" class="privacy-cancel-btn" bindtap="handleDisagree">不同意</view>
<button id="agree-btn" open-type="agreePrivacyAuthorization" class="privacy-confirm-btn" bindagreeprivacyauthorization="handleAgree">同意</button>
</view>
</view>
</view>
// 组件js
let privacyHandler
let privacyResolves = new Set()
let closeOtherPageshowDialogHooks = new Set()
if (wx.onNeedPrivacyAuthorization) {
wx.onNeedPrivacyAuthorization(resolve => {
if (typeof privacyHandler === 'function') {
privacyHandler(resolve)
}
})
}
const closeOtherPageshowDialog = (closeDialog) => {
closeOtherPageshowDialogHooks.forEach(hook => {
if (closeDialog !== hook) {
hook()
}
})
}
Component({
data: {
visible: false,
mini_logo: __wxConfig.accountInfo.icon,
mini_name: __wxConfig.accountInfo.nickname
},
properties: {
useSafeArea: { // 是否在非tabBar页面引用,适配tabbar底部 type: Boolean,
value: true
}
},
lifetimes: {
attached() {
const closeDialog = () => {
this.hideDialog()
}
privacyHandler = resolve => {
privacyResolves.add(resolve)
this.showDialog()
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
closeOtherPageshowDialog(closeDialog)
}
this.closeDialog = closeDialog
closeOtherPageshowDialogHooks.add(closeDialog)
},
detached() {
closeOtherPageshowDialogHooks.delete(this.closeDialog)
}
},
pageLifetimes: {
// 解决首页有手机授权、进入二级页面再返回就无法弹出隐私协议的问题。
show() {
if (this.closeDialog) {
privacyHandler = resolve => {
privacyResolves.add(resolve)
this.showDialog()
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
closeOtherPageshowDialog(this.closeDialog)
}
}
}
},
methods: {
handleAgree() {
this.hideDialog()
// 这里同时调用多个wx隐私接口:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行
privacyResolves.forEach(resolve => {
resolve({
event: 'agree',
buttonId: 'agree-btn'
})
})
privacyResolves.clear()
},
// 拒绝协议
handleDisagree(e) {
this.hideDialog()
privacyResolves.forEach(resolve => {
resolve({
event: 'disagree'
})
})
privacyResolves.clear()
},
// 显示隐私协议弹窗
showDialog() {
if (!this.data.visible) {
this.setData({
visible: true
})
// 控制底部页面不可滚动
wx.setPageStyle({
style: {
overflow: 'hidden'
}
})
}
},
// 隐藏隐私协议弹窗
hideDialog() {
if (this.data.visible) {
this.setData({
visible: false
})
// 控制底部页面可以滚动
wx.setPageStyle({
style: {
overflow: 'auto'
}
})
}
},
// 跳转隐私协议
openPrivacyContract() {
wx.openPrivacyContract({
success: res => {
console.log('openPrivacyContract success', res)
},
fail: err => {
console.error('openPrivacyContract fail', err)
}
})
},
// tabbar页面切换时关掉其他页面的隐私协议弹窗
tabBarPageShow() {
this.handleDisagree() // 切换tabbar默认用户点了拒绝,保持单例
if (this.closeDialog) {
privacyHandler = resolve => {
privacyResolves.add(resolve)
this.showDialog()
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
closeOtherPageshowDialog(this.closeDialog)
}
}
}
}
})
@import "/app.wxss";
.privacy-dialog {
width: 100%;
visibility: hidden;
position: relative;
overflow: hidden;
z-index: 1000;
}
.privacy-dialog.active {
visibility: visible;
}
.privacy-back {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 8888;
opacity: 0;
transition: all 0.3s;
}
.privacy-back.active {
opacity: 1;
transition: all 0.3s;
}
.privacy-container {
width: 100%;
background: #fff;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 9999;
border-radius: 32rpx 32rpx 0 0;
padding: 48rpx;
transform: translateY(100%);
transition: all 0.3s;
overflow: hidden;
}
.privacy-container.active {
transform: translateY(0%);
transition: all 0.3s;
}
.privacy-container.change {
padding-bottom: calc(env(safe-area-inset-bottom) + 32rpx);
}
.privacy-info {
width: 100%;
display: flex;
align-items: center;
}
.privacy-logo {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
}
.privacy-name {
margin-left: 8rpx;
font-size: 32rpx;
font-weight: bold;
}
.privacy-text {
font-size: 28rpx;
color: #808999;
margin: 32rpx 0;
letter-spacing: 2rpx;
}
.privacy-text text {
color: #1277FF;
}
.privacy-btns {
width: 470rpx;
display: flex;
margin: 0 auto;
justify-content: space-between;
align-items: center;
}
.privacy-cancel-btn {
width: 220rpx;
height: 90rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 14rpx;
color: #07c160;
background-color: #F2F2F2;
font-weight: bold;
margin: 0;
padding: 0;
}
.privacy-confirm-btn {
width: 220rpx;
height: 90rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 14rpx;
color: #fff;
background: #07c160;
font-size: 32rpx;
font-weight: bold;
margin: 0;
padding: 0;
}
第二步:如何使用?
这里有两种情况需要处理:一种是tabbar页面,一种是普通页面。
首先在app.json全局引入自定义组件,无需在单个页面json中额外引入:
"usingComponents": {
"privacy-dialog": "/components/privacyDialog/index"
},
- tabbar页面:存在tabbar页面使用手机号授权提示
invoke getPhoneNumber too frequently
操作频繁的问题。 - 原因是切换tabbar并不会导致组件实例被销毁,上个tabbar页面手机号授权会被隐私协议pending住,在当前页面再次请求手机号授权就会提示该错误。可按下方方式处理:
// tabbar的wxml引入组件,id自定义:
<privacy-dialog id="im-login" />
// js处理:
// tabbar item点击后触发隐私协议组件内的tabBarPageShow方法销毁上个页面的隐私协议弹窗实例。
onTabItemTap() {
this.selectComponent('#im-login').tabBarPageShow()
}
- 普通页面无需特殊处理,根据下面贴出来的官方文档全局搜索使用到的API,在该API对应的页面直接引用隐私协议弹窗组件即可。
// 使用到了文档中的api,就需要在wxml引入隐私协议组件:
<privacy-dialog />
老规矩,结尾放代码片段,有问题评论区讨论:
https://developers.weixin.qq.com/s/ArnN74mh7BLG
记录:8月30日及31日上午正常,8月31日下午灰度了基础库,tabBarPageShow方法目前测试无效。最新的解决方案是页面onHide时wx:if移除组件实例,onShow再挂载。
<privacy-dialog id="privacy-dialog-page1" useSafeArea="{{false}}" wx:if="{{showPrivacy}}" />
data: {
showPrivacy: true,
},
onShow() {
this.setData({
showPrivacy: true
})
},
onHide() {
this.setData({
showPrivacy: false
})
},
9月2日官方说已恢复正常,测试发现已恢复,改回tabbarPageShow方法。
https://developers.weixin.qq.com/community/develop/doc/000ae292b88fb092374030b6d6ec00
这玩意现在还有用吗?
大佬,想请问下这个:
首页index页面首先弹“获取位置信息”的弹框,点击拒绝,之后点击“到非tabbar页面”到page3,页面没有弹框,直接走fail,我想page3页面设置一个按钮,点击再次弹“获取位置信息”的弹框,请问应该在点击事件里面怎么写啊?
大佬,我再uniapp中使用,将组件放在wx模块下,然后对应页面引用,但是在tabBar的vue页面加载后点击手机号授权就一直提示:invoke getPhoneNumber too frequently,按照上面的方法也不行
👍
大佬。我贴的你的代码,tabbar里面用,为啥我是先执行的页面的 wx.getLocation 呢
赞,直接贴源码啦