这是一篇我鸽了很久的文章,从最初的 5 月 5 日开写,一直拖到近日才算完成。虽然主观原因是人懒,但客观原因不还是有嘛,这重新备案很费时间的啊喂~

言归正传,写这篇文章主要是在使用小程序发送订阅消息时却是踩了不少坑,按照原有的系统设计,是打算将其按照一个常用的消息通知渠道使用的。但是事实上,小程序的消息通知在次数上存在限制,一次授权、一次发送。自然无法实现持久化通知。后来的解决方案是在每个页面作权限校验,诱导(强制)用户勾选保持选择,不再询问巴拉巴拉,说人话就是你不给我权限我这边就疯狂跳转弹申请。

通过微信的 Api 我们可以获取到以上这些信息,当发现了不满足条件的时候就各种弹窗恶心用户就好了(终于活成了自己讨厌的样子淦)。以上操作在理想情况下就是:如果我们亲爱的用户勾选了保持选择,那么对用户来说之后的权限确认过程是无感的,进而在服务端发送消息时就不会出现由于权限次数不足而失败的情况了。

一、基础知识

订阅消息

消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验。

  • 订阅消息推送位置:服务通知
  • 订阅消息下发条件:用户自主订阅
  • 订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面

订阅消息有两种类型:一次性订阅消息长期订阅消息 ,长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,一般用户无法申请到。本文着重于一次性订阅,按照官网文档中的定义:

一次性订阅消息用于解决用户使用小程序后,后续服务环节的通知问题。用户自主订阅后,开发者可不限时间地下发一条对应的服务消息;每条消息可单独订阅或退订。

服务端通过调用 subscribeMessage.send 接口发送消息,对于服务端来说,也只能做到调用 Api ,然后接收到返回值。客户端通过 requestSubscribeMessage 调出权限申请,通过 getSetting 进行权限确认。

二、逻辑实现

需要实现的效果是这样的,把只有一次性订阅消息当成持久的消息通知渠道来使用。

这里说下小程序的额外设定,小程序拥有登录和自动登录能力。我将第一次授权放到了等候完成之后的回调里进行,将消息通知的权限检查放到了自动登录的完成回调中。

大概是这样吧
大概是这样吧

三、代码实现

订阅消息 subscribeMessage 调用
/**
* @param {string} tmplIds 模板 id
* @param {Function} done 成功回调
*/
subscribeMessage: function (tmplIds, done = null) {
const that = this;
wx.requestSubscribeMessage({
tmplIds: tmplIds,
success(res) {
tmplIds.forEach(item => {
if (res[item] !== 'accept') {
console.info('消息通知没有订阅');
}
})
if (done) done(res);
},
fail(res) {
// 20004: 用户关闭了主开关,无法进行订阅,引导开启
if (res.errCode == 20004) {
that.openSettingPage(() => {
if (done) done(false);
});
} else {
console.error('申请订阅消息权限失败', res.errMsg);
if (done) done(false);
}
}
})
}
校验订阅信息(只在通过自动登录方式进入的才调用)
checkSubscribeMessage: function () {
const that = this;
wx.getSetting({
withSubscriptions: true,
success: res => {
if (!!res.subscriptionsSetting.mainSwitch) {
// itemSettings 只在勾选了总是选择时返回
// 如果此处没有结果,就再次申请订阅消息,如果勾选了
if (!!res.subscriptionsSetting.itemSettings) {
// 此处处理勾选了总是选择的
// 直接跳到设置里(因为订阅消息的弹窗已经弹不出来了)
for (const key of that.globalData.subscribeTmplIds) {
if (res.subscriptionsSetting.itemSettings[key] !== 'accept' &&
res.subscriptionsSetting.itemSettings[key] !== undefined) {
that.openSettingPage('您有一条或多条订阅消息勾选了禁止接收,建议您重新勾选,是否确认?');
break;
}
}

// 至少一条未勾选总是选择,弹窗权限窗口
if (!that.globalData.subscribeTmplIds.every(item => {
return res.subscriptionsSetting.itemSettings[item] !== undefined
})) {
wx.showModal({
title: '订阅消息',
content: '您有消息尚未勾选保持以上选择,建议您勾选,是否确认?',
success: (res) => {
if (res.confirm) {
that.subscribeMessage(that.globalData.subscribeTmplIds);
}
}
})
}
} else {
// 此处是尚未勾选总是选择
wx.showModal({
title: '订阅消息',
content: '为了确保您能接收到审核信息,建议您勾选总是保持以上选择,是否确认?',
success: (res) => {
if (res.confirm) {
that.subscribeMessage(that.globalData.subscribeTmplIds);
}
}
})
}
} else {
// 此处是订阅消息总开关压根没开,直接跳转到设置页
that.openSettingPage();
}
}
})
},
跳转到设置页面
/**
* @param {string} str 消息通知
* @param {Function} done 回调函数
*/
openSettingPage: function (str = '检测到您未开启订阅消息开关,是否开启?', done) {
const that = this;
wx.showModal({
content: str,
success: (res) => {
if (res.confirm) {
wx.openSetting({
success(res) {
console.log(res.authSetting)
}
})
} else {
console.error('订阅消息失败');
wx.showToast({
title: '您拒绝开启通知权限,将无法收取到相关信息',
icon: 'none',
complete: () => {
if (done) done();
}
});
}
}
})
},

四、额外内容

这部分与主旨无关,不过有趣。

setGlobaUrl: function () {
let url, env;
switch (wx.getAccountInfoSync().miniProgram.envVersion) {
case 'develop': // 开发版
env = 'develop';
url = this.globalData.hostUrlList.develop;
break;
case 'trial': // 体验版
env = 'trial';
url = this.globalData.hostUrlList.trial;
break;
case 'release': // 正式版
env = 'release';
url = this.globalData.hostUrlList.release;
break;
default:
env = 'release';
url = this.globalData.hostUrlList.release;
}
wx.setEnableDebug({
enableDebug: env !== 'release',
fail: () => {
// 开发工具不提供此 Api
}
})
this.globalData.hostUrl = url;
this.globalData.env = env;
},
autoUpdate: function () {
// 获取小程序更新机制兼容
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager();
//1. 检查小程序是否有新版本发布
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
if (res.hasUpdate) {
//2. 小程序有新版本,则静默下载新版本,做好更新准备
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否马上重启小程序?',
success: function (res) {
if (res.confirm) {
//3. 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function () {
// 新的版本下载失败
wx.showModal({
title: '更新提示',
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开。',
})
})
}
})
} else {
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
},

评论