微信公众号自定义分享,ios签名失败,安卓可以正常分享

3,044 阅读5分钟
基于uni-app,vue-ts,h5公众号开发,在接入微信自定义分享的时候出现了在Android上一切正常,但是在ios端调用wx.config的时候总是失败。
具体解决过程如下:

目录

  1. JS-SDK-API调用以及配置
  2. 常见错误及解决方案
  3. 微信内问题强调

JS-SDK-API调用以及配置

  • wx.config-接口配置;service层, 请求后端签名接口,获取签名信息。

import baseRequest from '~/utils/request'

class WeChatServivce extends BaseRequest {

  constructor() {
    super()
  }

  /**
   * 获取签名配置信息
   * url: 用来签名的url
   */
  querySdkSignSettings (url: string) {
    return this.post(`we-chat/js-sign`,{url})
  }
}

export default new WeChatServivce()

  • JS-SDK-API配置类

import WeChatServivce from '~/service/weChatServivce'

class JsSDKPluginClass {
    
    /**
     * 页面调用-微信api
     * @param {String} signUrl 用来签名的url
     * @param {Object} options 自定义分享对象信息
     * @param {String} apiType 调用api类型, share
     */
    handleWxJsSdkAPI (params: {
        signUrl: string,
        options: Object,
        apiType: string
    }) {
        return new Promise((resolve, reject) => {
            WeChatServivce.querySdkSignSettings(signUrl)
              .then(res => {
                    if (res) {
                      if (apiType === 'share') {
                        // 分享
                        handleShareJsApi(res, options)
                      } else if (apiType === 'scan') {
                        // 微信扫码API
                        // do something
                      } else if (apiType === 'location') {
                        // 微信定位API
                        // do something
                      } else if (apiType === 'hideItem') {
                        // 隐藏微信菜单面板按钮API
                        // do something
                      }
                      // wait ...
                    }
                }).catch(err => {
                    reject(`err-sign: ${err}`)
                })
        })
    }
    
    /**
     * 微信config配置,调用所有api都必须先注册配置
     * @param {object} jssdk-jsapi 签名配置信息
     * @param {object} jsApiList 需要使用的api,必须在此对象内注册才能生效,更多api目录请查阅官方文档附录3
     */
    handleWxConfig (jssdk: any) {
       wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: jssdk.appId,
        timestamp: parseInt(jssdk.timestamp),
        nonceStr: jssdk.nonceStr,
        signature: jssdk.signature,
        jsApiList: [
          'updateAppMessageShareData',
          'updateTimelineShareData',
          'scanQRCode',
          'hideMenuItems',
          'showMenuItems',
          'hideOptionMenu',
          'getLocation'
        ]
      })   
    }
    
    /**
     * 微信分享-微信分享朋友,朋友圈等
     * @param {object} options 自定义分享信息{title, desc, link, imgUrl}
     * @param {object} jssdk 签名配置信息
     */
    async handleShareJsApi (jssdk: any, options: any) {
        await handleWxConfig(jssdk)
      wx.ready(function() {
        let opts = options
        // 分享给微信朋友
        wx.updateAppMessageShareData({
          title: opts.title, // 分享标题
          desc: opts.desc, // 分享描述
          link: opts.link, // 分享链接
          imgUrl: opts.imgUrl, // 分享图标
          success: function() {
            console.log('success')
          },
          cancel: function() {
            console.log('cancel')
          },
          fail: function() {
            console.log('fail')
          },
          complete: function() {
            console.log('complete')
          },
        })
        // 分享到微信朋友圈
        wx.updateTimelineShareData({
          title: opts.title, // 分享标题
          link: opts.link, // 分享链接
          imgUrl: opts.imgUrl, // 分享图标
          success: function() {
            // 用户确认分享后执行的回调函数
            console.log('success')
          },
          cancel: function() {
            // 用户取消分享后执行的回调函数
            console.log('cancel')
          },
          fail: function() {
            console.log('fail')
          },
          complete: function() {
            console.log('complete')
          },
        })
      })
      wx.error(function(res: any) {
        // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
        console.error('wxjsapi-wx.error=', res)
      })
    }
}

