微信一次性订阅消息

一次性订阅消息官方文档:消息管理>发送一次性订阅消息

开发者可以通过一次性订阅消息授权让微信用户授权第三方移动应用接入说明)或公众号,获得发送一次订阅消息给到授权微信用户的机会。授权微信用户可以不需要关注公众号。微信用户每授权一次,开发者可获得一次下发消息的权限。对于已关注公众号的,消息将下发到公众号会话;未关注公众号的,将下发到服务通知

本篇文章主要讨论公众号

1、确认是否有权限

已认证的公众号即有权限,可登陆公众平台在接口权限列表处查看(如下图)。目前测试号还无法测试一次性订阅消息

一次性订阅消息-查看模板ID

2、配置相关的参数

  • 查看AppId以及AppSecret (发送一次性订阅消息需要ACCESS_TOKEN、获取ACCESS_TOKEN需要使用到)
  • 配置回调域名

image.png

设置授权域名-1

设置授权域名-2

3、授权发送一次性订阅消息

具体的参数看文档这里就不详细介绍了。

public static String getAuthorizeURL(String appId, String scene, String template_id,String redirectUri, String reserved) throws UnsupportedEncodingException {
        StringBuffer sbf = new StringBuffer();
        sbf.append(authorize_uri).append("&appid=").append(appId)
        .append("&scene=").append(scene)
        .append("&template_id=").append(template_id)
        .append("&redirect_uri=").append(URLEncoder.encode(redirectUri, Charsets.UTF_8.name()).replace("+", "%20"));
        if (StrKit.notBlank(reserved)) {
            sbf.append("&reserved=").append(reserved);
        }
        sbf.append("#wechat_redirect");

        return sbf.toString();
    }

用户同意或取消授权后会返回相关信息
如果用户点击同意或取消授权,页面将跳转至:

redirect_url/?openid=OPENID&template_id=TEMPLATE_ID&action=ACTION&scene=SCENE

4、通过API推送订阅模板消息给到授权微信用户

http请求方式: post
https://api.weixin.qq.com/cgi-bin/message/template/subscribe?access_token=ACCESS_TOKEN

{
  "touser": "OPENID",
  "template_id": "TEMPLATE_ID",
  "url": "URL",
  "scene": "SCENE",
  "title": "TITLE",
  "data": {
    "content": {
      "value": "VALUE",
      "color": "COLOR"
    }
  }
}

具体封装代码如下:

/**
     * 发送一次性订阅消息
     * 
     * @param jsonStr
     *            json字符串
     * @return ApiResult 
     * 
     */
    public static ApiResult subscribe(String jsonStr) {
        String jsonResult = HttpUtils.post(subscribe + AccessTokenApi.getAccessTokenStr(), jsonStr);
        return new ApiResult(jsonResult);
    }

    public static ApiResult subscribe(SubscribeInfo subscribeInfo) {
        return new ApiResult(JsonKit.toJson(subscribeInfo));
    }

    public static ApiResult subscribe(String openId, String templateId, String url, int scene, String title,
            String value, String color) {
        SubscribeInfo subscribeInfo = new SubscribeInfo.Builder()
                .setTouser(openId).setTemplate_id(templateId).setUrl(url)
                .setScene(String.valueOf(scene)).setTitle(title)
                .setData(new Data.Builder()
                        .setContent(new Content.Builder()
                                .setColor(color).setValue(value)
                                .create())
                        .create())
                .create();
        System.out.println(JsonUtils.toJson(subscribeInfo));                
        return subscribe(JsonUtils.toJson(subscribeInfo));
    }

Builder模式构建请求参数的json对象

class SubscribeInfo {
    private String touser;
    private String template_id;
    private String url;
    private String scene;
    private String title;
    private Data data;

    public static class Builder{
        private String touser;
        private String template_id;
        private String url;
        private String scene;
        private String title;
        private Data data;

        public Builder setTouser(String touser) {
            this.touser = touser;
            return this;
        }
        public Builder setTemplate_id(String template_id) {
            this.template_id = template_id;
            return this;
        }
        public Builder setUrl(String url) {
            this.url = url;
            return this;
        }
        public Builder setScene(String scene) {
            this.scene = scene;
            return this;
        }
        public Builder setTitle(String title) {
            this.title = title;
            return this;
        }
        public Builder setData(Data data) {
            this.data = data;
            return this;
        }
        public SubscribeInfo create(){    
            return new SubscribeInfo(this);    
        }
    }


    private SubscribeInfo(Builder builder) {
        if (StrKit.isBlank(builder.touser)) {
            throw new IllegalStateException("touser is null");
        }
        if (StrKit.isBlank(builder.template_id)) {
            throw new IllegalStateException("template_id is null");
        }
        if (StrKit.isBlank(builder.url)) {
            throw new IllegalStateException("url is null");
        }
        if (StrKit.isBlank(builder.scene)) {
            throw new IllegalStateException("scene is null");
        }
        if (StrKit.isBlank(builder.title)) {
            throw new IllegalStateException("title is null");
        }
        if (!StrKit.notNull(builder.data)) {
            throw new IllegalStateException("data is null");
        }

        this.touser = builder.touser;
        this.template_id = builder.template_id;
        this.url = builder.url;
        this.scene = builder.scene;
        this.title = builder.title;
        this.data = builder.data;
    }

