解决SPA微信分享失效问题?!

古有ie6,今有微信browser,都是前段的梦魇。
自从上次解决微信spa(单页面应用)分享问题已经一年去了,最近又一次遇到问题。经过仔细分析先吧解决办法记录下来。

根据之前的经验对微信分享相关诡异情况进行一次总结!

IOS直接访问域名,跳转子页面不能分享的问题!!

在ios内通过http://www.abc.com 进入后跳转页面可能出现的分享失效问题!注意不带最后的”/“。
我们可以在代码内进行一次跳转来解决这个问题,注意WKWebview和UIWebview处理方式稍微不一样。

在spa应用框架未初始化的时候调用!

6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (this.isIos() && location.pathname == "/") {
let baseUrl = "/account" + (location.search ? location.search : "");
//
if(window["__wxjs_is_wkwebview"]){
history.replaceState(null, null, baseUrl);
}else{
location.replace(baseUrl);
}
}
//注意排除 微信web开发者工具
let isIos = ()=>{
return /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent) &&
!(navigator.userAgent.indexOf("wechatdevtools") > -1);
}

客户端签名

每次跳转都 需要去服务器请签名,所以如果不考虑安全可以在客户端签名

6
1
2
3
4
5
6
7
8
9
10
11
import uuidV4 from "uuid/v4";
import jsSHA from "jssha/src/sha1";
let nonceStr = uuidV4();
let timestamp = Math.ceil(new Date().getTime() / 1000);
let str1 = "jsapi_ticket=" + tokenModel.jsToken
+ "&noncestr=" + nonceStr + "&timestamp="
+ timestamp + "&url=" + url;
let shaObj = new jsSHA("SHA-1", "TEXT");
shaObj.update(str1);
let signature = shaObj.getHash("HEX");

微信文档有如下说明,但是我认为一般没问题
“3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。”

安卓和ios不同的签名过程

经过反复尝试ios 和 安卓 的签名过程如下

ios: 首次进入的location(在处理了不带路径问题后获取的location),且判定是否已经签名过,如果没签名过就签名,已经签名的url不用签名!
安卓: 每次都使用 当前location.href.split(‘#’)[0] 签名

注意最好在popstate 事件 内触发签名

6
1
2
3
4
5
window.addEventListener('popstate', (event) => {
setTimeout(()=>{
//签名
},0)
}, false);

菜单无辜消失的问题

这个问题很没有规律,但是安卓下非常容易出现,解决办法,在签名成功后立即执行一次显示全部菜单

6
1
wx.showAllNonBaseMenuItem();

完整签名代码示例

6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const shareMap = {};
let share = {
title: '标题', // 分享标题
desc: '描述!', // 分享描述
link: location.href.split('#')[0], // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: location.origin + '/lips_share.jpg', // 分享图标
};
//popstate后调用
const innerInitWeixinConfig = () => {
let tokenModel = {}//启动的时候获取的签名需要信息;
if (!wx || !tokenModel) {
return;
}
let url = this.isIos() ? this._location : location.href.split('#')[0];
let nonceStr = uuidV4();
let timestamp = Math.ceil(new Date().getTime() / 1000);
let str1 = "jsapi_ticket=" + tokenModel.jsToken
+ "&noncestr=" + nonceStr + "&timestamp="
+ timestamp + "&url=" + url;
console.log("签名串", str1);
let shaObj = new jsSHA("SHA-1", "TEXT");
shaObj.update(str1);
let signature = shaObj.getHash("HEX");
if (!this.isIos() || (!shareMap[url])) {
shareMap[url] = url;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: tokenModel.appid, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature,// 必填,签名,见附录1
jsApiList: [
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone',
'startRecord',
'stopRecord',
'onVoiceRecordEnd',
'playVoice',
'pauseVoice',
'stopVoice',
'onVoicePlayEnd',
'uploadVoice',
'downloadVoice',
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'translateVoice',
'getNetworkType',
'openLocation',
'getLocation',
'hideOptionMenu',
'showOptionMenu',
'hideMenuItems',
'showMenuItems',
'hideAllNonBaseMenuItem',
'showAllNonBaseMenuItem',
'closeWindow',
'scanQRCode',
'chooseWXPay',
'openProductSpecificView',
'addCard',
'chooseCard',
'openCard'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(() => {
console.log("微信jssdk 初始化正确", share);
nativeShare();
});
wx.error(function (res) {
console.log("微信jssdk 初始化失败", res);
});
} else {
nativeShare();
}
};
const nativeShare = () => {
if (share) {
wx.onMenuShareTimeline(this.share);
wx.onMenuShareAppMessage(this.share);
wx.onMenuShareQQ(this.share);
wx.onMenuShareWeibo(this.share);
wx.onMenuShareQZone(this.share);
}
wx.showAllNonBaseMenuItem();
}

参考

  1. 微信官方有下面这段不明觉厉的说明!

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

参考地址: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

  1. vue-router 项目的讨论 https://github.com/vuejs/vue-router/issues/481