微信小程序生态13-微信公众号自定义菜单、个性化菜单配置

这篇具有很好参考价值的文章主要介绍了微信小程序生态13-微信公众号自定义菜单、个性化菜单配置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章导航

微信小程序生态1-初识小程序
微信小程序生态2-创建一个微信小程序
微信小程序生态3-微信小程序登录流程设计
微信小程序生态4-扫普通二维码进入小程序、打开短链接进入小程序
微信小程序生态5-微信公众号扫码登录PC端网页
微信小程序生态6-微信公众号授权登录(适用于H5小程序)
微信小程序生态7-微信公众号设置IP白名单
微信小程序生态8-基于weixin-java-mp实现微信公众号被动回复消息
微信小程序生态9-微信开放平台unionId机制介绍
微信小程序生态10-微信公众号token验证失败
微信小程序生态11-一个二维码同时支持微信、钉钉、支付宝扫码打开小程序
微信小程序生态12-微信小程序开发设置中服务器域名和业务域名
微信小程序生态13-微信公众号自定义菜单、个性化菜单配置
微信小程序生态14-下线已发布的小程序
微信小程序生态15- 批量提交微信小程序审核的一种方式

微信公众号分为订阅号和服务号两种,虽然二者很大的不同,但是这两种公众号的底部却是差不多的,二者都有菜单栏,而且这些底部菜单也都是自定义配置的。
如CSDN的官方公众号的底部就有精彩栏目、新程序员、CSDN等菜单可供使用:

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

那这些菜单是如何生成的呢?微信以配置方式的不同把它分为了两类:自定义菜单、个性化菜单。

自定义菜单

微信公众号自定义菜单栏的配置需要登录『微信公众平台』,依次选择 内容与互动—>自定义菜单 ,如下:

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

在『菜单信息栏』中我们有3种类型的菜单可以选择:发送消息、跳转网页、跳转小程序。

菜单类型

1. 发送消息

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

这种菜单点击后,公众号会自动弹出一条消息,比如华为运动健康的『最新排行』:

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

2. 跳转网页

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

这种菜单点击后,当前会离开公众号,跳转到指定的页面,这个多用在H5小程序上。

3. 跳转小程序

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

这种菜单点击后,当前会离开公众号,跳转到指定的小程序的指定页面。

小结一下

虽然提供了这三种菜单栏,但灵活性上还是不够,想要修改必须要登录『微信公众平台』,做不到自动更新。
举个例子,有个菜单名为『最新资讯』,点击即可打开最新的那一条资讯或文章,如果是自定义菜单,那么就需要运营自己不断地去手动更新跳转的链接,这样运营就很辛苦了。
为了方便运营,官方还推出了个性化菜单,所谓个性化菜单就是微信官方推出了可以更改自定义菜单的接口,开发者调用该接口就可以达到菜单的配置。
这里要注意一下,启用个性化菜单后,自定义菜单栏就会变得不可用了,这两种方式只能选其一。
小程序自定义菜单,小程序生态,微信小程序,微信,小程序

个性化菜单

第一步、开启服务器配置

在设置与开发—>基础配置页找到『服务器配置』

开发者ID(AppID)

这个是当前公众号的唯一标识,生成后就不会变化

开发者密码(AppSecret)

这个是动态生成的一串密钥,非常重要,且不能泄露,如有需要请生成后妥善保存。密钥一般可以重复生成。

IP白名单

只有在这里配置过的IP地址,才可以调用微信的服务,之前有篇文章提到过:微信小程序生态7-微信公众号设置IP白名单

服务器地址(URL)

这个是『微信公众号』回调我们的地址,必须以http://或https://开头,分别支持80端口和443端口。也就是说这个不能配置IP,得是域名才行。
例如:https://xxx.com/handleWxCheckSignature

令牌(Token)

自己设置,越复杂越好,不要太简单

消息加解密密钥(EncodingAESKey)

可以随机生成,这个密钥用于解析推送过来的值。

消息加解密方式

有三种,明文模式(明文模式下,不使用消息体加解密功能,安全系数较低)、兼容模式(兼容模式下,明文、密文将共存,方便开发者调试和维护)、安全模式(推荐,安全模式下,消息包为纯密文,需要开发者加密和解密,安全系数高)

