在微信小程序开发中,订阅消息是一种重要的用户触达方式。然而,开发者经常面临一个问题:如何准确地检测用户是否订阅了特定的模板消息?当用户在设置中手动关闭订阅权限时,如何在前端及时反映这一状态变化?
传统的做法是依赖本地存储来记录用户订阅状态,但这存在明显的缺陷:当用户在微信设置中手动关闭订阅权限时,应用无法感知这一变化,导致界面上显示的状态与实际状态不一致。
微信小程序提供了检查订阅消息状态的官方API,关键在于使用 withSubscriptions: true 参数:
uni.getSetting({
withSubscriptions: true, // 关键参数
success(res) {
console.log(res.subscriptionsSetting);
// 包含 mainSwitch 和 itemSettings 字段
}
});
返回的 subscriptionsSetting 对象包含以下重要字段:
withSubscriptions: true 参数调用 getSettingconst checkSubscriptionStatus = () => {
if (typeof uni.getSetting === 'function') {
uni.getSetting({
withSubscriptions: true,
success: (res) => {
if (res.subscriptionsSetting) {
// 检查主开关
const mainSwitch = res.subscriptionsSetting.mainSwitch;
// 检查特定模板状态
const itemSettings = res.subscriptionsSetting.itemSettings || {};
const templateStatus = itemSettings[TEMPLATE_ID];
// 根据状态更新本地存储和UI
// 将 templateStatus !== 'accept' 视为未授权(例如 'reject'、'ban' 或 undefined)
if (mainSwitch === false || templateStatus !== 'accept') {
// 更新为未订阅状态(将状态保存在 patientReminders.notificationsEnabled)
notificationsEnabled.value = false;
try {
const reminders = uni.getStorageSync('patientReminders') || {
bloodPressureReminder: { enabled: false, times: [] },
bloodSugarReminder: { enabled: false, times: [] },
heartRateReminder: { enabled: false, times: [] },
medicationReminder: { enabled: false, times: [] },
notificationsEnabled: false,
subscriptionAvailable: true
};
reminders.notificationsEnabled = false;
uni.setStorageSync('patientReminders', reminders);
} catch (e) {}
} else if (mainSwitch === true && templateStatus === 'accept') {
// 更新为已订阅状态(保存到 patientReminders)
notificationsEnabled.value = true;
try {
const reminders = uni.getStorageSync('patientReminders') || {
bloodPressureReminder: { enabled: false, times: [] },
bloodSugarReminder: { enabled: false, times: [] },
heartRateReminder: { enabled: false, times: [] },
medicationReminder: { enabled: false, times: [] },
notificationsEnabled: false,
subscriptionAvailable: true
};
reminders.notificationsEnabled = true;
uni.setStorageSync('patientReminders', reminders);
} catch (e) {}
}
}
},
fail: (err) => {
console.error('Failed to get user settings:', err);
}
});
}
};
withSubscriptions 参数通过使用 uni.getSetting 配合 withSubscriptions: true 参数,我们可以准确地检测用户对订阅消息的设置,实现前端独立的状态管理,无需依赖后端服务。这种方法能够实时反映用户在微信设置中的操作,提升用户体验和应用的准确性。
在本仓库的 src/pages/patient/health/reminder.vue 中,我们把原来分散的订阅检查逻辑合并为一个统一的函数 checkSubscriptionStatus,并为其新增了一个 passive 参数,用来区分“被动检查”和“主动检查”的行为:
checkSubscriptionStatus(passive = false)
mainSwitch === false 或模板状态非 accept(例如 reject、ban 或未返回模板状态 undefined),将把 notificationsEnabled 设为 false、显示权限引导(showPermissionGuide = true,当主开关关闭时),并保存本地状态。mainSwitch === true 且模板状态为 accept,将把 notificationsEnabled 设为 true、关闭权限引导,并保存本地状态。onShow 时自动检测)。在此模式下:mainSwitch === false 或模板状态非 accept(例如 reject、ban 或未返回模板状态 undefined)时,才会把 notificationsEnabled 设为 false 并保存本地状态;不会在检测到 accept 时把本地开关置为 true,也不会显示权限引导(遵循“被动不打扰用户”的原则)。修改要点:
onShow 中原本重复的 uni.getSetting({...}) 代码替换为 checkSubscriptionStatus(true),实现代码复用和行为统一(onShow 执行被动检查)。openSettings 中在用户从系统设置返回时仍然调用 checkSubscriptionStatus()(默认主动模式),以便在用户在系统设置中开启权限后,将本地状态同步为已开启并关闭权限引导。示例调用:
// 页面返回前台时(被动检查)
checkSubscriptionStatus(true)
// 用户在设置页返回时(主动检查)
checkSubscriptionStatus()
为什么这样做:
已在代码中完成该改动,且相关逻辑已保存到 reminder.vue 中的注释与实现里。