之前写了篇新版隐私协议适配,分享下我在uniapp中的实现,小程序原生代码也可以参照实现,写得比较仓促,对照uniapp中的实现,这次带来小程序原生代码的实现
隐私弹窗
PrivacyModal
使用了van-dialog封装,可自行实现
<view>
<van-dialog
use-slot
show="{{show}}"
title="温馨提示"
id="PrivacyModal"
show-cancel-button
use-confirm-button-slot
use-cancel-button-slot
bind:close="onClose"
>
<view class="privacy-modal-content">
在您使用【xxxx】服务之前,请仔细阅读 <text class="btn-link" catch:tap="openPrivacyContract">{{ privacyContractName }}</text>,如你同意{{privacyContractName}}
,请点击同意开始使用【xxxx】
</view>
<view class="flex-between privacy-modal-btn-container">
<button
id="disagree-btn"
catch:tap="handleDisagree"
class="privacy-cancel-btn flex-center" slot="cancel-button">拒绝</button>
<button
id="agree-btn"
open-type="agreePrivacyAuthorization"
bind:agreeprivacyauthorization="handleAgree"
class="privacy-confirm-btn flex-center" slot="confirm-button">同意
</button>
</view>
</van-dialog>
</view>
style
.privacy-modal-content {
box-sizing: border-box;
padding: 5px 15px 10px;
}
.privacy-modal-btn-container {
box-sizing: border-box;
padding: 5px 15px 20px;
}
.privacy-modal-btn-container .privacy-cancel-btn {
font-size: 14px;
line-height: 1;
border-radius: 4px!important;
width: 100px;
color: #606266;
padding: 8px 0!important;
background: #f1f1f1;
}
.privacy-modal-btn-container .privacy-confirm-btn {
line-height: 1;
font-size: 14px;
border-radius: 4px!important;
width: 150px;
color: #ffffff;
padding: 8px 0!important;
background: green;
}
.btn-link {
color: #1B97FF;
}
.flex-center{
display:flex;
align-items:center;
justify-content:center;
}
.flex-between{
display:flex;
align-items:center;
justify-content:space-between;
}
js
const app = getApp()
Component({
options:{
addGlobalClass: true
},
properties: {
background: {
type: String,
value: ''
}
},
data: {
show: false,
resolve: null,
reject: null,
privacyContractName: '',
resolvePrivacyAuthorization: null
},
methods: {
check() {
app.globalData.inPrivacyChecking = true
return new Promise((resolve, reject) => {
this.data.resolve = resolve
this.data.reject = reject
if (!wx.canIUse('getPrivacySetting')) {
resolve()
return
}
wx.getPrivacySetting({
success: (res) => {
if (!res.needAuthorization) {
resolve()
return
}
this.setData({
privacyContractName: res.privacyContractName,
show: true
})
}
})
}).finally(() => {
app.globalData.inPrivacyChecking = false
})
},
openPrivacyContract() {
wx.openPrivacyContract()
},
handleDisagree() {
this.data.resolvePrivacyAuthorization &&
this.data.resolvePrivacyAuthorization({ buttonId: 'disagree-btn', event: 'disagree' })
this.setData({
show: false
})
this.data.reject && this.data.reject()
},
handleAgree() {
this.data.resolvePrivacyAuthorization && this.data.resolvePrivacyAuthorization({ buttonId: 'agree-btn', event: 'agree' })
this.setData({
show: false
})
this.data.resolve && this.data.resolve()
}
}
})
对隐私弹窗进行同步调用封装
usePrivacyCheck.js
let curPromise = null
export default function UsePrivacyCheck(options = {}) {
const app = getApp()
// 如果处于检查中,返回保存好的curPromise,多个隐私接口调用共用 inPrivacyChecking现在app.globalData 中声明
const inPrivacyChecking = app.globalData.inPrivacyChecking
if (inPrivacyChecking && curPromise) {
return curPromise
}
curPromise = null
let { vm } = options
const pages = getCurrentPages()
if (!vm) {
vm = pages[pages.length-1] // 这里就是取当前页面,可自行实现
}
const instance = vm.selectComponent('#privacy-modal')
if (!instance) {
console.error('没有找到对应的Modal实例,请检查id设置是否为privacy-modal')
curPromise = new Promise((resolve, reject) => {
wx.getPrivacySetting({
success: (res) => {
if (!res.needAuthorization) {
resolve()
return
}
// 页面没有放置隐私弹窗字段的情况下跳转到一个隐私检查的页面,并且通过event来接收最终授权状态
wx.navigateTo({
url: '/pages/user/privacyCheck/privacyCheck',
events:{
complete: ({ authorized }) => {
if (authorized) {
resolve()
} else {
reject()
}
}
}
})
}
})
})
return curPromise
}
curPromise = instance.check()
return curPromise
}
在app.json
配置全局组件和 __usePrivacyCheck__
usingComponents:{
"privacy-modal": "./pages/components/PrivacyModal/index"
}
"__usePrivacyCheck__": true
这样我们就能在代码中使用UsePrivacyCheck来检测隐私授权状态了,并且同步得到授权结果,还可以将UsePrivacyCheck
封装到自己的一些包装过的调用隐私接口的工具方法中
wxml中
<privacy-modal id="privacy-modal"></privacy-modal>
页面js中
UsePrivacyCheck().then(()=>{
// 用户已同意
}).catch(()=>{
//用户已拒绝
})
比如在app.js
中,我封装了一个获取地理位置并解析详细地址的方法
// old
setGlobalAddress(op){
return setGlobalDataAddress(op) // 内部实现就不展开了,里面调用了getLocation接口
}
//new
setGlobalAddress (op) {
return UsePrivacyCheck().then(()=>{
return setGlobalDataAddress(op)
}).catch(()=>{
getApp().globalData.location = {
latitude: 0,
longitude: 0,
addresses: '',
formatted_addresses: '',
myLocation: {
latitude: 0,
longitude: 0,
}
}
return Promise.reject()
})
},
上述代码都是主动触发检测,为了实现被动触发,我们新增一个隐私授权页面,主要用于被动触发和使用了 UsePrivacyCheck
但是没有在页面放置 <privacy-modal id="privacy-modal"></privacy-modal>
的情况
用于被动触发的privacyCheck授权页
记得在app.json中声明
wxml
<view>
<privacy-modal id="privacy-modal"></privacy-modal>
</view>
js
import UsePrivacyCheck from '../../components/PrivacyModal/usePrivacyCheck'
Component({
properties: {},
data: {},
methods: {
onLoad(){
const eventChannel = this.getOpenerEventChannel()
UsePrivacyCheck()
.then(() => {
eventChannel.emit('complete', { authorized: true })
})
.catch(() => {
eventChannel.emit('complete', { authorized: false })
})
.finally(() => wx.navigateBack())
}
}
})
启动程序时在onLaunch设置授权监听
app.js
//
onLaunch: function (e) {
//....
this.addWxListener()
//....
}
//
addWxListener(){
if (!wx.canIUse('onNeedPrivacyAuthorization')){
return
}
wx.onNeedPrivacyAuthorization((resolve) => {
const pages = getCurrentPages()
const curPage = pages[pages.length-1]
const privacyModalInstance =curPage.selectComponent('#privacy-modal')
if (privacyModalInstance) {
privacyModalInstance.check()
return
}
// 没有隐私弹窗组件,跳转隐私授权页面页面
wx.navigateTo( {
url: '/pages/user/privacyCheck/privacyCheck',
events: {
complete: () => {}
}
})
})
},
总结
通过上述封装,我们可以实现主动触发、被动触发,隐私授权页面兜底,尽量覆盖更多的触发方式,并降低代码侵入性,我司调用隐私api的页面非常多,通过被动触发的方式进入授权页面,授权后返回,可以降低对现有代码的改动,避免改出问题,还可以融合到一些对小程序Page和Component封装逻辑中。
if (!wx.canIUse('onNeedPrivacyAuthorization')){ return } wx.onNeedPrivacyAuthorization((resolve) => { UsePrivacyCheck() })