注意:这里的配置一旦启用,自定义菜单就会失效并停用;而且如果想要调用服务号的各种功能就必须要启用该配置,那么自定义菜单就一定会失效 -.-!

小程序自定义菜单,小程序生态,微信小程序,微信,小程序

第二步、『微信公众号』签名校验接口实现

第一步中有一个服务器地址(URL),这个地址有一个作用:校验服务器是安全且可用的。即微信那边需要我们保证这个接口微信官方可以调通并且正确返回他们想要的值,如果调不通的话则无法设置自定义菜单。
这里我是用的是SpringBoot应用作为服务

1. 引入小程序开发包依赖

<!-- weixin-java-mp SDK框架-->
<dependency>
  <groupId>com.github.binarywang</groupId>
  <artifactId>weixin-java-mp</artifactId>
  <version>3.6.0</version>
</dependency>

2. 编写微信内容解码类

由于消息加解密方式我们选择的是安全模式,微信传给我们的内容都是加过密的,所以我们需要写一个解码类。

WXBizMsgCrypt.java

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.crypto.PKCS7Encoder;
import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Arrays;

/**
 * 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串).
 * 第三方回复加密消息给公众平台,第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
 */
@Slf4j
public class WXBizMsgCrypt {
    static Charset CHARSET = Charset.forName("utf-8");
    Base64 base64 = new Base64();
    byte[] aesKey;
    String token;
    String appId;

    /**
     * 构造函数
     *
     * @param token          公众平台上,开发者设置的token
     * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
     * @param appId          公众平台appid
     * @throws WxAesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws WxAesException {
        if (encodingAesKey.length() != 43) {
            throw new WxAesException(WxAesException.IllegalAesKey);
        }

        this.token = token;
        this.appId = appId;
        aesKey = Base64.decodeBase64(encodingAesKey + "=");
    }

    // 还原4个字节的网络字节序
    int recoverNetworkBytesOrder(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }

    /**
     * 对密文进行解密.
     *
     * @param text 需要解密的密文
     * @return 解密得到的明文
     * @throws WxAesException aes解密失败
     */
    String decrypt(String text) throws WxAesException {
        byte[] original;
        try {
            // 设置解密模式为AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);

            // 使用BASE64对密文进行解码
            byte[] encrypted = Base64.decodeBase64(text);

            // 解密
            original = cipher.doFinal(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            throw new WxAesException(WxAesException.DecryptAESError);
        }

        String xmlContent, from_appid;
        try {
            // 去除补位字符
            byte[] bytes = PKCS7Encoder.decode(original);

            // 分离16位随机字符串,网络字节序和AppId
            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);

            int xmlLength = recoverNetworkBytesOrder(networkOrder);

            xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
            from_appid =
                    new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
            throw new WxAesException(WxAesException.IllegalBuffer);
        }

        // appid不相同的情况
        if (!from_appid.equals(appId)) {
            throw new WxAesException(WxAesException.ValidateSignatureError);
        }
        return xmlContent;

    }

    /**
     * * 检验消息的真实性,并且获取解密后的明文.
     * <ol>
     * <li>利用收到的密文生成安全签名,进行签名验证</li>
     * <li>若验证通过,则提取xml中的加密消息</li>
     * <li>对消息进行解密</li>
     * </ol>
     *
     * @param msgSignature 签名串,对应URL参数的msg_signature
     * @param timeStamp    时间戳,对应URL参数的timestamp
     * @param nonce        随机串,对应URL参数的nonce
     * @param postData     密文,对应POST请求的数据
     * @return 解密后的原文
     * @throws WxAesException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
            throws WxAesException {

        // 密钥,公众账号的app secret
        // 提取密文
        Object[] encrypt = extract(postData);

        // 验证安全签名
        String signature = getSHA1(token, timeStamp, nonce, encrypt[1].toString());

        // 和URL中的签名比较是否相等
        // System.out.println("第三方收到URL中的签名:" + msg_sign);
        // System.out.println("第三方校验签名:" + signature);
        if (!signature.equals(msgSignature)) {
            throw new WxAesException(WxAesException.ValidateSignatureError);
        }

        // 解密
        String result = decrypt(encrypt[1].toString());
        return result;
    }

    /**
     * 提取出xml数据包中的加密消息
     *
     * @param xmltext 待提取的xml字符串
     * @return 提取出的加密消息字符串
     * @throws WxAesException
     */
    public static Object[] extract(String xmltext) throws WxAesException {
        Object[] result = new Object[3];
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
            dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            dbf.setXIncludeAware(false);
            dbf.setExpandEntityReferences(false);
            DocumentBuilder db = dbf.newDocumentBuilder();
            StringReader sr = new StringReader(xmltext);
            InputSource is = new InputSource(sr);
            Document document = db.parse(is);

            Element root = document.getDocumentElement();
            NodeList nodelist1 = root.getElementsByTagName("Encrypt");
            NodeList nodelist2 = root.getElementsByTagName("ToUserName");
            result[0] = 0;
            result[1] = nodelist1.item(0).getTextContent();

            //注意这里,获取ticket中的xml里面没有ToUserName这个元素,官网原示例代码在这里会报空
            //空指针,所以需要处理一下
            if (nodelist2 != null) {
                if (nodelist2.item(0) != null) {
                    result[2] = nodelist2.item(0).getTextContent();
                }
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new WxAesException(WxAesException.ParseXmlError);
        }
    }

