当前位置:   article > 正文

uniapp (vue3) 小程序隐私协议方案分享_配置小程序用户隐私保护指引vue

配置小程序用户隐私保护指引vue

一、前言

开始之前,如果还没阅读过 隐藏协议整改公告 的,其实也不要紧,官方公告指引写的那叫一个一言难尽,也不知道跟谁学的,貌似写了很多,有用的却不多,接下来以我的角度给大家解读一下本次更新的要点和具体的操作。

二、公告解读

公告其实可以很简单的理解:自2023年9月15日起,涉及用户隐私的接口如:获取你的头像昵称,选择地址wx.chooseAddress,获取手机号等隐私接口如果被调用,中间会触发一个监听回调:wx.onNeedPrivacyAuthorization,具体有哪些,可以参考以下:小程序用户隐私保护指引内容介绍
提供一段示例代码

  uni.onNeedPrivacyAuthorization((resolve, eventInfo) => {
    console.log('onNeedPrivacyAuthorization', eventInfo);
    toggleStore.privacyModal.resolvePrivacyAuthorization = resolve;
    toggleStore.togglePrivacyModal(true);
  });
  • 1
  • 2
  • 3
  • 4
  • 5

这个函数的回调会提供一个 resolve 函数,只有调用 resolve 函数 resolve({event: ‘agree’}) 才能继续触发之前那些隐私接口,类似加了中间件。
另外提一句,第三方开发如果要配置隐私协议,需要通过接口配置,参考:第三方开发隐私协议配置

三、方案设计

1. 在启动页 app 设置监听函数,监听隐私接口,把回调的resolve函数挂在到全局,在用户点击同意的时候调用

App.vue

   import { useToggleStore } from '@/store';
    const listenPrivacyOpen = () => {
    const toggleStore = useToggleStore();
    uni.onNeedPrivacyAuthorization((resolve, eventInfo) => {
  	  toggleStore.privacyModal.resolvePrivacyAuthorization = resolve;
      toggleStore.togglePrivacyModal(true);
     })
    };
     onLaunch(() => {
      listenPrivacyOpen();
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3. 提供全局组件 PrivacyModal,使用pinia全局变量控制显隐

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128

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'),
    },
  },
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

四、用户昵称填写能力

由于用户昵称填写使用的是 input 组件,是不会触发上述的隐私事件监听事件的,需要用到主动查询 wx.getPrivacySetting,这部分就不写了,比较简单。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/552169
推荐阅读