消息能力是小程序能力中的重要组成,以便实现服务的闭环和更优的体验。此前的小程序模板消息接口于2020年1月10日下线,2.10.0 版本开始,开发版和体验版小程序将禁止使用模板消息 fomrId。开发者可使用订阅消息功能。订阅消息特点:
订阅消息的使用主要以下几个步骤:
在微信公众平台手动配置获取模板 ID:
登录 https://mp.weixin.qq.com 获取模板,如果没有合适的模板,可以申请添加新模板,审核通过后可使用。
初始状态下我的模板中没有模板,需要点击添加按钮添加模板。这里需要说明以下,模板库中有两种类型的模板,一次性订阅和长期订阅,长期订阅只会在一些特定的类目下才有。我这里以一次性订阅为例,选择自己合适的模板,设置模板里面要显示的条目即可,确定后就跟我上面截图一样就会看到了。
这里需要说明的是:一次性订阅和长期订阅。官方社区说明
一次性订阅消息用于解决用户使用小程序后,后续服务环节的通知问题。用户自主订阅后,开发者可不限时间地下发一条对应的服务消息;每条消息可单独订阅或退订。
一次性订阅消息可满足小程序的大部分服务场景需求,但线下公共服务领域存在一次性订阅无法满足的场景,如航班延误,需根据航班实时动态来多次发送消息提醒。为便于服务,我们提供了长期性订阅消息,用户订阅一次后,开发者可长期下发多条消息。目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。
订阅消息的发送同时还需要用户同意接收,否则用户将不会收到消息。在小程序中需要调用下面API,调起客户端小程序订阅消息界面。注意仔细查看该API文档,有很多细节(坑)。先说一个,这个API只会在真机上才生效,模拟器不行,文章结尾再来说说其他的细节。
如下:
wx.requestSubscribeMessage({
// 相当于询问用户愿不愿意接收这个模板的订阅消息
tmplIds: ['eggfYknjtIhEUupiB3qhbfBt2dHtqe92ff3qgqui6dk'],
success(res) {
console.log('已授权接收订阅消息')
},
complete(res) {
console.log(res)
}
})
所以,简单来说,小程序中需要调用上面的API,并且用户需要同意接收,这样才能接收到发送过来的订阅消息。
我这边是在java服务端程序测试的。首先需要细看发送订阅消息的API。
POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN
参数:access_token,后台接口调用凭据,对应的API。
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
所以需要在发送前获取该token_access值。
post请求体中对应的参数,必须是json格式,我这里值传了必须的三项,说明如下,value里面的数据一定要注意按照文档中的格式,否则会包=报数据格式错误的!
这里面还有一个参数也是需要提前获取的,就是接收消息的用户openid,这个可以在登录时获取,对应API。
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
这里面有个js_code参数,这个参数可以在小程序端调用wx.login()时获取到。
到这基本上流程已经介绍清楚了,搞清楚相关参数即可。
首先声明,我下面的流程只是作为一次测试,感受下订阅消息的发送效果,实际项目中不要这么整啊,经理会打人的~
流程:
小程序:
wxml:
js:
Page({
onLoad: function () {
},
permission(){
wx.requestSubscribeMessage({
tmplIds: ['eggfYknjtIhEUupiB3qhbfBt2dHtqe92ff3qgqui6dk'],
success(res) {
console.log('已授权接收订阅消息')
},
complete(res) {
console.log(res)
}
})
},
send(){
wx.login({
success(res) {
if (res.code) {
console.log(res)
wx.request({
url: 'http://自己电脑ip:8090/test/send?code=' + res.code,
success(res) {
// console.log(res.data)
},
complete(res) {
// console.log(res)
}
})
}
}
})
}
})
服务端:
pom.xml
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.62version>
dependency>
<dependency>
<groupId>cn.gjinggroupId>
<artifactId>tools-httpclientartifactId>
<version>1.2.6version>
dependency>
controller:
@RestController
@RequestMapping("/test")
public class TestCtrl {
@RequestMapping("send")
public String getToken(@RequestParam("code") String code){
System.out.println("code:" + code);
String token = getToken();
String openid= getOpenId(code);
Map<String,Object> param = new HashMap<>();
param.put("touser",openid);
param.put("template_id","eggfYknjtIhEUupiB3qhbfBt2dHtqe92ff3qgqui6dk");
Map<String,Object> data = new HashMap<>();
data.put("thing1",new Value("上海市普陀区"));
data.put("thing4",new Value("空调清洗"));
data.put("phone_number8",new Value("17635688803"));
data.put("thing7",new Value("每周六天,8:00~18:00"));
data.put("date5",new Value("2019-10-25 12:23"));
param.put("data",data);
// 注意检查参数的格式,很容易出现问题
System.out.println("param:" + JSON.toJSONString(param));
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token;
Map result = HttpUtils.post(url, param);
System.out.println("result=" + result);
return "success";
}
private String getToken(){
String url = "https://api.weixin.qq.com/cgi-bin/token?appid=你的appid&secret=你的appsecret&grant_type=client_credential";
String result = HttpUtils.get(url);
Map<String,Object> map = JSON.parseObject(result);
String access_token = map.get("access_token").toString();
System.out.println("access_token:" + access_token);
return access_token;
}
private String getOpenId(String code){
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=你的appid" +
"&secret=你的appsecret" +
"&js_code="+code+"&grant_type=authorization_code";
String result = HttpUtils.get(url);
Map<String,Object> map = JSON.parseObject(result);
String openid = map.get("openid").toString();
System.out.println("openid:" + openid);
return openid;
}
}
HttpUtils:
package com.example.demo1.ctrl.util;
import cn.gjing.http.HttpClient;
import cn.gjing.http.HttpMethod;
import java.util.Map;
public class HttpUtils {
public static String get(String url, Map<String, Object> param) {
String result = HttpClient.builder(url, HttpMethod.GET, String.class)
.param(param)
.execute()
.get();
return result;
}
public static String get(String url) {
String result = HttpClient.builder(url, HttpMethod.GET, String.class)
.execute()
.get();
return result;
}
public static Map post(String url, Map<String, Object> param) {
Map result = HttpClient.builder(url, HttpMethod.POST, Map.class)
.body(param)
.execute()
.get();
return result;
}
}
启动服务器,在手机上打开小程序,先在设置中打开调试功能,否则小程序可能无法调用本地服务端接口。先点击权限按钮,允许接收订阅消息,在点击发送按钮,效果图:
补充:
一次性订阅消息用户允许一次后,只能接收一次消息,再次发送时会显示用户拒收。长期订阅消息则是可以接收多条。
result={errcode=43101, errmsg=user refuse to accept the msg hint: [NLYvMa06944924]}
如果你勾选了这个“保持以上选择”,那么这个弹框将再也不会出来了~~我这示例中当你再点一次权限按钮,还是能接收到一次消息的,只是弹框不显示了。