基于uni-app,vue-ts,h5公众号开发,在接入微信自定义分享的时候出现了在Android上一切正常,但是在ios端调用wx.config的时候总是失败。
具体解决过程如下:
目录
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签名错误。建议按如下顺序检查:
- 确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
- 确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
- 确认url是页面完整的url(请在当前页面alert(==location.href.split('#')[0]==)确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
- 确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
- 确保一定缓存access_token和jsapi_ticket。
- 确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。
the permission value is offline
- verifying这个错误是因为config没有正确执行,或者是调用的JSAPI没有传入config的jsApiList参数中。建议按如下顺序检查:
- 确认config正确通过。
- 如果是在页面加载好时就调用了JSAPI,则必须写在wx.ready的回调中。
- 确认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)