微信 js-sdk 完成 H5自定义页面分享

1,071 阅读4分钟

之前做一个新闻项目的详情页微信二次分享,开发阶段略显痛苦,google到的博客都是一半一半的,加之对微信公众号的配置不熟悉,绕了很多弯路,现在慢慢整理下来。

微信二次分享需要依赖公众号配置,这样在H5页面被分享出去之后,别人看到的就不只是一个简单的页面中包裹的标题加一个url,而是可以自定义title和内容以及图标的具有一定美观度的分享块。

1. 获取测试号相关信息

进入微信公众帐号测试号申请系统 (mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index)

只是为了测试这个文档转发,只需要获取「测试号信息」和配置「JS接口安全域名」

2.签名算法

有了上面的两个信息,就可以完成一个「签名算法」服务

// express 实现
app.use('/sdWxService', async function (req, res, next) {
  const {url} = req.query;
  const access_token = await axios.get(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${AppID}&secret=5397a76acffd10116413dbd741849c1c`).then(
    (res) => {
      const {access_token} = res.data;
      return access_token;
    });
  const ticket = await axios.get(`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`).then((res) => {
    console.log(res.data)
    return res.data.ticket;
  });
  let noncestr = uuidv4();
  let jsapiTicket = ticket
  let timestamp = moment().unix().toString()
  // 此处noncestr为全部小写
  let string = `jsapi_ticket=${jsapiTicket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`
  let signature = crypto.createHash('sha1').update(string).digest('hex')
​
  res.json({
    status: 200,
    data: {
      jsapiTicket,
      appId: AppID,
      timestamp,
      nonceStr: noncestr, // 注意此处大小写
      signature,
  }
  })
});

有几个常见问题需要记录下

  • timestamp、 nonceStr 都必须是字符串
  • 确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致
  • 如果是正式的公众号,确保一定缓存access_token和jsapi_ticket(测试号就先不关心这个了)
  • timestamp 是10位时间戳
  • timestamp与用以签名中的timestamp一致
  • url一定要注意:不进行URL 转义、签名用的url必须是调用JS接口页面的完整URL
  • 确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
  • 前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent
  • 注意:noncestr,在拼接signature原串时,这个key全部小写;但是前端在config中配置时,需要驼峰的nonceStr
  • 对于最终产生的信息可以使用 微信 JS 接口签名校验工具 (mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign)
  • 关于接口签名校验工具校验一致 但是仍然报 invalid signature 错误的,一定要认真检查上述的几个注意事项,还有developers.weixin.qq.com/doc/offiacc…

3. H5页面配置

首先页面要引入微信的sdk,有两种方式,这里也顺便贴一下:

方式一

<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js />

方式二

npm install weixin-js-sdk
​
/* 使用CommonJs规范引入 */const wx = require('weixin-js-sdk');
​
/* 使用ES6模块引入 */import wx from 'weixin-js-sdk';
  1. H5分享模块代码
import wx from 'weixin-js-sdk';
import axios from 'axios';
import moment from 'moment';
import _ from 'lodash';
​
const url = encodeURIComponent(window.location.href);
​
const getSignature = () =>
  axios
    .get(
      `http://192.168.0.106:4003/sdWxService?url=${url}`,
    )
    .then(res => res.data);
​
export default async function initWeChat() {
  const {
    signature,
    nonceStr,
    timestamp,
    appId,
    jsapiTicket,
  } = await getSignature();
  
  wx.config({
    // debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId, // 必填,公众号的唯一标识
    jsApiList: [
      'checkJsApi',
      'onMenuShareTimeline',
      'onMenuShareAppMessage',
      'onMenuShareQQ',
      'onMenuShareWeibo',
    ],
    nonceStr, // 必填,生成签名的随机串
    signature, // 必填,签名
    timestamp, // 必填,生成签名的时间戳
  });
}
export const updateWeChatShareData = () => {
  initWeChat();
  // TODO:确认华安提供的图片连接const wxShareData = {
    title: '活动页面', // 分享标题
    desc: '活动页面---111', // 分享描述
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl:
      'https://res.wx.qq.com/a/wx_fed/assets/res/OTE0YTAw.png', // 分享图标
  };
​
  wx.ready(() => {
    // 需在用户点击分享按钮前就先调用
    wx.updateAppMessageShareData(wxShareData);
    wx.updateTimelineShareData(wxShareData);
    wx.onMenuShareAppMessage(wxShareData);
    wx.onMenuShareTimeline(wxShareData);
  });
};
updateWeChatShareData();

最终分享的结果截图(微信开发者工具中调试截图),可以看出分享的title已经设置为H5模块中定义的title值。

还有一种情况是要禁止微信中页面的分享,参考下面代码段

这个方法好像有问题了,WeixinJSBridge.call会报错了,使用下面的方法

function onBridgeReady() {
  window.WeixinJSBridge.call('hideOptionMenu');
}
​
if (typeof WeixinJSBridge === 'undefined') {
  if (document.addEventListener) {
    document.addEventListener(
      'WeixinJSBridgeReady',
      onBridgeReady,
      false,
    );
  } else if (document.attachEvent) {
    document.attachEvent(
      'WeixinJSBridgeReady',
      onBridgeReady,
    );
    document.attachEvent(
      'onWeixinJSBridgeReady',
      onBridgeReady,
    );
  }
} else {
  onBridgeReady();
}

使用API提供的方法实现隐藏微信、朋友圈、QQ等分享,初始化时需要在wx.ready(() => {})的回调中实现

wx.hideMenuItems({
  menuList: [
    'menuItem:share:appMessage',
    'menuItem:share:timeline',
    'menuItem:share:qq',
    'menuItem:share:weiboApp',
    'menuItem:share:facebook',
    'menuItem:share:QZone',
    'menuItem:favorite',
  ], // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
});

也可以动态展示出来

wx.showMenuItems({
  menuList: [
    'menuItem:share:appMessage',
    'menuItem:share:timeline',
    'menuItem:share:qq',
    'menuItem:share:weiboApp',
    'menuItem:share:facebook',
    'menuItem:share:QZone',
    'menuItem:favorite',
  ], // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
});

wx.config中的jsApiList需要配置hideMenuItems和showMenuItems

欢迎扫码关注作者公众号