    /**
     * 用SHA1算法生成安全签名
     *
     * @param token     票据
     * @param timestamp 时间戳
     * @param nonce     随机字符串
     * @param encrypt   密文
     * @return 安全签名
     * @throws WxAesException
     */
    public static String getSHA1(String token, String timestamp, String nonce, String encrypt)
            throws WxAesException {
        try {
            String[] array = new String[]{token, timestamp, nonce, encrypt};
            StringBuffer sb = new StringBuffer();
            // 字符串排序
            Arrays.sort(array);
            for (int i = 0; i < 4; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            // SHA1签名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            throw new WxAesException(WxAesException.ComputeSignatureError);
        }
    }

    /**
     * 校验签名
     *
     * @param signature 签名
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @return 布尔值
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce, String token) {
        String checkText = null;
        if (null != signature) {
            //对ToKen,timestamp,nonce 按字典排序
            String[] paramArr = new String[]{token, timestamp, nonce};
            Arrays.sort(paramArr);
            //将排序后的结果拼成一个字符串
            String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);

            try {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                //对接后的字符串进行sha1加密
                byte[] digest = md.digest(content.toString().getBytes());
                checkText = byteToStr(digest);
            } catch (Exception e) {
                log.error("解码发生异常", e);
            }
        }
        //将加密后的字符串与signature进行对比
        return checkText != null ? checkText.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转化我16进制字符串
     * @param byteArrays 字符数组
     * @return 字符串
     */
    private static String byteToStr(byte[] byteArrays){
        String str = "";
        for (int i = 0; i < byteArrays.length; i++) {
            str += byteToHexStr(byteArrays[i]);
        }
        return str;
    }

    /**
     *  将字节转化为十六进制字符串
     * @param myByte 字节
     * @return 字符串
     */
    private static String byteToHexStr(byte myByte) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        char[] tampArr = new char[2];
        tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
        tampArr[1] = Digit[myByte & 0X0F];
        String str = new String(tampArr);
        return str;
    }
}

3. 回调接口代码

这里有一个gzhToken,这个token也就是上面配置中的令牌(Token)。

    @GetMapping(value = "/handleWxCheckSignature")
    @ResponseBody
    public void handleWxCheckSignature(HttpServletRequest request, HttpServletResponse response) {
        //微信加密签名
        String signature = request.getParameter("signature");
        //时间戳
        String timestamp = request.getParameter("timestamp");
        //随机数
        String nonce = request.getParameter("nonce");
        //随机字符串
        String echostr = request.getParameter("echostr");
        //接入验证
        if (WXBizMsgCrypt.checkSignature(signature, timestamp, nonce, gzhToken)) {
            log.info("微信公众号校验完成echostr:[{}]", echostr);
            try {
                response.getWriter().print(SecurityUtil.escapeHtml(echostr));
            } catch (IOException e) {
                log.error("输出返回值异常", e);
            }
            return;
        }
        throw new RuntimeException("解析签名发生异常");
    }

第三步、『微信公众号』获取accessToken

这一步想必只要对接过开放平台的小伙伴都清楚是啥,我就不赘述了,调用获取代码如下:

