先给个明确的结论:uni-app小程序端,不可能实现“自动下发”的全局消息订阅通知。这是微信平台的硬性规则,不是技术能力没跟上,而是平台逻辑本身就不允许任何非用户主动触发的订阅授权行为。所谓“自动下发”,在技术上既不可行,也直接踩了微信审核的红线。
真正可行的路径其实很清楚:前端只负责引导用户点击授权 + 后端按需调用微信接口推送。下面把几个关键实操点拆开来讲清楚。
uni.requestSubscribeMessage 必须由 button 点击触发
这不是什么兼容性问题,是微信划定的硬性限制。以下写法全部无效:
- 把
uni.requestSubscribeMessage放在onLoad、onShow或setTimeout里 → 直接报错errCode: -1, errMsg: "requestSubscribeMessage:fail api scope is not declared" - 用
或包裹调用 → 微信不识别,静默失败 没加open-type="subscribeMessage"属性(uni-app 3.0+ 要求)→ 不弹授权框
正确写法只有这一种:
JS 中调用时,tmplIds 每次最好只传 1 个模板 ID。用户如果点“拒绝”,整批模板都会失效,后续再无触达机会。
uni.getSetting 检查权限必须带 withSubscriptions: true
很多开发者调了 uni.getSetting() 却拿不到订阅状态,问题就出在这个参数被遗漏了。
withSubscriptions: false或不传 → 返回结果里根本没有subscriptionsSetting字段withSubscriptions: true→ 才能拿到res.subscriptionsSetting.mainSwitch和res.subscriptionsSetting.itemSettingsitemSettings[templateId]是undefined?说明该模板从未被请求过,不是“拒绝”,而是“未触达”。
别只盯着 mainSwitch,它只是总开关。真正决定能否发消息的是具体模板的 itemSettings[templateId] 值,可能为 'accept'、'reject' 或 'ban'。
后端发送消息必须用缓存的 access_token
前端拿到 'accept' 后,要立刻把 openid 和模板 ID 传给后端;后端不能每次发都重新拉 access_token。
access_token有效期仅 2 小时,且每 2 小时最多获取 1 次,日限 2000 次 → 不缓存必超限- 必须存在服务端内存或 Redis 中,并带过期时间自动刷新
- 调用地址是:
https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=xxx,不是旧的模板消息地址 data字段必须严格匹配模板定义的字段名(如thing1),结构必须是{ value: 'xxx' },不能直接传字符串
用户点了“拒绝”之后怎么补救
如果后端调用微信接口返回 {"errcode":43101,"errmsg":"user refuse to accept the msg"},说明用户当时点了“拒绝”,且没再手动打开设置。
- 前端应提示“请前往设置开启”,并立即调用:
uni.openSetting({ withSubscriptions: true }) - 注意:这个 API 也必须由用户点击触发,不能自动调;否则会失败
- 不要反复弹窗引导——微信对诱导授权非常敏感,可能被拒审
一次性模板的本质决定了它没法“全局自动下发”。所谓“全局”,只能靠业务侧在关键节点(如下单成功页、支付完成页)精准嵌入授权按钮,而不是幻想一个后台定时任务能推到用户手机上。
