使用JS-SDK自定义微信分享效果
之前做的一个h5页面,按照需求得分享到朋友圈he好友,默认分享链接的标题he内容以及图标都是微信默认的,下面是一个大神进行自定义的分享链接的代码,看到了记录下:
前言
刚进入一家新公司,接到的第一个任务就是需要需要自定义微信分享的效果(自定义缩略图,标题,摘要),一开始真是一脸懵逼,在网上搜索了半天之后大概有了方案。值得注意的是一开始搜索到的解决方案全是调用微信的自带的JS-SDK,然而腾讯是不会让广大吃瓜群众这么轻而易举的调用他们的东西的。微信开发团队已经把调用的权限收回,现在无法直接在页面直接调用JS-SDK了。话不多说,直接上干货。
预期效果
原始的分享效果:
使用微信JS-SDK的分享效果:
可以看出缩略图,标题,摘要样式良好,给用户的体验很好。
准备工作
微信官方开发者文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
现在的思路已经很明确了,就是通过调用微信的JS-SDK实现自定义分享效果。但是这个调用过程比较繁琐,需要提前准备如下东西:
(1)微信服务号一个,并且已经通过了实名认证;
没有实名认证的话,一些接口没有调用权限。
(2)一个ICP备案的域名;
这个域名需要设置为微信公众号后台的JS接口安全域名,否则微信仍然不允许调用它的接口。
这时大家应该就犯难了,这样的话岂不是不能在本地测试,只能部署到生产环境才能测试?不用着急,解决方案告诉大家:花生壳的内网穿透服务(收费,20元以内)
花生壳官网:http://hsk.oray.com/price/#personal
选择个人免费版就可以了,虽然说是免费版,但是其实注册过程中还是要收几块钱的,因为我自己买了域名和流量所以花的钱更多一些,但也在20元以内。不建议大家购买流量,送的流量可以用很久了。
当准备好上面提到的就可以开始敲代码了。
(3)安装微信开发者工具,用于本地调试。
下载地址:https://mp.weixin.qq.com/debug/cgi-bin/webdebugger/download?from=mpwiki&os=x64
官方使用教程:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140
具体步骤
(1)查看AppId,AppSecret以及绑定域名
进入微信后台,找到下面的菜单
获取AppID和AppSecret
设置JS接口安全域名
注意第三步,如果微信服务器不能在我们的服务器上访问到这个txt文件,域名是无法设置成功的,这里先告诉大家在哪里设置,想要成功设置域名还需要使用花生壳的服务,让微信服务器访问我们本地工程中的的txt文件才行。
hkh3321313.vicp.io是在花生壳上购买的域名,免费送的域名是在太难记了,完全不能忍。
(2)引入JS文件
这里需要注意是http还是https,如果生产环境是https,务必前缀是https,都则会出现mix content这样的错误,导致引入失败。
<script typet="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
(3)通过AppId和AppSecret请求accessToken,然后通过accessToken获取jsapi_ticket,生成config接口所需参数
因为获取这两个参数的次数是有限制的(accessToke 每日2000次,jsapi_ticket 每日100000次),有效期是7200秒,每两小时请求一次就行啦,把获取的accessToke和jsapi_ticket保存在后台,所以accessToken和jsapi_ticket这两个参数的获取是通过ajax方式请求后台,而不是实时去获取的。
config几个参数需要详细说明一下:
- timestamp 生成签名的时间戳 create_nonce_str()
- nonceStr 随机生成的字符串 create_timestamp()
- signature 按照微信文档签名算法生成的签名 makeWXTicket()
附上signature算法的官方说明:
https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.15697429783636763#buzhou3
在附录1中可以找到详细说明。
此外,官方提供了一个签名算法的校验工具:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
下面只附上了主要的方法:
//获取accessToken
private JSONObject getAccessToken(){//String accessTokenUrl= https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRETString requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);log.info("getAccessToken.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result ;
}//获取ticket
private JSONObject getJsApiTicket(){//String apiTicketUrl= https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapiString requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);log.info("getJsApiTicket.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result;
}//生成微信权限验证的参数
public Map<String, String> makeWXTicket(String jsApiTicket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonceStr = createNonceStr();String timestamp = createTimestamp();String string1;String signature = "";//注意这里参数名必须全部小写,且必须有序string1 = "jsapi_ticket=" + jsApiTicket +"&noncestr=" + nonceStr +"×tamp=" + timestamp +"&url=" + url;log.info("String1=====>"+string1);try{MessageDigest crypt = MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());log.info("signature=====>"+signature);}catch (NoSuchAlgorithmException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.error("WeChatController.makeWXTicket=====End");}catch (UnsupportedEncodingException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.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);
}
HttpUtil代码
public class HttpUtil {public static Log logger = LogFactory.getLog(HttpUtil.class);//get请求public static com.alibaba.fastjson.JSONObject doGet(String requestUrl) {CloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = null;String responseContent = null;com.alibaba.fastjson.JSONObject result = null;try {//创建Get请求,HttpGet httpGet = new HttpGet(requestUrl);//执行Get请求,response = httpClient.execute(httpGet);//得到响应体HttpEntity entity = response.getEntity();//获取响应内容responseContent = EntityUtils.toString(entity,"UTF-8");//转换为mapresult = JSON.parseObject(responseContent);} catch (IOException e) {logger.error("HttpUtil=====Start");logger.error(e.getMessage(),e);logger.error("HttpUtil=====End");}return result;}
}
(4)通过config接口注入权限验证配置
官方示例:
wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳nonceStr: '', // 必填,生成签名的随机串signature: '',// 必填,签名,见附录1jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
自己的代码:
其中的url不能硬编码写在后台,必须通过动态传递。
$(function(){var url = location.href.split('#').toString();//url不能写死$.ajax({type : "get",url : "/wechatParam",dataType : "json",async : false,data:{url:url},success : function(data) {wx.config({debug: false,生产环境需要关闭debug模式appId: data.appid,//appId通过微信服务号后台查看timestamp: data.timestamp,//生成签名的时间戳nonceStr: data.nonceStr,//生成签名的随机字符串signature: data.signature,//签名jsApiList: [//需要调用的JS接口列表'checkJsApi',//判断当前客户端版本是否支持指定JS接口'onMenuShareTimeline',//分享给好友'onMenuShareAppMessage'//分享到朋友圈]});},error: function(xhr, status, error) {//alert(status);//alert(xhr.responseText);}})
});
(5)通过ready接口处理成功验证
官方示例:
wx.ready(function(){// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。});
自己的代码:
wx.ready(function () {var link = window.location.href;var protocol = window.location.protocol;var host = window.location.host;//分享朋友圈wx.onMenuShareTimeline({title: '这是一个自定义的标题!',link: link,imgUrl: protocol+'//'+host+'/resources/images/icon.jpg',// 自定义图标trigger: function (res) {// 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回.//alert('click shared');},success: function (res) {//alert('shared success');//some thing you should do},cancel: function (res) {//alert('shared cancle');},fail: function (res) {//alert(JSON.stringify(res));}});//分享给好友wx.onMenuShareAppMessage({title: '这是一个自定义的标题!', // 分享标题desc: '这是一个自定义的描述!', // 分享描述link: link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: protocol+'//'+host+'/resources/images/icon.jpg', // 自定义图标type: 'link', // 分享类型,music、video或link,不填默认为linkdataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空success: function () {// 用户确认分享后执行的回调函数},cancel: function () {// 用户取消分享后执行的回调函数}});wx.error(function (res) {alert(res.errMsg);});});
到这里所有的代码都已经分享完毕了。
(6)启动花生壳的内网穿透服务,设置JS接口安全域名
这个基本是傻瓜式的,只要下载他们的客户端就可以了。
官网教程:http://hsk.oray.com/news/4345.html
添加一个映射就可以了
把之前下载的txt文件放在工程目录webapp下,然后本地启动工程,确定通过域名可以访问本地项目后,设置JS安全域名
现在访问 域名:端口号(例如:hkh3321313.vicp.io:8080)就可以访问本地项目啦。
(7)使用微信开发者工具测试
微信开发者工具其实就是微信的浏览器,其中集成了chrome的调试工具,前面提到wx.config中的debug模式这里就发挥作用了,浏览器会自动弹出调用微信接口的返回结果。
成功返回的话结果应该是ok什么的,图就不上了。提醒大家,上生产环境一定要把debug改为false~
后记
虽然已经给了主要的代码,大家一定还是不想写接口,下面附上完整的代码,如果你觉得解了燃眉之急
@Controller
public class WeChatController {private final Logger log = LoggerFactory.getLogger(this.getClass());//获取相关的参数,在application.properties文件中@Value("${wechat.appId}")private String appId;@Value("${wechat.appSecret}")private String appSecret;@Value("${wechat.url.accessToken}")private String accessTokenUrl;@Value("${wechat.url.apiTicket}")private String apiTicketUrl;//微信参数private String accessToken;private String jsApiTicket;//获取参数的时刻private Long getTiketTime = 0L;private Long getTokenTime = 0L;//参数的有效时间,单位是秒(s)private Long tokenExpireTime = 0L;private Long ticketExpireTime = 0L;//获取微信参数@RequestMapping("/wechatParam")@ResponseBodypublic Map<String, String> getWechatParam(String url){//当前时间long now = System.currentTimeMillis();log.info("currentTime====>"+now+"ms");//判断accessToken是否已经存在或者token是否过期if(StringUtils.isBlank(accessToken)||(now - getTokenTime > tokenExpireTime*1000)){JSONObject tokenInfo = getAccessToken();if(tokenInfo != null){log.info("tokenInfo====>"+tokenInfo.toJSONString());accessToken = tokenInfo.getString("access_token");tokenExpireTime = tokenInfo.getLongValue("expires_in");//获取token的时间getTokenTime = System.currentTimeMillis();log.info("accessToken====>"+accessToken);log.info("tokenExpireTime====>"+tokenExpireTime+"s");log.info("getTokenTime====>"+getTokenTime+"ms");}else{log.info("====>tokenInfo is null~");log.info("====>failure of getting tokenInfo,please do some check~");}}//判断jsApiTicket是否已经存在或者是否过期if(StringUtils.isBlank(jsApiTicket)||(now - getTiketTime > ticketExpireTime*1000)){JSONObject ticketInfo = getJsApiTicket();if(ticketInfo!=null){log.info("ticketInfo====>"+ticketInfo.toJSONString());jsApiTicket = ticketInfo.getString("ticket");ticketExpireTime = ticketInfo.getLongValue("expires_in");getTiketTime = System.currentTimeMillis();log.info("jsApiTicket====>"+jsApiTicket);log.info("ticketExpireTime====>"+ticketExpireTime+"s");log.info("getTiketTime====>"+getTiketTime+"ms");}else{log.info("====>ticketInfo is null~");log.info("====>failure of getting tokenInfo,please do some check~");}}//生成微信权限验证的参数Map<String, String> wechatParam= makeWXTicket(jsApiTicket,url);return wechatParam;}//获取accessTokenprivate JSONObject getAccessToken(){//String accessTokenUrl = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRETString requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);log.info("getAccessToken.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result ;}//获取ticketprivate JSONObject getJsApiTicket(){//String apiTicketUrl = https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapiString requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);log.info("getJsApiTicket.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result;}//生成微信权限验证的参数public Map<String, String> makeWXTicket(String jsApiTicket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonceStr = createNonceStr();String timestamp = createTimestamp();String string1;String signature = "";//注意这里参数名必须全部小写,且必须有序string1 = "jsapi_ticket=" + jsApiTicket +"&noncestr=" + nonceStr +"×tamp=" + timestamp +"&url=" + url;log.info("String1=====>"+string1);try{MessageDigest crypt = MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());log.info("signature=====>"+signature);}catch (NoSuchAlgorithmException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.error("WeChatController.makeWXTicket=====End");}catch (UnsupportedEncodingException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.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);}
}
那 qq 里分享网页呢?标题、描述 和 图片 怎么设置?
参考:手机QQAPI-腾讯移动Web开发平台
<meta itemprop="name" content="这是分享的标题"/> <meta itemprop="image" content="http://imgcache.qq.com/qqshow/ac/v4/global/logo.png" /> <meta name="description" itemprop="description" content="这是要分享的内容" />
其他问题
问:直接在卡片上长按进行转发的话,缩略图信息会失效?
答:参考 微信分享给朋友的链接,再次被好友转发之后,分享链接的图标不见了,怎么解决?求赐教!
使用JS-SDK自定义微信分享效果相关推荐
- 手把手带你使用JS-SDK自定义微信分享效果
前言 刚进入一家新公司,接到的第一个任务就是需要需要自定义微信分享的效果(自定义缩略图,标题,摘要),一开始真是一脸懵逼,在网上搜索了半天之后大概有了方案.值得注意的是一开始搜索到的解决方案全是调用微 ...
- 带你使用JS-SDK自定义微信分享效果
本文转载于:猿2048网站https://www.mk2048.com/blog/blog.php?id=jhh1ib&title=%E5%B8%A6%E4%BD%A0%E4%BD%BF%E7 ...
- js实现自定义微信分享
1.安装相关依赖 1.1在需要调用JS接口的页面引入如下JS文件 (支持https):<script src="http://res.wx.qq.com/open/js/jweixin ...
- android微信分享怎么自定义样式,自定义微信分享样式设置教程
一.功能效果 自定义微信分享可以设置个性化的分享图片.标题.描述,让分享内容更加受到用户的喜爱和欢迎. 二.功能说明 [版本]网站标准版及以上 [前提]1.需要授权已认证的公众号(支持服务号.订阅号) ...
- android微信分享怎么自定义样式,自定义微信分享样式教程
使用场景: 当网站浏览者访问你的网站的时候,情不自禁分享.然而,样式怎么这么挫? 分享别人的网站链接,却是这样的样式,为什么呢? 答案:你没有设置"自定义 微信分享样式" 共有三个 ...
- H5 -- 自定义微信分享第三方页面链接的标题和小缩略图
需求:自定义微信分享第三方页面链接的标题和小缩略图(如图) 2018.6.4更新线 - - - - - - - - - - - - - - - - - - 更新:微信6.5.5版本以后调整了分享规则, ...
- android sdk引入 微信分享_android 调用本地微信自定义多图分享朋友圈,可放在share sdk中一起使用...
最终的效果图,右下角微信多图为自定义调用系统分享,分享到微信. 在你能正常调用share sdk的时候想在原本的基础上加自定义的分享非常的简单. 它的官网已经给出了代码,但是给的不是很清楚. lz毕竟 ...
- 简单粗暴教你在VUE中引入微信SDK 调用微信分享、朋友圈分享、QQ分享......
写在前面: 刚做了一个微信端的网页,用到了微信分享,在网上看了好多的资料,发现好多文档都写得云里雾里,让人看的头疼.通过对很多大佬文章的综合整理,才完成了微信分享的部分.所以我想着自己写一篇文章,能让 ...
- 使用微信JSSDK自定义微信分享标题、描述、和图标
最近做一个项目的时候用到微信的分享 ,实现定义分享标题,图片,了解到微信在发布JSSDK后,把包括自定义分享在内的众多网页服务接口进行了统一.如果要想自定义分享自己的网页信息给好友或朋友圈,就最好使用 ...
最新文章
- 同一个类 cannot be cast to_留学热门assignment之 税收筹划类essay
- 希捷期望HAMR实现其营收的增长
- RESTful Android
- 高级驾驶辅助系统ADAS
- Zabbix 3.4.3 使用阿里云短信服务进行报警
- java 更改css_CSS样式更改——文本Content
- koa --- [MVC实现之二]Controller层的实现
- 自己动手开发调试器 01
- 在CDI应用程序中使用@Alternative
- RHEL 8 - 用OpenSCAP工具对容器镜像进行漏洞安全合规扫描,并修复
- 性能测试之二——性能测试的流程
- 【java学习之路】(数据结构篇)002.栈和队列
- 【Ubuntu】检测内存并压力测试
- 车马邮件都慢,一生只够爱一个人
- 测试员,面对自己30岁后的下坡路,我们该何去何从?
- Prometheus入门实践
- 「应用架构」六边型架构:三个原则和一个实现示例
- 中关村-DIY之国外网盘下载测试
- 怎么去掉视频上的水印?快速去除水印或字幕的大神技巧
- Oracle数据库 SQL语句总结大赏
热门文章
- 使用CSS绘制一个平行四边形
- 2021年中国马铃薯种植生产情况及机械化程度分析:单产面积不断扩大,四川省产量居全国首位[图]
- 地形湿度指数(TWI)获取教程
- 玩转Jetson AGX Orin—— Quick Start
- 安装 Visual Studio Community 2015
- 主元排序法c语言写法,快速排序隨即主元法
- were passed to component but could not be automatically inherited because component renders fragment
- nginx反向代理文件下载失败
- 2021大三学习机器学习课程手杖之机器学习基本概念的理解
- git commit后回退方法