问:小程序订阅消息用户拒绝后,如何引导用户开启?并获得用户的操作状态?

前言

有些时间没折腾小程序了,话说年前小程序就发布了消息,于1月10日会下线模板消息下发功能,所有的订阅消息都要用户手动触发确认同意,这可就太难了,之前的 wx.openSettingwx.getPhoneNumberwx.getUserInfo等等API的调整,可把我折腾惨了,这次又来……

难道直接js调用,不爽吗?非要整手动确认,爽是肯定的,但如果从一个用户的角度出发,自己啥都没干,你就把我信息获取了、天天给我推一堆垃圾信息,那肯定不爽了,所以从这角度看,微信的调整也是为了尊重用户的隐私,毕竟用户第一嘛

今天主要是想分享一下,今天在处理这个订阅消息逻辑时,遇到当用户拒绝后,如何重新引导开启 「订阅消息」通知的问题,并在开启后获取到它的状态

如果你处理过小程序的订阅消息,应该是知道的,在用户拒绝或关闭消息总开关之后,我们引导用户手动开启「订阅消息」功能(也就是openSettingAPI的调用回调里,是拿不到scope.subscribeMessage状态的),开始我也纠结了很久,百度、google都用上了,同样发现很多的同学也有遇到这样的问题,而都没有找到解决方案,最后在我快要放弃的时候却突然灵光一闪,想到了个办法,所以抖胆BB几句,分析一下:

温馨提示:书读的少,却又喜欢瞎BB几句,内容仅为个人解决方案的思路,仅供参考,不足之处请见谅,勿喷,谢谢~

授权API示例

首先来看下调用的示例:


wx.requestSubscribeMessage({
  tmplIds: ['模版id'],
  success (res) {

  }
})

同时官方也说了,success 回调的模版对应有三种状态:

  1. accept = 同意
  2. reject = 拒绝
  3. ban = 后台封禁

fail 也有对应的状态码,如下:

errCode errMsg 说明
10001 TmplIds can't be empty 参数传空了
10002 Request list fai 网络问题,请求消息列表失败
10003 Request subscribe fail 网络问题,订阅请求发送失败
10004 Invalid template id 参数类型错误
10005 Cannot show subscribe message UI 无法展示 UI,一般是小程序这个时候退后台了导致的
20001 No template data return, verify the template id exist 没有模板数据,一般是模板 ID 不存在 或者和模板类型不对应 导致的
20002 Templates type must be same 模板消息类型 既有一次性的又有永久的
20003 Templates count out of max bounds 模板消息数量超过上限
20004 The main switch is switched off 用户关闭了主开关,无法进行订阅
20005 This mini program was banned from subscribing messages 小程序被禁封

本次要讲的是errorCode 20004reject状态时,

根据以往经验,如果拒绝了,我们肯定是使用直接使用 openSetting,引导用户进行手动开启授权(),比如:

//以微信运动为例
export default class Sign extends wepy.page {
  config = {
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: '赢积分',
  };
  components = {
    Toast: Toast,
    Modals: Modals
  };
  methods = {
  };
  data = {
    signHistory: []
  };
  getRunData() {
    wx.getWeRunData({
      success: res => {
        ……处理运动步数逻辑
      }
    });
  }
  setAuth() {
    wx.getSetting({
      success: res => {
        //第一步,检测是否有授权 - 没有授权
        if (!res.authSetting['scope.werun']) {
          //第二步,开始授权,但这里有一个坑点(腾讯的bug),之前授权过但是是拒绝,所以会进入失败
          wx.authorize({
            scope: 'scope.werun',
            success: () => {
              this.getRunData();
            },
            fail: () => {
              //第三步,引导用户,手动引导用户点击按钮,去设置页开启,## Modals是自定义组件
              this.$invoke('Modals', '__modalConfirm__', [
                '检测到您没有打微信运动的权限,是否去设置?',
                'openSetting',
                //第四步,进入设置页的回调 - 成功
                res => {
                  let { authSetting } = res.detail;
                  if (authSetting['scope.werun']) {
                    this.getRunData();
                  } else {
                    this.$invoke('Toast', '__warning__', [
                      `您没有同意授权微信运动,获取步数失败`
                    ]);
                  }
                },
                //第五步,点击取消按钮的回调
                () => {
                  this.$invoke('Toast', '__warning__', [
                    `您已拒绝微信运动授权,无法获取步数`
                  ]);
                }
              ]);
            }
          });
        } else {
          //第六步,已经授权直接进入保存逻辑
          // console.log("授权了")
          this.getRunData();
        }
      }
    });
  }
}

上面代码执行截图如下:
问:小程序订阅消息用户拒绝后,如何引导用户开启?并获得用户的操作状态?_第1张图片
问:小程序订阅消息用户拒绝后,如何引导用户开启?并获得用户的操作状态?_第2张图片