export default new JsSDKPluginClass()


  • 异步调用sdk

    // sdk异步调用方法 common.ts
    
    /**
     * 微信sdk jweixin 异步加载,目前最新版本1.6
     * @param {*} callback api接口
     */
    export const handleLoadScript = (callback: any) => {
      const src =  `https://res.wx.qq.com/open/js/jweixin-1.6.0.js`
      if (!(typeof callback === 'function')) {
        callback = function () { }
      }
      var check = document.querySelectorAll(`script[src="${src}"]`)
      if (check.length > 0) {
        check[0].addEventListener('load', function () {
          callback()
        })
        callback()
        return
      }
      var script = document.createElement('script')
      var head = document.getElementsByTagName('head')[0]
      script.type = 'text/javascript'
      script.charset = 'UTF-8'
      script.src = src
      if (script.addEventListener) {
        script.addEventListener(
          'load',
          function () {
            callback()
          },
          false
        )
      } else if (script.attachEvent) {
        script.attachEvent('onreadystatechange', function () {
          if (window.event) {
            let target = window.event.srcElement
            if (target && target.readyState === 'loaded') {
              callback()
            }
          }
        })
      }
      head.appendChild(script)
    }
    
    /**
     * name 需要获取的参数名
     */
    export function getUrl(name) {
        return (
          decodeURIComponent(
            (new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(
              location.href
            ) || [, ''])[1].replace(/\+/g, '%20')
          ) || null
        )
    }

  • 页面使用场景一:支付成功后邀请好友参与活动,此场景目前IOS的问题支付成功页面跳转:window.location.href||replace

    // payResult.vue
    // 在这个场景用的是replace
    // 比较坑的点:支付成功后跳转到支付结果页的方式必须是window.location.replace,因此需要用到getUrl获取链接带的入参
    // 使用window.location.replace()跳转,因为IOS微信的浏览器跳转页面时,URL不替换的问题导致,可能导致用来签名的url获取不正确
    import { handleLoadScript, getUrl } from '~/utils/common'
    import JsSDKPluginClass from '~/utils/wechat/JsSDKPluginClass'
    
    onShow () {
        // 示例:查询订单明细成功,调用分享信息
        demoService.queryOrderDetail({orderId: getUrl('orderId')}).then((res)=>{
          
          // 调用分享
          // 动态获取签名url,可查看常见问题说明
          const signUrl = location.href.split('#')[0]  // location.href.split('&from')[0] 
          const shareUrl = '' // 需要发起分享的链接
          handleLoadScript(() => {
            JsSDKPluginClass.handleWxJsSdkAPI(signUrl, 'share', {
              title: `需自定义标题`,
              desc: `需自定义副标题`,
              link: shareUrl,
              imgUrl: '' // 注意,图片地址必须是可访问的,不然前面配置没问题,但是自定义分享的效果还是不正确
            })
          })
          
        })
    }

  • 页面使用场景二:商品类信息分享, 注意点还是要动态获取用来签名的url

    // detail.vue
    import { handleLoadScript } from '~/utils/common'
    import JsSDKPluginClass from '~/utils/wechat/JsSDKPluginClass'
    
    onShow () {
        // 示例:查询商品详情,调用分享信息
        demoService.queryGoodsDetail({productId: ''}).then((res)=>{
          
          // 调用分享
          // 动态获取签名url,可查看常见问题说明
          const signUrl = location.href.split('#')[0]  // location.href.split('&from')[0] 
          const shareUrl = '' // 需要发起分享的链接
          handleLoadScript(() => {
            JsSDKPluginClass.handleWxJsSdkAPI(signUrl, 'share', {
              title: `需自定义标题`,
              desc: `需自定义副标题`,
              link: shareUrl,
              imgUrl: '' // 注意,图片地址必须是可访问的,不然前面配置没问题,但是自定义分享的效果还是不正确
            })
          })
          
        })
    }

常见错误及解决方案

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

  1. 确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
  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),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。

the permission value is offline

  • verifying这个错误是因为config没有正确执行,或者是调用的JSAPI没有传入config的jsApiList参数中。建议按如下顺序检查:
  1. 确认config正确通过。
  2. 如果是在页面加载好时就调用了JSAPI,则必须写在wx.ready的回调中。
  3. 确认config的jsApiList参数包含了这个JSAPI。

以上问题,在IOS内常遇到,其实官方文档有此说明,重点摘录下,其他问题,可以在官方文档查看更多说明 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#66

微信内问题强调

  • 问题描述:

在PC端和手机浏览器中router.replace() or router.push()能够正常使用,页面的地址和页面都正常显示;
但是在微信中,从/a页面通过router.push('/b')跳转到/b页面后,页面正常,但是复制浏览器的地址会发现其地址仍为/a;
选择在浏览器打开发现也是显示的/a的页面。
这应该是微信浏览器那边的问题,微信浏览器只会记住你第一次进来的地址;

官方github-issue
https://github.com/Tencent/weui/issues/125


  • 解决方案:

如果需要分享的:跳转用(window.location.replace())此方式,当前需要发起分享页面,用来签名的url,用location.href.split('#')[0]动态获取url方式;

只是替换url的也可用:
history.replaceState(null, '', url)
history.pushstate(null, '', url)

⬆ 回到顶部