如果要完成微信分享,还是有需要去微信官方开发文档看一下的。附上地址:
微信开发平台
微信公众平台开发文档
自己老年记忆力过段时间肯定会忘记如何去实现这个功能,所以记录一下。
因为自己不是写客户端的(Android、ios),所以前端代码并不能详细记录在这里,可以参考微信开发平台中的说明。后端服务是在客户端提供给我们一个接口的前提下进行开发的。
接口如下:
/**
* 分享
* type:1:仅分享到通讯2:仅分享到其他3:分享到通讯和其他,
* wxTitle:微信分享标题(type==2|3时,必输),
* wxDes:微信分享描述(type==2|3时,必输),
* wxLink:微信分享分享页面地址(type==2|3时,必输),
* wxThump:微信分享 缩略图,
* wxType:微信分享类型0:网页分享1:文本分享2:本地图片分享3:网络图片分享,
*/
function shareMsg(json){
window.SysClientJs.shareMsgTo(JSON.stringify(json));
}
ps:参数type是用来表示点击分享后都有哪几个分享选项供用户选择:
1:平台通讯(我们自己应用内的通讯)
2:只分享到微信(没有平台通讯选项)
3:平台通讯和微信都有
有了客户端给的方法,实现微信分享功能就比较简单了。
/*
* 封装传送的数据
*/
var json ={
type:'2',
wxTitle:'**银行代销基金产品',
wxDes:'我行代销各类基金产品,请点击查看详情',
wxLink:$rootScope.AppUrl+'fundListWXShare?ShareId='+data.ShareId
};
/*
* 调用分享方法
*/
$clientUtils.shareMsg(json);
到这里微信分享就结束了,wxThump不填,默认选择客户端已经定义的图片,wxType默认为1。
分享后的图片:
ps:图片并不是代码里边的基金产品,不过样式是一样的。
好的,终于可以把好东西分享给好友了,但是好友并点不开你的分享。还差一步,你分享的这个东西相当于一个链接,就是参数里边的wxLink。好友点击你分享的内容,就相当于在微信浏览器里边输入了一个地址,然后微信浏览器去服务器获取页面展示给用户。最后一步就是写个页面来响应浏览器的请求。
问题复现流程:分享给好友->好友打开看了看感觉还不错就想分享给他的好友->点击微信浏览器右上角的三个点 ,->选择发送给朋友 ,ok 结果发现变样了(如下图)。
标题变了,摘要变了,图片也没了......
有问题就只能解决,之前试过WeixinJSBridge接口,但是没有效果,通过百度了解到微信为了整顿"诱导分享"的行为,关闭了WeixinJSBridge。
经过百度、看开发文档,总算找到了解决方法。
首先,你得有一个已经认证的微信公众号(企业公众号),没有是不行滴~。
要准备的东西:
1.APPID、appsecret(在微信公众号 开发->基本设置 能看到)
2.公众号要设置安全域名(在 微信公众号 设置->公众号设置 -> 功能设置 -> JS接口安全域名)
3.IP地址白名单
设置->安全中心->IP白名单(IP地址就是服务器地址,没有这个白名单获取token时 会报IP地址非法。)
下面开始撸代码:
向微信给定的url(https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET)发GET请求,获取token和token的有效期,获取token只需要替换APPID和APPSECRET,grant_type的值不变。
/* accessToken 静态全局变量 保存上次获取的token
* tokenExpireTime 静态的全局变量 保存上次获取token的有效期
* getTokenTime 静态的全局变量 保存上次获取token的时间
*/
if(accessToken==null||("").equals(accessToken)||(now - getTokenTime > tokenExpireTime*1000)){
Map tokenInfo = getAccessToken();
if(tokenInfo != null){
accessToken = (String) tokenInfo.get("access_token");
tokenExpireTime = Long.parseLong(tokenInfo.get("expires_in")+"");
getTokenTime = System.currentTimeMillis();
}else{
logger.info("get token is failure!");
}
}
private Map getAccessToken(){
String requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);
Map result = HttpUtil.doGet(requestUrl);//向微信发送get请求
return result ;
}
ps:token有每天的获取次数和获取频率,如果频繁获取将会触发限制。所以token要在本地缓存,上边的代码缓存简单的用static来存储,严格来说应该存在数据库,如果生产上有多台服务器,就必须要存在数据库了。
跟获取token有一点不同,token是获取ticket的参数,最后我们只需要ticket。url如下:(https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi)只需要把ACCESS_TOKEN(就是我们第一步获取的token)替换就OK。
if(jsApiTicket==null||("").equals(jsApiTicket)||(now - getTiketTime > ticketExpireTime*1000)){
Map ticketInfo = getJsApiTicket();
if(ticketInfo!=null){
jsApiTicket = (String) ticketInfo.get("ticket");
ticketExpireTime = Long.parseLong(ticketInfo.get("expires_in")+"");
getTiketTime = System.currentTimeMillis();
}else{
logger.info("get ticket is failure!");
}
}
@SuppressWarnings("rawtypes")
private Map getJsApiTicket(){
String requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);
Map result = HttpUtil.doGet(requestUrl);
return result;
}
下图是微信开发文档的签名算法,开发文档中还有微信给的简单示例(java、php...)。
实现代码:
public Map makeWXTicket(String jsApiTicket, String url) {
Map ret = new HashMap();
String nonceStr = createNonceStr();
String timestamp = createTimestamp();
String string1;
String signature = "";
string1 = "jsapi_ticket=" + jsApiTicket +
"&noncestr=" + nonceStr +
"×tamp=" + timestamp +
"&url=" + url;
try{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}catch (Exception e){
logger.error("WeChatController.makeWXTicket=====Start");
logger.error(e.getMessage(),e);
logger.error("WeChatController.makeWXTicket=====End");
}
ret.put("url", url);
ret.put("jsapi_ticket", jsApiTicket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
ret.put("appid", appId);
return ret;//返回到前端的数据
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String createNonceStr() {
return UUID.randomUUID().toString();
}
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
data是后端传过来的数据:包含appid、时间戳、随机字符串、签名、ticket、url。
wx.config({
debug: false,
appId: data.appid,
timestamp: data.timestamp,
nonceStr: data.nonceStr,
signature: data.signature,
jsApiList: [//需要用到的接口
'checkJsApi',
'onMenuShareTimeline',//分享到朋友圈的接口
'onMenuShareAppMessage'//分享给朋友的接口
]
});
如果验证成功,debug模式下会提示config:ok。一般情况下,不OK一般是因为url的问题。url的值就是分享微信时wxLink的值去掉#号后边的内容。一般url的取值在js中取:
url = location.href.split('#')[0].toString();
传到后端进行签名。这个url必须包含在js接口安全域名内。
分享到朋友圈、好友这两个接口只是众多接口中比较常用的两个。还有分享到qq、微博等接口。
wx.ready(function () {
wx.checkJsApi({//可要可不要,功能只是校验下都支持哪些接口
jsApiList:['onMenuShareTimeline','onMenuShareAppMessage'],
success:function(res){
}
});
wx.onMenuShareTimeline({
title: title,//自定义的标题
link: link,//自定义的链接
imgUrl: $rootScope.rootUrl+'share/assets/logo.jpg',//自定义的图片
trigger: function (res) {
},
success: function (res) {
},
cancel: function (res) {
},
fail: function (res) {
}
});
wx.onMenuShareAppMessage({
title: title,
desc: desc,
link: link,
imgUrl: $rootScope.rootUrl+'share/assets/logo.jpg',
type: 'link',
dataUrl: '',
success: function () {
},
cancel: function () {
}
});
wx.error(function (res) {
});
});
ok,效果图如下: