背景
项目很多地方使用了隐私接口,希望能以最小侵入性进行实现
隐私弹窗
JrModal是我对uview的modal组件的封装,可自行调整
inPrivacyChecking
是控制重复检测的标识
<script>
import JrModal from '@/components/JrModal/index.vue'
import { mapMutations } from 'vuex'
export default {
name: 'JrPrivacyModal',
components: { JrModal },
data() {
return {
show: false,
resolve: null,
reject: null,
refuse: false,
privacyContractName: '',
resolvePrivacyAuthorization: null
}
},
watch: {
show(val) {
this.setInPrivacyChecking(val)
if (!val) {
this.refuse = false
}
}
},
beforeDestroy() {
this.setInPrivacyChecking(false)
},
methods: {
...mapMutations('app', ['setInPrivacyChecking']),
check() {
this.setInPrivacyChecking(true)
return new Promise((resolve, reject) => {
//#ifdef MP-WEIXIN
this.resolve = resolve
this.reject = reject
if (!wx.canIUse('getPrivacySetting')) {
resolve()
return
}
wx.getPrivacySetting({
success: (res) => {
if (!res.needAuthorization) {
resolve()
return
}
this.privacyContractName = res.privacyContractName
this.show = true
// this.requirePrivacyAuthorize()
}
})
//#endif
//#ifndef MP-WEIXIN
resolve()
//#endif
}).finally(() => {
this.setInPrivacyChecking(false)
})
},
// requirePrivacyAuthorize() {
// wx.requirePrivacyAuthorize({
// success: () => {
// this.resolve && this.resolve()
// },
// fail: () => {
// this.reject && this.reject()
// }, // 用户拒绝授权
// complete: () => {
// this.show = false
// }
// })
// },
openPrivacyContract() {
wx.openPrivacyContract()
},
handleDisagree() {
this.resolvePrivacyAuthorization &&
this.resolvePrivacyAuthorization({ buttonId: 'disagree-btn', event: 'disagree' })
this.show = false
this.reject && this.reject()
},
handleAgree() {
this.resolvePrivacyAuthorization && this.resolvePrivacyAuthorization({ buttonId: 'agree-btn', event: 'agree' })
this.show = false
this.resolve && this.resolve()
}
}
}
</script>
<template>
<view>
<jr-modal
ref="jr-privacy-dialog"
:show.sync="show"
width="300px"
:show-cancel-button="false"
:show-confirm-button="false"
>
<view v-if="!refuse">
<view class="leading-inherit-1.4">
欢迎使用xxxx!我们将通过
<text
class="text-blue-500"
@click="openPrivacyContract"
>{{ privacyContractName }}</text
>,帮助您了解我们收集、使用个人信息及用途。如您同意,可点击“同意”开始接受我们的服务。
</view>
<view class="mt-10px flex items-center justify-between">
<button
class="m-0 h-30px w-80px rounded-full border border-solid border-jr-peach-puff bg-none text-14px text-jr-tip f-center after:border-none"
@click="refuse = true"
>拒绝</button
>
<button
id="agree-btn"
open-type="agreePrivacyAuthorization"
class="m-0 h-30px w-120px rounded-full !text-14px jr-btn-primary"
@agreeprivacyauthorization="handleAgree"
>同意</button
>
</view>
</view>
<view v-else>
<view class="leading-inherit-1.4">
若您不同意
<text
class="text-blue-500"
@click="openPrivacyContract"
>{{ privacyContractName }}</text
>,很遗憾,我们将无法为您提供服务。
</view>
<view class="mt-10px flex items-center justify-between">
<button
id="disagree-btn"
class="m-0 h-30px w-100px rounded-full border border-solid border-jr-peach-puff bg-none text-14px text-jr-tip f-center after:border-none"
@click="handleDisagree"
>暂不同意</button
>
<button
class="m-0 h-30px w-120px rounded-full !text-14px jr-btn-primary"
@click="refuse = false"
>查看协议</button
>
</view>
</view>
</jr-modal>
</view>
</template>
<style scoped lang="scss"></style>
对隐私弹窗进行同步调用封装
usePrivacyCheck.js
/* eslint-disable */
import { navigateTo, pageUtil } from '@/utils'
import { PAGES } from '@/constant/pages'
import store from '@/store/store'
let curPromise = null
/**
* @param {
* {
* [vm]
* }
* } options
* @return {Promise<void>}
* @constructor
*/
export default function UsePrivacyCheck(options = {}) {
// 如果处于检查中,返回保存好的curPromise,多个隐私接口调用共用
const inPrivacyChecking = store.getters['app/inPrivacyChecking']
if (inPrivacyChecking && curPromise) {
return curPromise
}
curPromise = null
//#ifndef MP-WEIXIN
// 非微信小程序直接检测通过,无需进行下一步
return Promise.resolve()
//#endif
//#ifdef MP-WEIXIN
// eslint-disable-next-line no-unreachable
let { vm } = options
if (!vm) {
vm = pageUtil.getCurPage().$vm // 这里就是取当前页面,可自行实现
}
const instance = vm.$refs['jr-privacy-modal']
if (!instance) {
console.error('没有找到对应的Modal实例,请检查vm、ref设置是否为jr-privacy-modal')
curPromise = new Promise((resolve, reject) => {
wx.getPrivacySetting({
success: (res) => {
if (!res.needAuthorization) {
resolve()
return
}
// 页面没有放置隐私弹窗字段的情况下跳转到一个隐私检查的页面,并且通过event来传递状态
navigateTo(PAGES.privacyCheck, {
events: {
complete: ({ authorized }) => {
if (authorized) {
resolve()
} else {
reject()
}
}
}
})
}
})
})
return curPromise
}
// eslint-disable-next-line no-unreachable
curPromise = instance.check()
return curPromise
//#endif
}
上述代码中
navigateTo
是对uni.navigateTo的小小封装
function navigateTo(url, options = {}) {
if (!url.startsWith('/')) {
url = '/' + url
}
const { query = {}, events = {} } = options
let queryKeys = Object.keys(query)
const params = queryKeys.reduce((previousValue, currentValue, index) => {
return (
`${index === 0 ? '?' : previousValue}` +
`${currentValue}=${query[currentValue]}${index === queryKeys.length - 1 ? '' : '&'}`
)
}, '')
url = `${url}${params ? params : ''}`
return uni.navigateTo({
url,
events
})
}
这样我们就能在代码中使用UsePrivacyCheck
来检测隐私授权状态了,并且同步得到授权结果
UsePrivacyCheck().then(()=>{
// 用户已同意
}).catch(()=>{
//用户已拒绝
})
privacyCheck页面
之所以会有这个页面,主要是用于被动触发或者页面忘记放置隐私弹窗时使用
<script>
import JrPrivacyModal from '@/components/JrPrivacyModal/index.vue'
import UsePrivacyCheck from '@/components/JrPrivacyModal/usePrivacyCheck'
export default {
name: 'privacyCheck',
components: { JrPrivacyModal },
data() {
return {}
},
mounted() {
const eventChannel = this.getOpenerEventChannel()
// 使用eventChannel传递授权状态,在usePrivacyCheck.js中就能知道是否同意了
UsePrivacyCheck()
.then(() => {
eventChannel.emit('complete', { authorized: true })
})
.catch(() => {
eventChannel.emit('complete', { authorized: false })
})
.finally(() => uni.navigateBack())
}
}
</script>
<template>
<view>
<jr-privacy-modal ref="jr-privacy-modal" />
</view>
</template>
<style scoped lang="scss"></style>
程序启动时,APP.vue中在onLaunch设置监听
async onLaunch(e) {
//...
//#ifdef MP-WEIXIN
wx.onNeedPrivacyAuthorization((resolve) => {
console.log('on needPrivacyAuthorization')
const curPage = pageUtil.getCurPage()
const privacyModalInstance = curPage.$vm.$refs['jr-privacy-modal']
// 当前页面有jr-privacy-modal的情况下,直接唤起该组件
if (privacyModalInstance) {
// 设置store中 inPrivacyChecking为true // 逻辑自行实现
this.setInPrivacyChecking(true)
privacyModalInstance.show = true
privacyModalInstance.resolvePrivacyAuthorization = resolve
return
}
// 没有组件,跳转隐私页面
navigateTo(PAGES.privacyCheck, {
events: {
complete: () => {}
}
})
})
//#endif
//...
},
总结
到这里基本就实现完毕了,不用去调整onShow,onLoad,尽量避免了改动过多代码。由于美好的周末即将开始,马上下班了,写得略微仓促,如果有不清楚的,欢迎评论。
补充下小程序中的实现
https://developers.weixin.qq.com/community/develop/article/doc/0008ca04d3807061e73053d206b413