在微信小程序开发中,订阅消息是一种重要的用户触达方式。然而,开发者经常面临一个问题:如何准确地检测用户是否订阅了特定的模板消息?当用户在设置中手动关闭订阅权限时,如何在前端及时反映这一状态变化?
传统的做法是依赖本地存储来记录用户订阅状态,但这存在明显的缺陷:当用户在微信设置中手动关闭订阅权限时,应用无法感知这一变化,导致界面上显示的状态与实际状态不一致。
微信小程序提供了检查订阅消息状态的官方API,关键在于使用 withSubscriptions: true 参数:
uni.getSetting({
withSubscriptions: true, // 关键参数
success(res) {
console.log(res.subscriptionsSetting);
// 包含 mainSwitch 和 itemSettings 字段
}
});
返回的 subscriptionsSetting 对象包含以下重要字段:
我们通过 uni.getSetting({ withSubscriptions: true }) 获取微信本地状态,并与服务器返回的 overview 数据进行对比同步。
根据微信本地获取的状态,分为以下三种情况进行处理:
notificationsEnabled。如果是开启的(true),先将其设定为关闭(false),然后积极尝试请求订阅(调用 requestSubscribeMessage),因为这可能是用户误操作关闭的。subscriptionAvailable。如果不为 "NONE",则修正为 "NONE"。subscriptionAvailable:"NONE":说明权限已消耗或未获得。只有在服务器 notificationsEnabled 为 true 时,才发起订阅请求。成功后根据微信侧 getSetting 的真实结果设定为 "ONCE" 或 "MULTI"。"ONCE":保持现状,无需重复请求。"MULTI":状态不一致(服务器认为是长期但微信本地不是),先将服务器设定为 "NONE"。只有在服务器 notificationsEnabled 为 true 时,才重新发起订阅请求。成功后根据微信侧 getSetting 的真实结果设定为 "ONCE" 或 "MULTI"。subscriptionAvailable 为 "MULTI"。如果不是,则进行更正。mainSwitch: false 且服务器为 true 时,才会将服务器状态改为 false。requestSubscription)时:
errCode: 20004),程序会自动将 notificationsEnabled 设为 false 并同步至服务器,同时弹出权限引导。notificationsEnabled 为 true,但在自动检查过程中发现微信权限已关闭或订阅请求失败,程序也会弹出权限引导,帮助用户恢复预期的通知状态。项目中实现了统一的 checkSubscriptionStatus 函数来执行上述逻辑:
const checkSubscriptionStatus = async (passive = false) => {
const info = await fetchSubscriptionSettings()
const { mainSwitch, templateStatus } = info
let needsSave = false
let shouldRequest = false
const wasEnabledBeforeCheck = notificationsEnabled.value
if (mainSwitch === false) {
if (notificationsEnabled.value === true) {
notificationsEnabled.value = false
needsSave = true
shouldRequest = true // 积极请求
}
if (subscriptionAvailable.value !== 'NONE') {
subscriptionAvailable.value = 'NONE'
needsSave = true
}
} else if (mainSwitch === true && templateStatus !== 'accept') {
if (subscriptionAvailable.value === 'NONE' && notificationsEnabled.value === true) {
shouldRequest = true
} else if (subscriptionAvailable.value === 'MULTI') {
subscriptionAvailable.value = 'NONE'
needsSave = true
if (notificationsEnabled.value === true) {
shouldRequest = true
}
}
} else if (mainSwitch === true && templateStatus === 'accept') {
if (subscriptionAvailable.value !== 'MULTI') {
subscriptionAvailable.value = 'MULTI'
needsSave = true
}
}
if (needsSave) {
await saveReminders()
}
if (shouldRequest) {
await requestSubscription(false, wasEnabledBeforeCheck)
}
}
onShow(被动检查)和用户手动操作(主动检查)时触发。requestSubscribeMessage 在某些平台上必须由用户点击触发。在 onShow 中自动触发可能会受到平台限制或弹出频率限制。showPermissionGuide 弹窗引导用户前往系统设置开启。withSubscriptions 参数通过使用 uni.getSetting 配合 withSubscriptions: true 参数,我们可以准确地检测用户对订阅消息的设置,实现前端独立的状态管理,无需依赖后端服务。这种方法能够实时反映用户在微信设置中的操作,提升用户体验和应用的准确性。
修改要点:
onShow 中原本重复的 uni.getSetting({...}) 代码替换为 checkSubscriptionStatus(true),实现代码复用和行为统一(onShow 执行被动检查)。openSettings 中在用户从系统设置返回时仍然调用 checkSubscriptionStatus()(默认主动模式),以便在用户在系统设置中开启权限后,将本地状态同步为已开启并关闭权限引导。示例调用:
// 页面返回前台时(被动检查)
checkSubscriptionStatus(true)
// 用户在设置页返回时(主动检查)
checkSubscriptionStatus()
为什么这样做:
已在代码中完成该改动,且相关逻辑已保存到 reminder.vue 中的注释与实现里。