前言:官方发布公告,自2023年9月15日起,对于涉及处理用户个人信息的小程序开发者,仅当开发者主动向平台同步用户已阅读并同意了小程序的隐私保护指引等信息处理规则后,方可调用微信提供的隐私接口。
涉及到的隐私接口:小程序用户隐私保护指引内容介绍
官方文档:小程序隐私协议开发指南
一、小程序
1.方式一在小程序端 设置 -->服务内容声明--->用户隐私保护指引
2.填写提审版本用户隐私保护指引
3.方式二:管理--> 版本管理-->提交代码审核-->信息填写页面
注意:若当前提交审核版本删除了最新的线上版本隐私说明中包含的隐私接口,无法在提审时进行编辑,建议开发者在版本发布后通过方式1进行修改。
二、项目
1.在项目里面找到 manifest.json 源码视图
"map-weixin":{"_usePrivacyCheck_":true}
三、微信开发者工具,详情-->本地设置--->调试基础库 ,最好>=2.33.0, 目前选择是3.0.0。
注意:如果发现privacyContractName没有返回的时间重新切换调试基础库。
四、1.在启动页app.vue设置监听函数,监听隐私接口,把回调的resolve函数挂到全局,在用户点击同意的时候调用。
App.vue
import useToggleStore from '@/stores/toggle-store'
const listenPrivacyOpen = () => {
const toggleStore = useToggleStore()
console.log(toggleStore.privacyModal,'toggleStore')
wx.onNeedPrivacyAuthorization((resolve: any, eventInfo: any) => {
toggleStore.privacyModal.resolvePrivacyAuthorization = resolve
toggleStore.togglePrivacyModal(true)
})
}
onLaunch(async (options) => {
listenPrivacyOpen()
})
2. store 设计
import { defineStore } from 'pinia';
const useToggleStore = defineStore<
string,
Record<string, any>
>('toggle', {
// 管理的数据
state: () => ({
privacyModal: {
show: false,
resolvePrivacyAuthorization: () => { },
},
}),
// 获取State中的状态,相当于计算属性(实现逻辑上的组合和应用)
getters: {},
// 异步操作
actions: {
togglePrivacyModal(value: boolean) {
this.privacyModal.show = value;
},
},
});
export default useToggleStore
3.在全局components提供全局组件 PrivacyModal,使用pinia全局变量控制显隐
privacy-modal.vue
<template>
<uni-popup ref="popup" type="center" :show="toggleStore.privacyModal.show">
<view class="reason-dialog uni-radius-t-lg">
<view class="title">用户隐私提示保护提示</view>
<view class="contents">感谢您使用本产品,您使用本产品前应当仔细阅读并同意<text @click="handleReadPrivacy" class="contents-text">{{
props.privacyContractName }}</text>当您点击同意并开始使用产品服务时,即表示你已理解并同意改条款内容,改条款将对您产生法律约束力。如您拒绝,无法更好地体验产品。
</view>
<view class="flex btns">
<button class="btn-cancel" @click="closeModal">拒绝</button>
<button class="confirm" :id="AGREE_ID" open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="handleAgreePrivacy">同意</button>
</view>
</view>
</uni-popup>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import useToggleStore from '@/stores/toggle-store'
const AGREE_ID = 'agree-btn'
const toggleStore = useToggleStore()
const props = withDefaults(defineProps<{
privacyContractName: string
}>(), {})
const popup = ref<any>()
const open = (value: string) => {
popup.value?.open()
}
const close = () => {
popup.value?.close()
}
// 打开隐私协议页面
const handleReadPrivacy = () => {
uni.showModal({
title: '提示',
content: '登录授权时需阅读小程序隐私保护指引',
success(res) {
if (res.confirm) {
wx.openPrivacyContract()
//同时进行就行
wx.getUserProfile()
}
}
})
}
// 关闭弹框
const closeModal = () => {
popup.value?.close()
}
// 同意隐私协议
const handleAgreePrivacy = () => {
closeModal()
toggleStore.privacyModal.resolvePrivacyAuthorization({
buttonId: AGREE_ID,
event: 'agree'
})
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.reason-dialog {
width: 555rpx;
margin: -80rpx 2rpx calc(var(--safe-area-inset-bottom) + 24rpx);
padding: 0rpx 20rpx;
background-color: $uni-white;
border-radius: 25rpx;
.title {
padding-top: 40rpx;
font-size: 36rpx;
color: #222222;
line-height: 50rpx;
text-align: center;
font-weight: bold;
}
.contents {
margin-bottom: 20rpx;
padding: 21rpx 20rpx 22rpx 20rpx;
font-size: 32rpx;
color: #222222;
line-height: 50rpx;
}
.contents-text {
color: $uni-primary;
}
.btns {
padding-bottom: 40rpx;
}
.btn-cancel {
width: 190rpx;
height: 70rpx;
color: $uni-main-color;
border-radius: 50rpx;
line-height: 70rpx;
border: 1rpx solid #a0a0a0;
}
.confirm {
margin-left: 34rpx;
width: 190rpx;
height: 70rpx;
border-radius: 50rpx;
color: #ffffff;
line-height: 70rpx;
background-color: $uni-primary;
}
.confirm-close {
position: fixed;
bottom: 150rpx;
left: 327rpx;
width: 60rpx;
height: 60rpx;
image {
width: 100%;
height: 100%;
}
}
}
</style>
4.引用组件
html:
<PrivacyModal ref="privacymodalRef" :privacyContractName="privacyContractName" />
ts:
import PrivacyModal from '@/components/privacy-modal.vue'
import { onLoad } from '@dcloudio/uni-app'
const privacyContractName = ref<string>('')
const privacymodalRef = ref<InstanceType<typeof PrivacyModal>>()
onLoad(() => {
wx.getPrivacySetting({
success: (res: any) => {
if (res.needAuthorization) {
// 需要弹出隐私协议
privacyContractName.value = res.privacyContractName
privacymodalRef.value?.open(res.privacyContractName)
} else {
console.log('用户同意了隐私协议 或 无需用户同意隐私协议')
}
},
fail: () => { }
})
})
5. 借 vite 的 transform 函数注入到所有页面(一次性注入到所有页面,避免未来使用到的时候踩坑)
/**
* 页面级注入全局组件
* @param comp 注入的组件
* @returns config
*/
const injectTemplateToPages = (comp: string): PluginOption => {
return {
name: 'injectTemplateToPages',
enforce: 'pre',
// code 代码,id 文件路径
transform(code, id) {
// vue文件,且不是App.vue,不是components目录下的文件
const shouldInject =
/\.vue$/.test(id) && !/App\.vue$/.test(id) && !/components/.test(id);
if (shouldInject) {
// 注入模板代码
code = code.replace(/\B<template>/, (_) => `${_}${comp}`);
}
return {
code,
map: null,
};
},
};
};
// https://vitejs.dev/config/
export default defineConfig({
mode: process.env.NODE_ENV,
// 注入隐私弹窗
plugins: [uni(), injectTemplateToPages('<PrivacyModal />')],
build: {
sourcemap: true,
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
});