微信JSSDK方法封装

588 阅读9分钟

微信JSSDK方法封装

微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力。

1. JSSDK使用步骤

步骤一:绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

步骤二:引入JS文件

在需要调用JS接口的页面引入如下JS文件,(支持https): res.wx.qq.com/open/js/jwe…

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问: res2.wx.qq.com/open/js/jwe… (支持https)。

备注:支持使用 AMD/CMD 标准模块加载方法加载

步骤三:通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

wx.config({
  debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  appId: '', // 必填,公众号的唯一标识
  timestamp: , // 必填,生成签名的时间戳
  nonceStr: '', // 必填,生成签名的随机串
  signature: '',// 必填,签名
  jsApiList: [] // 必填,需要使用的JS接口列表
});

注意:如果使用的是小程序云开发静态网站托管的域名的网页,可以免鉴权直接跳任意合法合规小程序,调用 wx.config 时 appId 需填入非个人主体的已认证小程序,不需计算签名,timestamp、nonceStr、signature 填入非空任意值即可。

步骤四:通过ready接口处理成功验证

wx.ready(function(){
   // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

步骤五:通过error接口处理失败验证

wx.error(function(res){
  // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});

2. 接口调用说明

JSSDK支持的接口可在微信官方文档中查找,所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

  1. success:接口调用成功时执行的回调函数。
  2. fail:接口调用失败时执行的回调函数。
  3. complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
  4. cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
  5. trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。

备注:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。

以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:

调用成功时:"xxx:ok" ,其中xxx为调用的接口名

用户取消时:"xxx:cancel",其中xxx为调用的接口名

调用失败时:其值为具体错误信息

如:分享接口(自定义“分享给朋友”及“分享到QQ”按钮的分享内容(1.4.0))

wx.ready(function () {   //需在用户可能点击分享按钮前就先调用
  wx.updateAppMessageShareData({ 
    title: '', // 分享标题
    desc: '', // 分享描述
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function (res) {
       // 设置成功
       console.log('分享', res);
    },
    fail:  function (err) {
       // 设置失败
       console.log('分享失败', err);
    },
  })
}); 
image.png

3. 基于微信接口再次封装

1:调用后端的接口获取需要的签名信息
在步骤一完成后,因为签名算法逻辑是要在后端实现的, 所以我们调用后端的接口获取需要的签名信息,用于config接口注入权限验证配置,方式如下:

import { getShareElement } from '@/api';

// 服务端签名接口
const getSignature = (callback: {
  (data: any): void;
  (arg0: {
    appId: string; // 必填,公众号的唯一标识
    timestamp: string; // 必填,生成签名的时间戳
    nonceStr: string; // 必填,生成签名的随机串
    signature: string;
  }): void;
}) => {
  const params = {
    url: window.location.href,
  };
  getShareElement(params).then((res: any) => {
    const { data, code } = res?.data || {};
    if (code === '10000') {
      callback({
        appId: data.appId, // 必填,公众号的唯一标识
        timestamp: data.timestamp, // 必填,生成签名的时间戳
        nonceStr: data.noncestr, // 必填,生成签名的随机串
        signature: data.signature, // 必填,签名
      });
    }
  });
};

2:初始化sdk配置
调用服务端签名接口后, 将返回的签名信息作为微信config接口参数,注入权限验证配置

import wx from 'weixin-js-sdk';

const wxConfig = {
  // 调试模式
  debug: false,
  url: '',
  // 需要使用的JS接口列表
  jsApiList: [
    'updateAppMessageShareData', // 分享给朋友及分享到QQ -- 在需要自定义分享的页面中调用
    'updateTimelineShareData', // 分享到朋友圈及分享到QQ空间  -- 在需要自定义分享的页面中调用
    'closeWindow', // 关闭页面事件
    'getLocation', // 获取位置信息
    'openLocation', // 使用微信内置地图查看位置接口
    'scanQRCode', // 微信扫码
    'chooseImage', // 选择图片
    'uploadImage', // 上传图片
    'downloadImage', // 下载图片
    'startRecord', // 开始录音
    'stopRecord', // 停止录音
    'uploadVoice', // 上传语音
    'playVoice', // 播放语音
    'pauseVoice', // 暂停语音
    'stopVoice', // 停止语音
    'downloadVoice', // 下载语音
  ],
  openTagList: [],
  initConfig(callback: () => void) {
    // 服务端签名接口
    getSignature((data: any) => {
      // 通过config接口注入权限验证配置
      wx.config({
        ...data,
        debug: this.debug, // debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        jsApiList: this.jsApiList, // 必填,需要使用的JS接口列表
        openTagList: this.openTagList,
      });
      // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
      wx.ready(() => {
        this.isReady = true;
        this.url = window.location.href;
        callback();
      });

      wx.error((err: any) => {
        console.log('wx_err', err);
      });
    });
  },
}

export default wxConfig;

3:调用微信api时,增加校验方式,判断是否是微信环境等

import wx from 'weixin-js-sdk';

const wxConfig = {
    isWechat() {
        const ua = window.navigator.userAgent.toLowerCase();
        return ua.match(/micromessenger/i) == 'micromessenger';
      },
    checkSdkEnv(callback: () => void) {
        if (!this.isWechat()) {
          return;
        }
        // 页面url变更,需要重新注入权限验证配置
        if (!this.isReady || this.url !== window.location.href) {
          this.initConfig(callback);
        } else {
          wx.ready(() => {
            callback();
            // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
          });
        }
      },
  };
  
export default wxConfig;

4:封装jsdk提供的接口方法


const wxConfig = {
    // 分享接口
      share(data: { title: string; desc: string; image: string }, callback: (arg0: any) => void) {
        this.checkSdkEnv(() => {
          const shareData = {
            title: data.title, // 分享标题
            desc: data.desc, // 分享描述
            link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
            imgUrl: data.image, // 分享图标
            success(res: any) {
              callback(res);
            },
            cancel(res: any) {
              callback(res);
            },
          };
          wx.updateAppMessageShareData(shareData); // 分享给朋友及分享到QQ -- 在需要自定义分享的页面中调用
          wx.updateTimelineShareData(shareData); // 分享到朋友圈及分享到QQ空间  -- 在需要自定义分享的页面中调用
        });
      },
      // 选择图片
      chooseImage(callback: (arg0: any) => void) {
        this.checkSdkEnv(() => {
          wx.chooseImage({
            count: 1, // 默认9
            sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
            sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
            success(res: any) {
              callback(res);
            },
          });
        });
      },
}
export default wxConfig;

5:在页面中使用

import wx from './wx';

useEffect(() => {
    /**
     * 分享
     */
    wx.share(
      {
        title: '分享标题',
        desc: '分享描述',
        image: '分享图标',
        link: window.location.href,
      },
      (res) => {
        console.log('分享', res);
      },
    );
  }, []);

  /**
   * 选择手机图片
   */
  const handleSelectImg = () => {
    wx.chooseImage((res) => {
      setState(res);
      console.log('res', res);
    });
  };
  

4.常见问题

1:接口报“config:invalid url domain”错误!

无效的url域名,当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,如果使用了端口号,则配置的绑定域名也要加上端口号,一个appid可以绑定三个有效域名,配置步骤如下:

微信公众平台后台→设置→公众号设置→功能设置→JS接口安全域名

image.png

输入域名即可

2.invalid signature签名错误。建议按如下顺序检查:

  1. 确认签名算法正确,可用mp.weixin.qq.com/debug/cgi-b… 页面工具进行校验。
  2. 确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
  3. 确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
  4. 确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
  5. 确保一定缓存access_token和jsapi_ticket。
  6. 确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。