@Override
    public String getGzhAccessToken(String appId,String appSecret) {
        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
        ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
        log.info("创建公众号AccessToken:{}", result.getBody());
        if (StringUtils.isEmpty(result.toString())) {
            return null;
        } else {
            return JSONObject.parseObject(result.getBody()).getString("access_token");
        }
    }

第四步、构建菜单栏数据

官方规定数据格式如下,详见官方文档:创建菜单

简单解释一下:DefaultMenu是一个保底的菜单,如果其他配置都失效了,用这个;菜单栏对于安卓端和IOS端是单独配置的,需要配置两份。

{
    "DefaultMenu": {
        "button": [
            {
                "type": "miniprogram",
                "name": "首页",
                "url": "小程序安全链接,当小程序打不开时跳转到此页",
                "appid": "appId",
                "pagepath": "pages/Main/pages/Index/index"
            }
        ],
        "matchrule": {
            "client_platform_type": "1"
        }
    },
    "iosMenu": {
        "button": [
            {
                "name": "菜单栏1",
                "sub_button": [
                    {
                        "type": "miniprogram",
                        "name": "小程序",
                        "url": "小程序安全链接,当小程序打不开时跳转到此页",
                        "appid": "appId",
                        "pagepath": "pages/Main/pages/Index/index"
                    },
                    {
                        "type": "view",
                        "name": "网页",
                        "url": "网页链接"
                    }
                ]
            },
            {
                "name": "菜单栏2",
                "type": "miniprogram",
                "url": "小程序安全链接,当小程序打不开时跳转到此页",
                "appid": "appId",
                "pagepath": "pages/Main/pages/Index/index"
            }
        ],
        "matchrule": {
            "client_platform_type": "1"
        }
    },
    "androidMenu": {
        "button": [
            {
                "name": "菜单栏1",
                "sub_button": [
                    {
                        "type": "miniprogram",
                        "name": "小程序",
                        "url": "小程序安全链接,当小程序打不开时跳转到此页",
                        "appid": "appId",
                        "pagepath": "pages/Main/pages/Index/index"
                    },
                    {
                        "type": "view",
                        "name": "网页",
                        "url": "网页链接"
                    }
                ]
            }
        ],
        "matchrule": {
            "client_platform_type": "2"
        }
    }
}

第五步、调用创建菜单接口

按照微信官方的说法,一共有两个接口, https://api.weixin.qq.com/cgi-bin/menu/create 和 https://api.weixin.qq.com/cgi-bin/menu/addconditional
第一个接口是创建默认菜单,也就是DefaultMenu的内容,第一个接口则是个性化菜单,也就是iosMenu和androidMenu
详见官方文档:创建默认菜单、创建个性化菜单

代码如下:

private JSONObject getResult(JSONObject data, String url) {
        HttpHeaders headers = new HttpHeaders();
        HttpMethod method = HttpMethod.POST;
        // 以表单的方式提交
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        //将请求头部和参数合成一个请求
        HttpEntity<JSONObject> requestEntity = new HttpEntity<>(data, headers);
        //执行HTTP请求,将返回的结构使用ResultVO类格式化
        ResponseEntity<JSONObject> response = restTemplate.exchange(url, method, requestEntity, JSONObject.class);
        return response.getBody();
    }

   //创建默认菜单
    public JSONObject addProgramDefaultMenu(String menus, String accessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;
        JSONObject data = JSONObject.parseObject(menus, JSONObject.class);
        return getResult(data, url);
    }

    //创建个性化菜单
    public JSONObject addProgramCustomMenu(String menus, String accessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=" + accessToken;
        JSONObject data = JSONObject.parseObject(menus, JSONObject.class);
        return getResult(data, url);
    }

总结

微信公众号的菜单栏很像浏览器网页上的导航栏,但是限于屏幕大小、生态属性,没法做的很花里胡哨,不过微信官方也在尽力帮助运营和开发者把菜单栏做的个性化一点。虽然上面的流程比较长,但只要好好看文档,实现这个功能也不难,核心就是把菜单配置好后,调用接口而已。不过确实有一些坑在:

  • IP白名单的配置
  • 微信签名校验解码
  • 菜单栏数据格式错误等等

希望我这篇文章可以让大家少走点弯路,成功实现自己想要的效果。文章来源地址https://www.toymoban.com/news/detail-546555.html

