消息订阅的实现
2020-10-12 本文已影响0人
洗耳恭听_kai
引言:去年五月份的时候总结过微信小程序消息推送的功能,然后最近重新做这个的时候发现没有消息推送这个东西了,后来知道今年微信官方把消息推送改到了消息订阅里去了,其实原理都差不多,都是在小程序端获取用户同意后,在后台传相关的模板id信息,再通过url发送到对应的用户
![](https://img.haomeiwen.com/i8562370/e29180bf5285081c.png)
一、效果
![](https://img.haomeiwen.com/i8562370/b53daf9a9b9c3eeb.png)
![](https://img.haomeiwen.com/i8562370/8a42f2ae8f8f2ca7.png)
二、获取模板id
这里和前面的消息推送是一样的,只不过改成了在“消息订阅”里添加了。如果需要自己定义一些消息模板,可以点击跳转到最后一页,然后在下面有几个小字,点进去可以自己配置一些模式。
三、实现
小程序端
支付成功后:
if(res.data.code == 1000){
wx.showModal({
title: '提示',
content: '支付成功',
success: function (res) {
//消息订阅
var touser = uid
var tmplId = 'G8f87i7GxuuKjEG7TkOTWJ69zPMJtxxxx'
var page = 'pages/index/index'
var content = _this.data.orderid
app.toggleSubscribe(touser,tmplId,page,content)
app.openPage('member/mine_order?type=2')
}
})
}
//消息订阅
toggleSubscribe: function (touser,tmplId,page,content) {
var that = this;
wx.getSetting({
withSubscriptions: true,
success(res) {
console.log(res.subscriptionsSetting) //这里可以看到每一项的授权状态,当用户没授权时,即使withSubscriptions开启了true,也是不会输出订阅状态的,所以直接让弹出授权框就得了
if (wx.requestSubscribeMessage) {
wx.requestSubscribeMessage({
tmplIds: [tmplId], //数组(多条订阅)
success: function (res) { //成功
console.log('订阅授权成功后的打印:')
console.log(res);
that.reqPost('Buy','sendSubscribeMessage',{
touser: touser,
template_id: tmplId,
page : page,
content: content
},function(res){
console.log('订阅消息请求成功')
})
},
fail: function (res) {
console.log(res);
}
})
} else {
wx.showToast({
title: '请更新您微信版本,来获取订阅消息功能',
icon: 'none'
});
}
}
});
},
注:传递的参数tmplIds需要是数组的类型,不然会报错,一个模板id也要放到数组里
后端
/*
* 订阅消息
*/
/**
* Notes:获取accessToken
* @return mixed
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function getAccessToken($touser)
{
//当前时间戳
$now_time = strtotime(date('Y-m-d H:i:s',time())) ;
//失效时间
$timeout = 7200 ;
//判断access_token是否过期
$before_time = $now_time - $timeout ;
//判断是否为首次
$is_e = Db::name('takeout_access_token')->where('uid',$touser)->find();
if(empty($is_e)){
//获取新的access_token
$appid = 'wx5cf756xxxxxxx';
$secret = "d32237266522xxxxxxxx";
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret;
$res = json_decode(file_get_contents($url),true);
$access_token = $res['access_token'] ;
//保存到数据库
$insert = ['access_token' => $access_token ,'update_time' => $now_time,'uid'=>$touser] ;
Db::name('takeout_access_token')->insert($insert);
return $access_token;
}
//未查找到就为过期
$access_token = Db::name('takeout_access_token')->where('uid',$touser)
->where('update_time' ,'>',$before_time)
->value('access_token');
//如果过期
if( !$access_token ) {
//获取新的access_token
$appid = 'wx5cf756xxxxx';
$secret = "d322372665220765xxxx";
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret;
$res = json_decode(file_get_contents($url),true);
$access_token = $res['access_token'] ;
//更新数据库
$update = ['access_token' => $access_token ,'update_time' => $now_time] ;
Db::name('takeout_access_token')->where('uid',$touser)->update($update) ;
}
return $access_token ;
}
//发送订阅消息
public function sendSubscribeMessage()
{
$touser = $_POST['touser'];
$template_id = $_POST['template_id'];
$page = isset($_POST['page'])?$_POST['page']:'';
$content = $_POST['content'];
//access_token
$access_token = self::getAccessToken($touser) ;
//查找openid
$openid = Db::name('users')->where('id',$touser)->find()['openid'];
//请求url
$url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $access_token ;
//发送内容
$data = [] ;
//接收者(用户)的 openid
$data['touser'] = $openid ;
//所需下发的订阅模板id
$data['template_id'] = $template_id ;
//点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
if(!empty($page)){
$data['page'] = $page ;
}
//模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
// $data['data'] = [
// "phrase10"=>[
// 'value' => '123456'
// ],
// "name8"=>[
// 'value' => '123456'
// ],
// ];
//获取到订单信息
$orderid = $content;
$orderinfo = Db::name('order')->where('id',$orderid)->find();
$data['data'] = [
"character_string3"=>[
'value' => $orderinfo['order_no']
],
"amount1"=>[
'value' => $orderinfo['money']
],
"time2"=>[
'value' => empty(date('Y-m-d H:i:s',$orderinfo['pay_time']))?date('Y-m-d H:i:s',time()):date('Y-m-d H:i:s',$orderinfo['pay_time'])
]
];
var_dump($data);
//跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
$data['miniprogram_state'] = 'formal' ;
return self::curlPost($url,json_encode($data)) ;
}
//发送post请求
protected function curlPost($url,$data)
{
$ch = curl_init();
$params[CURLOPT_URL] = $url; //请求url地址
$params[CURLOPT_HEADER] = FALSE; //是否返回响应头信息
$params[CURLOPT_SSL_VERIFYPEER] = false;
$params[CURLOPT_SSL_VERIFYHOST] = false;
$params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
$params[CURLOPT_POST] = true;
$params[CURLOPT_POSTFIELDS] = $data;
curl_setopt_array($ch, $params); //传入curl参数
$content = curl_exec($ch); //执行
curl_close($ch); //关闭连接
return $content;
}
注意:需要注意的几点,第一个是accessToken是会过期的,所以需要每次判断一下。第二个是需要传用户的openid,这样才能知道推送到的是哪个微信用户。第二个是消息内容中的key需要和模板消息里的key一致,否则发送不成功
特别说明:支付的消息订阅是可以在form中直接成功,但其他的需要有bintap绑定事件才能订阅成功,否则会报错:errMsg: "requestSubscribeMessage:fail can only be invoked by user TAP gesture
我的做法是:
tosend:function(){
var that = this
wx.showModal({
title: '申请成功',
content: '需要平台审核才能登陆,登陆账户为当前申请的手机号,初始密码为123456',
confirmText:'确定',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
that.toggleSubscribe() //在这里进行消息订阅
} else if (res.cancel) {
console.log('用户点击取消')
return
}
}
})
},
1、在需要的地方调用这个就行了。
2、其实有很多情况是小程序这边给用户跳出订阅的弹窗,授权订阅后,后台需要做一些业务上的审核,然后再主动去发送订阅消息到对应的用户,比如审核结果类的业务。所以,我的意思是大致的逻辑是:小程序端给授权,微信那边应该是根据openid来对应的判断用户是否有授权此订阅,然后我们后台就可以进行消息的推送了。