- uniapp (vue3) 小程序隐私协议方案分享
!!!重要,如果还没做隐私弹窗不用往下看了,先看这里: 新版隐私协议弹窗说明 一、前言 开始之前,如果还没阅读过 隐私协议整改公告 的,其实也不要紧,官方公告指引写的那叫一个一言难尽,也不知道跟谁学的,貌似写了很多,有用的却不多,接下来以我的角度给大家解读一下本次更新的要点和具体的操作。 二、公告解读 公告其实可以很简单的理解:自2023年9月15日起,涉及用户隐私的接口如:获取你的头像昵称,选择地址wx.chooseAddress,获取手机号等隐私接口如果被调用,中间会触发一个监听回调:wx.onNeedPrivacyAuthorization,具体有哪些,可以参考以下:小程序用户隐私保护指引内容介绍 提供一段示例代码: [代码] uni.onNeedPrivacyAuthorization((resolve, eventInfo) => { console.log('onNeedPrivacyAuthorization', eventInfo); toggleStore.privacyModal.resolvePrivacyAuthorization = resolve; toggleStore.togglePrivacyModal(true); }); [代码] 这个函数的回调会提供一个 resolve 函数,只有调用 resolve 函数 resolve({event: ‘agree’}) 才能继续触发之前那些隐私接口,类似加了中间件。 另外提一句,第三方开发如果要配置隐私协议,需要通过接口配置,参考:第三方开发隐私协议配置 三、方案设计 1. 在启动页 app 设置监听函数,监听隐私接口,把回调的resolve函数挂在到全局,在用户点击同意的时候调用 [代码]App.vue[代码] [代码] import { useToggleStore } from '@/store'; const listenPrivacyOpen = () => { if (!uni.canIUse('onNeedPrivacyAuthorization')) return; const toggleStore = useToggleStore(); uni.onNeedPrivacyAuthorization((resolve, eventInfo) => { toggleStore.privacyModal.resolvePrivacyAuthorization = resolve; toggleStore.togglePrivacyModal(true); }) }; onLaunch(() => { listenPrivacyOpen(); }) [代码] 2. store 设计 [代码]import { defineStore } from 'pinia'; const useToggleStore = defineStore< string, IStore.Toggle.State, Record<string, any>, IStore.Toggle.Action >('toggle', { state: () => ({ privacyModal: { show: false, resolvePrivacyAuthorization: () => {}, }, }), actions: { togglePrivacyModal(value: boolean) { this.privacyModal.show = value; }, }, }); export default useToggleStore; [代码] 3. 提供全局组件 PrivacyModal,使用pinia全局变量控制显隐 [代码]main.ts[代码] 全局注册组件 [代码]import PrivacyModal from '@/components/privacy-modal/index.vue'; app.component('PrivacyModal', PrivacyModal); // 统一隐私协议弹窗 [代码] 隐私弹窗 [代码]privacy-modal.vue[代码] [代码]<template> <u-popup class="privacy-wrap" :show="toggleStore.privacyModal.show" mode="center" round="10"> <view class="content"> <view class="title">隐私协议须知</view> <view class="tips"> 在使用本服务之前,请仔细阅读 <text class="privacy-link" @click="handleReadPrivacy"> {{ privacyContractName }} </text> 。如果你同意{{ privacyContractName }},请点击“同意”开始使用服务。 </view> <view class="btns"> <button class="btn cancel" @click="handleDisagreePrivacy">取消</button> <button :id="AGREE_ID" class="btn" open-type="agreePrivacyAuthorization" @agreeprivacyauthorization="handleAgreePrivacy"> 同意 </button> </view> </view> </u-popup> </template> <script setup lang="ts"> import { promisify } from '@/helper/wx'; import { useToggleStore } from '@/store'; import { ref } from 'vue'; const getPrivacySetting = promisify(uni.getPrivacySetting); // 同意按钮id const AGREE_ID = 'agree-btn'; const toggleStore = useToggleStore(); const privacyContractName = ref('隐私保护协议'); // 初始化隐私协议 initPrivacyInfo(); async function initPrivacyInfo() { const res = await getPrivacySetting(); privacyContractName.value = res.privacyContractName; } /** * 阅读隐私协议 */ function handleReadPrivacy() { uni.openPrivacyContract(); } /** * 关闭弹窗 */ function closeModal() { toggleStore.togglePrivacyModal(false); } /** * 拒绝隐私协议 */ function handleDisagreePrivacy() { closeModal(); toggleStore.privacyModal.resolvePrivacyAuthorization({ event: 'disagree', }); } /** * 同意隐私协议 */ function handleAgreePrivacy() { closeModal(); toggleStore.privacyModal.resolvePrivacyAuthorization({ buttonId: AGREE_ID, event: 'agree', }); } </script> <style lang="scss" scoped> .content { width: 290px; padding: 20px; border-radius: 10px; } .tips { margin-top: 16px; .privacy-link { color: #34a5fc; } } .btns { display: flex; align-items: center; justify-content: center; margin-top: 30px; .btn { width: 120px; height: 36px; background: var(--bg-color); text-align: center; line-height: 36px; color: #fff; border-radius: 20px; font-size: 16px; &.cancel { border: 1px solid var(--bg-color); color: var(--bg-color); background: #fff; } &:not(:last-child) { margin-right: 20px; } } } </style> [代码] 4. 借 vite 的 transform 函数注入到所有页面(一次性注入到所有页面,避免未来使用到的时候踩坑) [代码]vite.config.ts[代码] [代码]/** * 页面级注入全局组件 * @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'), }, }, }); [代码] 四、用户昵称填写能力 由于用户昵称填写使用的是 input 组件,是不会触发上述的隐私事件监听事件的,需要用到主动查询 wx.getPrivacySetting,这部分就不写了,比较简单。 [图片]
2023-09-15 - 隐私授权弹窗在调用手机号授权时会提示invoke getPhoneNumber too frequ?
隐私授权弹窗,在调用 手机号授权时,多页面会相互阻塞手机号获取 例如 首页中 点击 微信授权手机号登陆 按钮,获取手机号授权,弹出了隐私弹窗,此时不操作弹窗 进入一个详情页, 点击 微信授权手机号登陆 按钮,获取手机号授权,弹出了隐私弹窗,此时不操作弹窗, 返回 首页,再次点击微信授权手机号登陆 按钮, 此时会提示 invoke getPhoneNumber too frequently [图片] [图片] [图片] 代码片段 https://developers.weixin.qq.com/s/yOmtrGmY7lKW
2023-08-23 - 2022-03-04