到了这里,关于微信小程序生态13-微信公众号自定义菜单、个性化菜单配置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信公众号启用了服务器配置如何自定义菜单?

    微信公众号(服务号)启用了服务器配置,如何自定义菜单呢? 当我们启用了服务器配置,公众号的默认的自定义菜单就会失效。其实我们可以通过调用API接口来完成自定义菜单功能的配置。 微信公众号自定义菜单接口文档:微信开放文档 目录 一、获取Access_TOKEN 二、创建

    2024年02月09日
    浏览(58)
  • 微信小程序自定义底部菜单设计,固定在底部,并非使用tabBar设计

    1.微信小程序自定义底部菜单设计,并且固定在底部,并非tabBar设计 场景:比如加载详情页时:底部需要加入购物车、收藏、返回主页等设计 效果图: 点击事件发生 xx.wxml 样式设计xx.wxss js设计xx.js

    2024年02月16日
    浏览(49)
  • uniapp微信公众号跳转到小程序(是点击微信页面上面的按钮/菜单跳转)

    先看效果 先贴代码: 1、先下载依赖 2、main.js 3、使用的页面引入(或者main引入) 4、初始化、注册 5、html 接下来才是重点: 要在公众号后台配置JS接口安全域名、网页授权域名、IP白名单,而且域名需要备案,在微信开发者工具中不能通过ip调试,可以修改本地hosts代理一下

    2024年02月09日
    浏览(115)
  • 微信小程序如何跳转微信公众号

    登录微信公众号,点击【小程序管理】: 点击【添加】: 点击【关联小程序】: 输入小程序进行关联: 登录微信小程序,点击【设置】: 打开 “引导关注公众号”,设置需要关注的公众号: 首页添加代码: 如果关联的公众号为已认证企业号,可以添加如下代码: url 为公

    2024年02月11日
    浏览(213)
  • 微信小程序如何跳转到微信公众号文章,小程序如何关联公众号或订阅号

    公众号最高管理权限(或能与最高权限管理者配合操作) 小程序开发权限或最高管理权限 根据官方资料描述,小程序中展示微信公众号中的文章需要使用到 web-view web-view 是一个 web 浏览器组件,可以用来承载网页的容器,会自动铺满整个页面 src:webview 指向网页的链接 特别

    2024年02月14日
    浏览(83)
  • 【小程序】微信小程序中实现【关注公众号】弹窗

    1、效果,注意,在开发工具中并不显示公众号信息,只有在体验版和正式版中才能看到!

    2024年02月15日
    浏览(59)
  • 微信小程序或公众号音频下载保存

    需求背景 一些微信公众号的文章或小程序里会嵌入一些音频,有时我们需要把这些音频保存到手机或电脑里,在音频失效后或没有微信环境时也能随时听。下面就个人经验总结一下: 环境 手机微信版本:8.0.35 开干 打开要下载的音频开始播放。 打开手机上的文件管理器,依

    2024年02月16日
    浏览(53)
  • 微信小程序向公众号推送消息模板

    由于微信小程序长期订阅的消息模板全部失效以后,对于小程序的消息推送可以改成往公众号推。 这里将介绍如何使用小程序向公众号推送消息,并且消息可以跳转到小程序 1、微信公众平台注册 服务号 (订阅号是不可以推送的)与小程序,两者都需要认证并且 认证主体是

    2024年02月06日
    浏览(56)
  • 【实战】前端必会 —— 微信小程序 跳转 微信公众号

    web-view | 微信开放文档 跳转方案的选择关键在于目的性: 引流关注:直接跳转公众号页面 内容查看:使用 web-view 直接查看 biz 相当于微信公众号的 唯一身份标识 PC端随意打开一篇公众号文章,使用非微信内置浏览器打开, F12 ,network(网络),fetch/XHR 过滤,可以看到这些请

    2024年02月16日
    浏览(59)
  • 微信小程序引导关注公众号(超详细),获取公众号openID,是否关注公众号信息

    需求背景:微信小程序里,需要判断使用该小程序的用户是否有关注该小程序关联的公众号,如未关注要引导用户去关注公众号(用于公众号推送信息) 官网: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html 接口(获取Code): 参数: APPID:公众号的唯

    2024年02月15日
    浏览(79)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包