评论

新版隐私协议适配,分享下我在uniapp中的实现,小程序原生代码也可以参照实现

新版隐私协议适配,分享下我在uniapp中的实现,小程序原生代码也可以参照实现

背景

项目很多地方使用了隐私接口,希望能以最小侵入性进行实现

隐私弹窗

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,尽量避免了改动过多代码。由于美好的周末即将开始,马上下班了,写得略微仓促,如果有不清楚的,欢迎评论。

最后一次编辑于  2023-08-25  
点赞 0
收藏
评论

1 个评论

登录 后发表内容