评论

新版隐私协议适配,分享下我在小程序中的适配方式

新版隐私协议适配,分享下我在小程序中的适配方式

之前写了篇新版隐私协议适配,分享下我在uniapp中的实现,小程序原生代码也可以参照实现,写得比较仓促,对照uniapp中的实现,这次带来小程序原生代码的实现

隐私弹窗

PrivacyModal 使用了van-dialog封装,可自行实现

<view>
    <van-dialog
            use-slot
            show="{{show}}"
            title="温馨提示"
            id="PrivacyModal"
            show-cancel-button
            use-confirm-button-slot
            use-cancel-button-slot
            bind:close="onClose"
    >
        <view class="privacy-modal-content">
            在您使用【xxxx】服务之前,请仔细阅读 <text class="btn-link" catch:tap="openPrivacyContract">{{ privacyContractName }}</text>,如你同意{{privacyContractName}}
            ,请点击同意开始使用【xxxx】
        </view>
        <view class="flex-between privacy-modal-btn-container">
            <button
                    id="disagree-btn"
                    catch:tap="handleDisagree"
                    class="privacy-cancel-btn flex-center" slot="cancel-button">拒绝</button>
            <button
                    id="agree-btn"
                    open-type="agreePrivacyAuthorization"
                    bind:agreeprivacyauthorization="handleAgree"
                    class="privacy-confirm-btn flex-center" slot="confirm-button">同意
            </button>
        </view>
    </van-dialog>
</view>

style

.privacy-modal-content {
  box-sizing: border-box;
  padding: 5px 15px 10px;
}
.privacy-modal-btn-container {
  box-sizing: border-box;
  padding: 5px 15px 20px;
}
.privacy-modal-btn-container .privacy-cancel-btn {
  font-size: 14px;
  line-height: 1;
  border-radius: 4px!important;
  width: 100px;
  color: #606266;
  padding: 8px 0!important;
  background: #f1f1f1;
}
.privacy-modal-btn-container .privacy-confirm-btn {
  line-height: 1;
  font-size: 14px;
  border-radius: 4px!important;
  width: 150px;
  color: #ffffff;
  padding: 8px 0!important;
  background: green;
}
.btn-link {
  color: #1B97FF;
}
.flex-center{
  display:flex;
  align-items:center;
  justify-content:center;
}
.flex-between{
  display:flex;
  align-items:center;
  justify-content:space-between;
}

js

const app = getApp()
Component({
  options:{
    addGlobalClass: true
  },
  properties: {
    background: {
      type: String,
      value: ''
    }
  },
  data: {
    show: false,
    resolve: null,
    reject: null,
    privacyContractName: '',
    resolvePrivacyAuthorization: null
  },
  methods: {
    check() {
      app.globalData.inPrivacyChecking = true
      return new Promise((resolve, reject) => {
        this.data.resolve = resolve
        this.data.reject = reject
        if (!wx.canIUse('getPrivacySetting')) {
          resolve()
          return
        }
        wx.getPrivacySetting({
          success: (res) => {
            if (!res.needAuthorization) {
              resolve()
              return
            }
            this.setData({
              privacyContractName: res.privacyContractName,
              show: true
            })
          }
        })
      }).finally(() => {
        app.globalData.inPrivacyChecking = false
      })
    },
    openPrivacyContract() {
      wx.openPrivacyContract()
    },
    handleDisagree() {
      this.data.resolvePrivacyAuthorization &&
      this.data.resolvePrivacyAuthorization({ buttonId: 'disagree-btn', event: 'disagree' })
      this.setData({
        show: false
      })
      this.data.reject && this.data.reject()
    },
    handleAgree() {
      this.data.resolvePrivacyAuthorization && this.data.resolvePrivacyAuthorization({ buttonId: 'agree-btn', event: 'agree' })
      this.setData({
        show: false
      })
      this.data.resolve && this.data.resolve()
    }
  }
})

对隐私弹窗进行同步调用封装

usePrivacyCheck.js