    public String getTouser() {
        return touser;
    }

    public String getTemplate_id() {
        return template_id;
    }

    public String getUrl() {
        return url;
    }

    public String getScene() {
        return scene;
    }

    public String getTitle() {
        return title;
    }

    public Data getData() {
        return data;
    }
}

class Data {
    private Content content;

    public static class Builder {
        private Content content;

        public Builder setContent(Content content) {
            this.content = content;
            return this;
        }
        public Data create(){    
           return new Data(this);    
        }    
    }

    private Data(Builder builder) {
        if (!StrKit.notNull(builder.content)) {
            throw new IllegalStateException("content is null");
        }
        this.content = builder.content;
    }

    public Content getContent() {
        return content;
    }


}

class Content {
    private String value;
    private String color;

    public static class  Builder{
        private String value;
        private String color;

        public Builder setValue(String value) {
            this.value = value;
            return this;
        }
        public Builder setColor(String color) {
            this.color = color;
            return this;
        }

        public Content create(){
            return new Content(this);
        }

    }

    private Content(Builder builder) {
        if (StrKit.isBlank(builder.value)) {
            throw new IllegalStateException("value is null");
        }
        if (StrKit.isBlank(builder.color)) {
            throw new IllegalStateException("color is null");
        }
        this.value = builder.value;
        this.color = builder.color;
    }

    public String getValue() {
        return value;
    }

    public String getColor() {
        return color;
    }
}

5、遗留问题

1、授权后页面跳转无效redirect_url
2、发送一次性订阅消息提示没有权限(认证的服务号)

{"errcode":48001,"errmsg":"api unauthorized hint: [uAi6Za0855sz10!]"}

猜测:应该是官方接口存在问题

推荐阅读
10分钟搭建属于自己的ngork服务器,实现内网穿透
极速开发微信公众号
IJPay让支付触手可及
微信、支付宝App支付

微信小程序中实现长期发送一次性订阅消息的功能,虽然受限于其设计机制,但仍可通过一些策略优化用户体验并满足业务需求。以下是一些可行的方法: 1. **用户多次主动触发订阅**:由于每条一次性订阅消息仅支持推送一次,因此需要用户每次接收新消息前重新点击订阅弹窗。可以通过设计合理的交互流程,例如在特定操作后提示用户再次订阅,以确保服务端能够继续推送消息[^1]。 2. **结合后台定时任务与用户行为分析**:通过分析用户的活跃度和使用习惯,在合适的时间点向用户发送订阅请求。这样可以提高用户再次订阅的可能性,并减少对用户的打扰。 3. **利用模板消息管理接口**:按照官方文档指导,首先获取模板ID,然后从小程序端获取必要的参数如登录凭证(code),接着后端调用接口下发订阅消息。这一过程包括获取OPENID、ACCESS_TOKEN等步骤,是成功发送订阅消息的基础[^2]。 4. **提供有价值的内容激励用户订阅**:为了鼓励用户持续订阅,应确保推送的消息内容具有较高的价值或相关性,比如重要的通知、个性化的推荐或是限时优惠信息等。 5. **教育用户关于订阅的重要性**:通过简短明了的说明或者引导页面告知用户订阅的好处以及如何正确地进行订阅操作,帮助他们理解为何需要重复这个动作。 6. **优化订阅体验**:简化订阅流程,尽可能降低用户操作成本;同时也要注意不要过于频繁地请求权限,以免引起反感。 7. **考虑采用其他通信渠道作为补充**:如果条件允许的话,还可以探索邮件、短信或者其他即时通讯工具来辅助传递关键信息给用户,从而减轻单纯依赖小程序订阅消息的压力。 综上所述,尽管微信小程序的一次性订阅消息存在局限性,但通过上述方法可以在一定程度上实现较为稳定的长期消息推送效果。此外,对于有更高要求的应用场景,可能还需要考虑申请成为企业账号以获得更多的功能支持,或者寻找官方提供的更高级别的解决方案。 ```javascript // 示例代码 - 获取登录凭证(code) wx.login({ success: res => { if (res.code) { // 发送 res.code 到后台换取 openId, sessionKey, unionId console.log('Login Code:', res.code); } else { console.error('登录失败!' + res.errMsg); } } }); ``` ```http POST https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET // 下发订阅消息示例请求体 { "touser": "OPENID", "template_id": "TEMPLATE_ID", "page": "index", "form_id": "FORMID", "data": { "keyword1": {"value": "VALUE1"}, "keyword2": {"value": "VALUE2"} }, "emphasis_keyword": "KEYWORD" } ``` 请根据实际开发情况调整以上代码片段中的参数和逻辑。
评论 20
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值