微信公众号开发入门
Posted 左直拳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信公众号开发入门相关的知识,希望对你有一定的参考价值。
实在是太折腾,太难懂了。也太坑了。
下面是这几天的,有关微信公众号的工作总结。算不上全面,只是我作为一个初哥的记录,仅以备忘。
一、微信公众号开发,开发什么?
公众号与小程序不同,小程序类似手机APP,微信只是提供了一个入口而已,而公众号则基本上是在微信框架内。微信公众号本质上是用户的一个联系人,只不过是比较特殊的联系人而已。通过微信提供的管理后台,无须任何编程,就可以很快搭建出一个像模像样的公众号,菜单、自动客服,文章更新。
当然,如果要更强的功能,就需要额外的服务了。比如,自动客服。通过公众号管理后台,可以定义一些自动回复语,但毕竟不够智能,这时我们可以在互联网上搭建服务器,提供相应服务。启用这个选项后,则公众号收到的用户的消息,全部由我们的服务来处理,原有的自动客服失效。当然,提供服务,要有网址、域名。
除此之外,还有菜单。菜单项可以设置为点击则回复一些消息,或跳转到小程序,或打开一张页面。未经验证的公众号,只能打开发表在当前公众号里的文章或图片、视频之类,而经过验证的公众号,点击菜单项可以直接打开网址。这个网址,应该没有什么限制,但我觉得,通常都会是部署在互联网上的所谓微信网页,即这些个页面不是普通的网页,而是使用了微信JS-SDK的页面,上面有各种微信的元素,比如扫一扫啦,分享到朋友圈啦,诸如此类。这些个页面,需要开发。
还有就是给关注者发送消息。我认为这是微信公众号最大的卖点。比如说,我关注了某个公众号,通过这个公众号的菜单,打开了相关小程序办事,事情有了进展,系统就可以通过这个公众号给我发个消息,提示一下当前进度。我认为这是公众号开发中最值得做的工作。
当然,还可以通过程序自动组织材料,在公众号上发表文章。不过这种事情,人工在公众号管理后台也能做,无非动动手而已。
二、微信公众号开发前铺垫
1、公众号的分类
衣穿三色,食分五等。所谓微信公众号,分为订阅号和服务号,个人只能申请订阅号,企业可以申请订阅号和服务号。然后公众号又有经过认证和未经认证之分。是否经过认证,在进行开发,调用微信服务上的差别非常大。未经认证,基本上没有啥可以玩的。而且!个人申请的订阅号,是没有微信认证这一说法的,直接堵死这扇门。
那开发怎么办?微信提供了测试账号这个机制,我们可以申请测试账号,用这个账号来测试微信服务接口。这个账号所有接口都能测,好像无敌了。然鹅!像微信网页这些,需要跑在手机上看效果,有些渲染测试账号是出不来的,比如所谓的微信开放标签(就是微信自己定义的,类似html的标签),用测试账号的信息注册页面功能,根本没东西显示出来。
总之,整个微信体系,感觉东西很多很杂,各种自定义的术语,对于初接触者,晕头转向。然后提供的开发文档,洋洋洒洒,密密麻麻,但你又往往看不出它说的究竟是个什么东西,只是一上来就说应该怎么怎么弄,却又极少举例子。这就给初学者带来很大的困扰,人为制造了许多的障碍。
订阅号与服务号侧重点不同。按我的理解,订阅号侧重发表文章,服务号则侧重针对性发通知消息。总的来说,服务号功能比订阅号要强大许多。
表面上看,订阅号每天可以群发1条消息,而服务号只能每个月发4条,订阅号要强。问题是,群发消息有啥用?我们网上办事,要的是针对本人的消息。这个消息,其实叫“模板消息”。只有服务号才能发送模板消息。这种消息,是根据需要,针对某个人进行发送。为啥叫模板消息呢?是因为这种消息发送时,要结合模板生成消息文本,然后进行发送。就像我们的手机短信。做过手机短信开发都知道,手机短信可不是随随便便就能发送的,因为众所周知的原因,怕有违法、出格的内容,所以手机短信管理后台,有所谓的模板,即短信格式是固定的,许多字眼也都是固定的,我们每次发送时只需往里面填一些内容就行。这个模板是要事先创建好并通过电信运营商审批。微信这个模板消息也一样,需要结合模板。
2、调试工具
就是微信开发者工具。注意是开发者工具,而不是开发工具。这个工具,对于小程序来说,的确就是一个开发工具;而对于公众号来说,只是一个调试工具,并不能通过它来键入什么代码;而且只是微信网页的调试工具。此时它只是一个微信浏览器。方法是在微信开发者工具的顶部输入微信网页地址即可浏览,调试,跟普通浏览器按下F12
差不多。
3、查看运行结果
公众号通过微信客户端就能看到。这里说的查看结果,是指查看 微信网页 的运行结果。虽然有网页二字,但这不是普通的网页,用一般浏览器其实看不到什么东西,最好是通过微信浏览器或者微信开发者工具来运行。手机上并没有一个app叫微信浏览器,是微信隐含的。怎么召唤它呢?可以将微信网页的地址发给微信某个好友,比如“文件传输助手”,然后在聊天记录里点击这个网址,即用微信浏览器打开。绝逼是微信浏览器,QQ浏览器都不好使。
4、开发文档
基于微信做二次开发,网上查资料基本没什么卵用,最好还是老老实实地啃微信官方开发文档。
公众号开发文档在 公众号管理后台 - 设置与开发 - 开发者工具 - 开发文档 打开。
微信有两个平台,小程序的叫“微信开发开放平台”,公众号的叫“微信开发公众平台”。
5、一些术语
1)管理员及运营者
申请公众号的人是管理员。申请过程中,要申请人无数次用自己的微信去扫二维码。这对开发来说就比较尴尬,管理员一般是公众号的所有权人,但他往往不开发,那后台设置要做些修改咋办?难道下下都惊动大老板来扫二维码吗?可以把我们加到运营者名单里,我们自己扫码就行。运营者分长期和短期2种,应该是长期运营者,权限才够大。可在 微信公众号管理后台 - 设置与开发 - 人员设置 里设置。
2)IP白名单
在开发过程中,我们需要访问微信服务器,比如获取token之类。发出请求的IP,需要在白名单上。这个IP,是指互联网IP。假如我们在公司内部开发,那这个IP是公司上网的IP。问题是,这个IP经常变。我基本上是每天改一次白名单。
3)开发者微信号
公众号管理后台 - 设置与开发 - web开发者工具,将我们开发人员的微信号加进去。这是开发微信网页要用到的。因为微信开发者工具需要微信号登录。
4)JS接口安全域名
公众号管理后台 - 设置与开发 - 公众号设置 - 功能设置。
也是微信网页开发需要。我们的页面,需要放在这个域名里,微信的js-sdk才可以使用。
填写这个域名的时候,需要下载一个txt文件放到域名下,微信验证域名真伪才能保存。不过,我们在本地开发,可以修改host文件,将本机ip映射为这个域名。
5)微信开放标签
类似HTML的,微信独有的标签。如
跳转小程序:<wx-open-launch-weapp>
跳转App:<wx-open-launch-app>
服务号订阅通知:<wx-open-subscribe>
音频播放:<wx-open-audio>
三、微信网页开发
1、概述
微信网页真的就是一张张网页,只不过,它引用了微信提供的JS库,可能使用微信独有的,类似html的所谓开放标签。并且这个微信网页似乎在普通浏览器上运行,虽不会报错,但似乎看不到什么效果,只能运行在微信浏览器或微信开发者工具上。
以下是一张微信网页(spring boot下,结合了thymeleaf)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>wechat</title>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="./libs/jquery.min.js"></script>
<style>
.sao
text-align: center;width: 100%;height:5.5em;background-color: #ddd;line-height: 5.5em;
cursor:pointer;
.block
height: 100px;
border:solid 1px red;
</style>
</head>
<body>
<!-- 在手机微信上打开本页面,点这个扫一扫,真的会打开摄像头 -->
<div class="sao qr_btn">扫一扫</div>
<div class="block">
<!-- 微信开放标签。测试号不支持,只有认证服务号才可以 -->
<wx-open-subscribe th:template="$template" id="subscribe-btn">
<script type="text/wxtag-template" slot="style">
<style>
.subscribe-btn
color: #fff;
background-color: #07c160;
</style>
</script>
<script type="text/wxtag-template">
<button class="subscribe-btn">
模版消息订阅
</button>
</script>
</wx-open-subscribe>
</div>
</body>
<script th:inline="javascript">
//微信验证
wx.config(
debug: true,
appId: /*[[$wc.appId]]*/'',
timestamp: /*[[$wc.timestamp]]*/'',
nonceStr: /*[[$wc.nonceStr]]*/'',//随机串
signature: /*[[$wc.signature]]*/'',
jsApiList: ['chooseImage','scanQRCode','updateAppMessageShareData','updateTimelineShareData'],//需要使用的微信js-sdk函数列表
openTagList: ['wx-open-subscribe']//开放标签列表
);
wx.ready(function ()
// 微信分享 -- 分享给朋友
wx.updateAppMessageShareData(
title: '分享给您的猪朋狗友吧',
desc: '独食难肥',
link: location.href.split('#')[0],
imgUrl: "http://test.duduchuhai.com/images/share.png",
success: function(res)
console.log(res);
);
// 微信分享 -- 分享到朋友圈
wx.updateTimelineShareData(
title: '分享到猪圈',
link: location.href.split('#')[0],
imgUrl: "http://test.duduchuhai.com/images/share.png",
success: function(res)
console.log(res);
);
);
wx.error(function (res)
console.log(res); // res为微信返回的错误结果
);
// 微信扫一扫
$(".qr_btn").on('click', function()
wx.scanQRCode(
needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res)
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
);
);
</script>
<script>
var btn = document.getElementById('subscribe-btn');
console.log(btn);
btn.addEventListener('success', function (e)
console.log('success', e.detail);
);
btn.addEventListener('error',function (e)
console.log('fail', e.detail);
);
</script>
</html>
2、验证
微信网页运行时,首先要经过微信验证,然后才能正常使用微信各种功能。验证流程是,
1)凭appId和appSecret访问微信服务器获得token
2)用token访问微信服务器获得ticket
3)依次用ticket、随机串、时间戳、当前页面地址组合成一个字符串,然后对字符串进行sha散列运算,得到一个摘要
4)用摘要访问微信服务器获得签名
5)将 appId、时间戳、随机串、签名、本页面需要使用的微信函数、微信开放标签注册到微信
上面例子中,
wx.config(
debug: true,
appId: /*[[$wc.appId]]*/'',
timestamp: /*[[$wc.timestamp]]*/'',//注意是秒,不是毫秒
nonceStr: /*[[$wc.nonceStr]]*/'',//随机串
signature: /*[[$wc.signature]]*/'',//关键所在
jsApiList: ['chooseImage','scanQRCode','updateAppMessageShareData','updateTimelineShareData'],//需要使用的微信js-sdk函数列表
openTagList: ['wx-open-subscribe']//开放标签列表
);
为了得到这个json对象可不容易。appId在微信公众号管理后台可得到,每个公众号都有唯一一个appId;时间戳也容易得到;随机串是自己定的,相对比较容易;最麻烦的是这个签名signature,我调试了差不多1天,总是说非法签名。
获取这个json对象的java代码:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import javax.annotation.PostConstruct;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;
@Service
public class WxServiceImpl implements WxService
@Override
public WxConfig getWxConfig(String url) //url是微信网页地址
WxConfig wc = new WxConfig();//这个是自定义的对象,不必深究
wc.setAppId(APPID);
wc.setNonceStr(getNonceStr());//随机串
wc.setTimestamp((long) (new Date()).getTime() / 1000);//时间戳
wc.setSignature(getSignature(wc.getNonceStr(), wc.getTimestamp(), url));//签名
return wc;
@PostConstruct
void init()
/*
由于从微信服务器获取token和ticket的函数有调用次数限制(每天<=2000),因此用redis将它们缓存起来
*/
this.jedis = new Jedis(redis的IP, redis端口号);
private String getSignature(String nonceStr, long timestamp, String url) //获取签名
String signature = null;
String ticket = getTicket();
if (ticket != null)
String string1 = String.format("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s",
ticket,
nonceStr,
timestamp,
url);
signature = getSha1(string1);
return signature;
//redis对象
private Jedis jedis;
//除了redis缓存,也用静态变量保存一份。不过,应用程序重启它们就消失了,并且不会自动过期
//而从微信获取到的token和ticket有效期是7200秒
private String _ticket = null;
private String _token = null;
//锁。为避免并发,使用锁机制,不要大家都去获取token和ticket
private ReentrantLock lockTok = new ReentrantLock();
private ReentrantLock lockTik = new ReentrantLock();
private String getTicket()
String ticket = null;
String key = "ticket";
ticket = getKey(key, this._ticket);
if (ticket == null)
//锁定。
lockTik.lock();
ticket = getKey(key, this._ticket);//再努力一把
if (ticket == null)
String token = getToken();
if (token != null)
ticket = callGet(String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi",
token), "ticket");
if (ticket != null)
this._ticket = ticket;
setKey(key, ticket);
//解锁
lockTik.unlock();
return ticket;
private String getToken()
String token = null;
String key = "token";
token = getKey(key, this._token);
if (token == null)
lockTok.lock();
token = getKey(key, this._token);
if (token == null)
token = callGet(String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",APPID,AppSecret),
"access_token");
if (token != null)
this._token = token;
setKey(key, token);
lockTok.unlock();
return token;
final static int EXPIRTED = 7200;
private String getKey(String key, String v)
String value = null;
try
value = jedis.get(key);
catch (Exception ex)
value = v;//如果无法从redis中读取则将候补变量值返回。但变量值可能有过期的问题
System.err.println(ex.getMessage());
return value;
private void setKey(String key, String value)
try
jedis.set(key, value);
jedis.expire(key, EXPIRTED);
catch (Exception ex)
System.err.println(ex.getMessage());
final static int NONCESTR = 16;//随机串的长度为16。这个数值是自己定的
private String getNonceStr() // 生成随机字符串noncestr
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuffer noncestr = new StringBuffer();
int limit = chars.微信公众号开发--入门