上述代码,this.$invoke('Modals'……)部分为自定义弹窗,即引用用户确定,去设置页,

requestSubscribeMessage 问题点

但是 在 openSetting的回调里,是没有 scope.subscribeMessage这一项的,下面是列出的scope 列表官方清单(文档地址):

scope 对应接口 描述
scope.userInfo wx.getUserInfo 用户信息
scope.userLocation wx.getLocation, wx.chooseLocation 地理位置
scope.userLocationBackground wx.startLocationUpdateBackground 后台定位
scope.address wx.chooseAddress 通讯地址
scope.invoiceTitle wx.chooseInvoiceTitle 发票抬头
scope.invoice wx.chooseInvoice 获取发票
scope.werun wx.getWeRunData 微信运动步数
scope.record wx.startRecord 录音功能
scope.writePhotosAlbum wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum 保存到相册
scope.camera camera 组件 摄像头
//提交订阅消息示例


export default class Sign extends wepy.page {
  config = {
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: '赢积分',
  };
  setClock(e) {
    let that = this;
    if (wx.requestSubscribeMessage) {
      wx.requestSubscribeMessage({
        tmplIds: [pushReservationTmplIds],
        success(res) {
          if (res[pushReservationTmplIds] === 'accept') {
            //发起请求……
          } else if (res[pushReservationTmplIds] === 'reject') {
            // 用户历史操作有设置了拒绝 or 关闭了订阅消息的主(总)开关,导致无法推送
            that.guideOpenSubscribeMessage();
          } else {
            wx.showToast({
              title: '授权订阅消息有误',
              icon: 'none'
            });
          }
        },
        fail(res) {

          // 20004:用户关闭了主开关 或在 消息通知 里 “拒绝接收”操作,无法进行订阅,引导开启
          if (res.errCode == 20004) {
            console.log(res, 'fail:用户关闭了主开关,无法进行订阅,引导开启---');
          }
        }
      });
    } else {
      wx.showToast({
        title: '请更新您微信版本,来获取订阅消息功能',
        icon: 'none'
      });
    }
  }
  guideOpenSubscribeMessage() {
    //引导用户,手动引导用户去设置页开启,
    this.$invoke('Modals', '__modalConfirm__', [
      '检测到您没有开启订阅消息的权限,是否去设置?',
      'openSetting',
      res => {
        console.log('openSetting的回调数据:', res);
        //但是这个回调数据里,并没有 「订阅消息」 相关 open/close 的状态返回

      },
      //用户点击了取消按钮
      () => {
        // console.log("取消了")
        this.$invoke('Toast', '__warning__', [
          `您已拒绝订阅消息授权,无法预约`
        ]);
      }
    ]);
}

问:小程序订阅消息用户拒绝后,如何引导用户开启?并获得用户的操作状态?_第3张图片
上图为 openSetting的回调数据,而网上说回调里不做任何处理,用户是否有手动开启,则让提示让他再手动点击一次业务按钮,如果有开启,则回到最初的逻辑,订阅消息成功,否则则又循环进入 openSetting设置页,俗称“死缠烂打授权法”,这当然不失为一种方法,但体验不是最好,

对于追求完美的我来说,不能接受,继续寻找更好的方案,把官方文档来回看,终于发现了新大陆,——wx.getSetting

属性 类型 说明 最低版本
authSetting AuthSetting 用户授权结果
subscriptionsSetting SubscriptionsSetting 用户订阅消息设置,接口参数withSubscriptions值为true时才会返回。 2.10.1

文档有有这么一个属性:subscriptionsSetting,感谢苍天,终于让我看到了订阅消息相关的东西,

//官方示例
wx.getSetting({
  withSubscriptions: true,
  success (res) {
    console.log(res.authSetting)
    // res.authSetting = {
    //   "scope.userInfo": true,
    //   "scope.userLocation": true
    // }
    console.log(res.subscriptionsSetting)
    // res.subscriptionsSetting = {
    //   mainSwitch: true, // 订阅消息总开关
    //   itemSettings: {   // 每一项开关
    //     SYS_MSG_TYPE_INTERACTIVE: 'accept', // 小游戏系统订阅消息
    //     SYS_MSG_TYPE_RANK: 'accept'
    //     zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: 'reject', // 普通一次性订阅消息
    //     ke_OZC_66gZxALLcsuI7ilCJSP2OJ2vWo2ooUPpkWrw: 'ban',
    //   }
    // }
  }
})

wx.getSetting的回调里,有一项 mainSwitch,还有一项withSubscriptions: true,最后回调里还能一项 zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: 'reject',到这里,但它也只是在getSetting方法里啊,跟 openSetting没有扯上任何关系,怎么办?

其实道理很简单,但人有时候就是这样,思维如果没有转换过来,你可以就会一直杠在那个死胡同里出不来,

openSetting回调里取不到状态,那么我们是否可以在它的回调里,再做一次 getSetting的调用里呢?,取getSetting回调里的状态来判断,刚才用户在设置页的行为操作,直接看示例吧:

//提交订阅消息示例

const pushReservationTmplIds = 'PVC_DBcvvdtffd1fO0vdS8YpSe0c7Br3QW54';

export default class Sign extends wepy.page {
  config = {
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: '赢积分',
  };
  submitClock() {
    fetchJson({
      type: 'POST',
      url: '/api/steps/clock',
      data: {
      },
      success: res => {
        wx.showToast({
          title: '预定成功',
          icon: 'success',
          duration: 2000
        });
      }
    });
  }
  setClock(e) {
    let that = this;
    if (wx.requestSubscribeMessage) {
      wx.requestSubscribeMessage({
        tmplIds: [pushReservationTmplIds],
        success(res) {
          if (res[pushReservationTmplIds] === 'accept') {
            that.submitClock();
          } else if (res[pushReservationTmplIds] === 'reject') {
            // 用户历史操作有设置了拒绝 or 关闭了订阅消息的主(总)开关,导致无法推送
            // console.log(res, '0 拒绝 or 关闭了订阅消息的主(总)开关---');
            that.guideOpenSubscribeMessage();
          } else {
            wx.showToast({
              title: '授权订阅消息有误',
              icon: 'none'
            });
          }
        },
        fail(res) {
          // 20004:用户关闭了主开关,无法进行订阅,引导开启
          if (res.errCode == 20004) {
            // console.log(res, 'fail:用户关闭了主开关,无法进行订阅,引导开启---');
            that.guideOpenSubscribeMessage();
          }
        }
      });
    } else {
      wx.showToast({
        title: '请更新您微信版本,来获取订阅消息功能',
        icon: 'none'
      });
    }
  }
  guidSubscribeMessageAuthAfter() {
    //引导用户 开启订阅消息 之后,「openSetting」 接口暂时不会返回,用户手动设置后的状态,所以采用「getSetting」接口重新进行查询
    wx.getSetting({
      withSubscriptions: true,
      success: res => {
        let {
          authSetting = {},
          subscriptionsSetting: { mainSwitch = false, itemSettings = {} } = {}
        } = res;

        if (
          (authSetting['scope.subscribeMessage'] || mainSwitch) &&
          itemSettings[pushReservationTmplIds] === 'accept'
        ) {
          this.submitClock();
          // console.log('用户手动开启同意了,订阅消息');
        } else {
          this.$invoke('Toast', '__warning__', [
            `您没有同意授权订阅消息,预约领取失败`
          ]);
        }
      }
    });
  }
  guideOpenSubscribeMessage() {
    //引导用户,手动引导用户去设置页开启,
    this.$invoke('Modals', '__modalConfirm__', [
      '检测到您没有开启订阅消息的权限,是否去设置?',
      'openSetting',
      //用户点击了确定按钮,进入设置页的回调
      res => {
        console.log('openSetting的回调数据:', res);
        this.guidSubscribeMessageAuthAfter();
      },
      //用户点击了取消按钮
      () => {
        // console.log("取消了")
        this.$invoke('Toast', '__warning__', [
          `您已拒绝订阅消息授权,无法预约领取`
        ]);
      }
    ]);
  }
}

结尾

到这里,wx.requestSubscribeMessage的问题,也就得到了解决,看到网上有贴子在喷requestSubscribeMessageAPI的设计,比如:wx.requestSubscribeMessage的接口参数结构设计反人性,实习生设计的吗?,其实我也想说这么庞大的一个生态体系,更新方案就考虑的这么不全面吗?还是说就是这么反人类? getSetting里给requestSubscribeMessage的相关状态,openSetting里又压根没有,然后又把它的引导开启逻辑UI也放在设置页里面,我就郁闷了,

今天的分享,为我个人的解决思路方案,如有不足之处,请指出,勿喷~谢谢!!

推荐阅读:

  • Chrome插件千千万 ,最适合开发者的却只有这几个
  • 谈谈 HTTPS
  • WebSocket 是时候展现你优秀的一面了
  • 互联网免费编程书籍清单
  • Js 函数式编程指南
  • JavaScript 秘密花园
  • 你不懂JavaScript
  • React Bits中文版
  • TypeScript Deep Dive 中文版
  • 十大经典排序算法
  • CSS权威指南(第四版)

领略前端技术,关注IT平头哥联盟,尽在Js中文网 www.javascriptc.com

作者:IT平头哥联盟

链接:https://susouth.com/

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

你可能感兴趣的:(小程序)