之前做的一个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几个参数需要详细说明一下:

  1. timestamp  生成签名的时间戳  create_nonce_str()
  2. nonceStr  随机生成的字符串 create_timestamp()
  3. 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 +"&timestamp=" + 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 +"&timestamp=" + 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自定义微信分享效果相关推荐

  1. 手把手带你使用JS-SDK自定义微信分享效果

    前言 刚进入一家新公司,接到的第一个任务就是需要需要自定义微信分享的效果(自定义缩略图,标题,摘要),一开始真是一脸懵逼,在网上搜索了半天之后大概有了方案.值得注意的是一开始搜索到的解决方案全是调用微 ...

  2. 带你使用JS-SDK自定义微信分享效果

    本文转载于:猿2048网站https://www.mk2048.com/blog/blog.php?id=jhh1ib&title=%E5%B8%A6%E4%BD%A0%E4%BD%BF%E7 ...

  3. js实现自定义微信分享

    1.安装相关依赖 1.1在需要调用JS接口的页面引入如下JS文件 (支持https):<script src="http://res.wx.qq.com/open/js/jweixin ...

  4. android微信分享怎么自定义样式,自定义微信分享样式设置教程

    一.功能效果 自定义微信分享可以设置个性化的分享图片.标题.描述,让分享内容更加受到用户的喜爱和欢迎. 二.功能说明 [版本]网站标准版及以上 [前提]1.需要授权已认证的公众号(支持服务号.订阅号) ...

  5. android微信分享怎么自定义样式,自定义微信分享样式教程

    使用场景: 当网站浏览者访问你的网站的时候,情不自禁分享.然而,样式怎么这么挫? 分享别人的网站链接,却是这样的样式,为什么呢? 答案:你没有设置"自定义 微信分享样式" 共有三个 ...

  6. H5 -- 自定义微信分享第三方页面链接的标题和小缩略图

    需求:自定义微信分享第三方页面链接的标题和小缩略图(如图) 2018.6.4更新线 - - - - - - - - - - - - - - - - - - 更新:微信6.5.5版本以后调整了分享规则, ...

  7. android sdk引入 微信分享_android 调用本地微信自定义多图分享朋友圈,可放在share sdk中一起使用...

    最终的效果图,右下角微信多图为自定义调用系统分享,分享到微信. 在你能正常调用share sdk的时候想在原本的基础上加自定义的分享非常的简单. 它的官网已经给出了代码,但是给的不是很清楚. lz毕竟 ...

  8. 简单粗暴教你在VUE中引入微信SDK 调用微信分享、朋友圈分享、QQ分享......

    写在前面: 刚做了一个微信端的网页,用到了微信分享,在网上看了好多的资料,发现好多文档都写得云里雾里,让人看的头疼.通过对很多大佬文章的综合整理,才完成了微信分享的部分.所以我想着自己写一篇文章,能让 ...

  9. 使用微信JSSDK自定义微信分享标题、描述、和图标

    最近做一个项目的时候用到微信的分享 ,实现定义分享标题,图片,了解到微信在发布JSSDK后,把包括自定义分享在内的众多网页服务接口进行了统一.如果要想自定义分享自己的网页信息给好友或朋友圈,就最好使用 ...

最新文章

  1. 同一个类 cannot be cast to_留学热门assignment之 税收筹划类essay
  2. 希捷期望HAMR实现其营收的增长
  3. RESTful Android
  4. 高级驾驶辅助系统ADAS
  5. Zabbix 3.4.3 使用阿里云短信服务进行报警
  6. java 更改css_CSS样式更改——文本Content
  7. koa --- [MVC实现之二]Controller层的实现
  8. 自己动手开发调试器 01
  9. 在CDI应用程序中使用@Alternative
  10. RHEL 8 - 用OpenSCAP工具对容器镜像进行漏洞安全合规扫描,并修复
  11. 性能测试之二——性能测试的流程
  12. 【java学习之路】(数据结构篇)002.栈和队列
  13. 【Ubuntu】检测内存并压力测试
  14. 车马邮件都慢,一生只够爱一个人
  15. 测试员,面对自己30岁后的下坡路,我们该何去何从?
  16. Prometheus入门实践
  17. 「应用架构」六边型架构:三个原则和一个实现示例
  18. 中关村-DIY之国外网盘下载测试
  19. 怎么去掉视频上的水印?快速去除水印或字幕的大神技巧
  20. Oracle数据库 SQL语句总结大赏

热门文章

  1. 使用CSS绘制一个平行四边形
  2. 2021年中国马铃薯种植生产情况及机械化程度分析:单产面积不断扩大,四川省产量居全国首位[图]
  3. 地形湿度指数(TWI)获取教程
  4. 玩转Jetson AGX Orin—— Quick Start
  5. 安装 Visual Studio Community 2015
  6. 主元排序法c语言写法,快速排序隨即主元法
  7. were passed to component but could not be automatically inherited because component renders fragment
  8. nginx反向代理文件下载失败
  9. 2021大三学习机器学习课程手杖之机器学习基本概念的理解
  10. git commit后回退方法