let curPromise = null
export default function UsePrivacyCheck(options = {}) {
  const app = getApp()
  // 如果处于检查中,返回保存好的curPromise,多个隐私接口调用共用 inPrivacyChecking现在app.globalData 中声明
  const inPrivacyChecking = app.globalData.inPrivacyChecking
  if (inPrivacyChecking && curPromise) {
    return curPromise
  }
  curPromise = null
  let { vm } = options
  const pages = getCurrentPages()
  if (!vm) {
    vm = pages[pages.length-1] // 这里就是取当前页面,可自行实现
  }
  const instance = vm.selectComponent('#privacy-modal')
  if (!instance) {
    console.error('没有找到对应的Modal实例,请检查id设置是否为privacy-modal')
    curPromise = new Promise((resolve, reject) => {
      wx.getPrivacySetting({
        success: (res) => {
          if (!res.needAuthorization) {
            resolve()
            return
          }
          // 页面没有放置隐私弹窗字段的情况下跳转到一个隐私检查的页面,并且通过event来接收最终授权状态
          wx.navigateTo({
            url: '/pages/user/privacyCheck/privacyCheck',
            events:{
              complete: ({ authorized }) => {
                if (authorized) {
                  resolve()
                } else {
                  reject()
                }
              }
            }
          })
        }
      })
    })
    return curPromise
  }
  curPromise = instance.check()
  return curPromise
}

app.json配置全局组件和 __usePrivacyCheck__

usingComponents:{
    "privacy-modal": "./pages/components/PrivacyModal/index"
}
  "__usePrivacyCheck__": true

这样我们就能在代码中使用UsePrivacyCheck来检测隐私授权状态了,并且同步得到授权结果,还可以将UsePrivacyCheck封装到自己的一些包装过的调用隐私接口的工具方法中
wxml中

    <privacy-modal id="privacy-modal"></privacy-modal>

页面js中

UsePrivacyCheck().then(()=>{
// 用户已同意
}).catch(()=>{
//用户已拒绝
})

比如在app.js中,我封装了一个获取地理位置并解析详细地址的方法

// old

setGlobalAddress(op){
	  return setGlobalDataAddress(op) // 内部实现就不展开了,里面调用了getLocation接口
}

//new

 setGlobalAddress (op) {
        return UsePrivacyCheck().then(()=>{
            return setGlobalDataAddress(op)
        }).catch(()=>{
            getApp().globalData.location = {
                latitude: 0,
                longitude: 0,
                addresses: '',
                formatted_addresses: '',
                myLocation: {
                    latitude: 0,
                    longitude: 0,
                }
            }
            return Promise.reject()
        })
    },

上述代码都是主动触发检测,为了实现被动触发,我们新增一个隐私授权页面,主要用于被动触发和使用了 UsePrivacyCheck但是没有在页面放置 <privacy-modal id="privacy-modal"></privacy-modal>的情况

用于被动触发的privacyCheck授权页

记得在app.json中声明
wxml

 <view>
    <privacy-modal id="privacy-modal"></privacy-modal>
</view>

js

import UsePrivacyCheck from '../../components/PrivacyModal/usePrivacyCheck'

Component({
  properties: {},
  data: {},
  methods: {
    onLoad(){
      const eventChannel = this.getOpenerEventChannel()
      UsePrivacyCheck()
        .then(() => {
          eventChannel.emit('complete', { authorized: true })
        })
        .catch(() => {
          eventChannel.emit('complete', { authorized: false })
        })
        .finally(() => wx.navigateBack())
    }
  }
})

启动程序时在onLaunch设置授权监听

app.js

//
onLaunch: function (e) {
		//....
	this.addWxListener()
    //....
}
//
addWxListener(){
        if (!wx.canIUse('onNeedPrivacyAuthorization')){
            return
        }
        wx.onNeedPrivacyAuthorization((resolve) => {
            const pages = getCurrentPages()
            const curPage =  pages[pages.length-1]
            const privacyModalInstance =curPage.selectComponent('#privacy-modal')
            if (privacyModalInstance) {
                privacyModalInstance.check()
                return
            }
            // 没有隐私弹窗组件,跳转隐私授权页面页面
            wx.navigateTo( {
                url: '/pages/user/privacyCheck/privacyCheck',
                events: {
                    complete: () => {}
                }
            })
        })
    },

总结

通过上述封装,我们可以实现主动触发、被动触发,隐私授权页面兜底,尽量覆盖更多的触发方式,并降低代码侵入性,我司调用隐私api的页面非常多,通过被动触发的方式进入授权页面,授权后返回,可以降低对现有代码的改动,避免改出问题,还可以融合到一些对小程序Page和Component封装逻辑中。

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

1 个评论

  • 🇬 🇭 ٩۶
    🇬 🇭 ٩۶
    2023-08-31
    • handleDisagree和handleAgree中的this.data.resolvePrivacyAuthorization&&this.data.resolvePrivacyAuthorization()可以不要
    • addWxListener中可以直接改成


     if (!wx.canIUse('onNeedPrivacyAuthorization')){
                return
            }
            wx.onNeedPrivacyAuthorization((resolve) => {
              UsePrivacyCheck()
            })
    


    2023-08-31
    赞同 3
    回复
登录 后发表内容