思路
h5 微信分享的官方文档在 这里,如果链接挂了,可以按照一下路径去查找:【微信开放社区】 - 【文档】 - 【公众号】 - 【微信网页开发】 - 【JS-SDK 说明文档】找到。
从上面可以看出,网页分享必须要有公众号,公众号分两种,服务号和订阅号,必须要先注册。
注册后就是按照官方文档进行 【绑定域名】 的操作:
步骤一:绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS 接口安全域名”。
备注:登录后可在“开发者中心”查看对应的接口权限。
绑定完就引入 sdk 文件:
步骤二:引入 JS 文件
在需要调用 JS 接口的页面引入如下 JS 文件,(支持 https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js
微信会 sdk 会在全局暴露一个 wx 对象供我们访问,使用如 window.wx
。
但是但是,现在的 sdk 根本用不成,需要进行权限配置。 权限配置全部丢给后端做,我特么把文档读完了才看到这部分是后端的内容,垃圾文档。反正就是请求 access_token,然后又去取啥 jsapi_ticket 票据,然后拿着票据又特么用随机字符串、时间戳和当前页面的 url 来加密获取签名,反正就全是安全的操作。注意,这部分逻辑不能写在客户端,让后端写接口。
注意这个签名的流程里面需要当前页面的 url,一般后端会让前端发给他们,其实后端也可以从请求报文里面拿,看业务需求。
然后就是通过后端返回的相关数据进行微信权限验证:
步骤三:通过 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 接口列表
});
大致就是那么回事,该让后端返回的就让后端返回就行。注意正常开发不要开启 debug,debug 只是用来测试是否正常完成注册。
注册完成就可以使用了:
步骤四:通过 ready 接口处理成功验证
步骤五:通过 error 接口处理失败验证
踩坑集锦
链接不能直接作用与分享
我特么都把分享流程写完了,而且 debug 也跑通了,问题他么的我点击链接进去分享出来就是不成功。后来才知道,必须使用扫码打开才行。所以测试时候要把准备的页面转化为二维码,然后扫码打开。
解决:
chrome 自带二维码生成,不过只支持 250 字符以内,真的是个二百五。然后我又用了 草料。然后扫码打开可以完成测试。
url 参数不能携带特殊字符,比如花括号 “{}”
这也是个大坑,我在网上居然没找到相关踩坑。我的分享网址的查询参数上有 json 字符串,所以自然好多的花括号 {}
,这特么微信文档也不说,估计是个 bug。
解决:
本来我尝试把发给后端的 url 使用 encodeURI 把 json 字符串转义了,结果特喵的还是不行,匹配当前页面的 url 和签名里的 url 不一致。所以必须把当前 url 重定向到一个已经转义后的 url 上。
那就重定向咯,我在进入页面直接进行判断是否转义,没转义就重定向到转义后的 url 上,就这样,才最终好使。
我写了那么一段无用代码才解决这个 bug:
/** 修复微信屎一样的 bug,meta 是 json 类型,含有花括号 {},微信他么用来加密使用的 url 解析会出错,分享导致失败。如果发给后端的 url 使用转义后的,微信加密又会不匹配。最后无法,直接重定向到一个解析后的 url,使用该 url 来作为分享链接。encode 字段用来标识该 url 是转义过的,满足微信 sdk 调用要求。 */
if (!params.get("encode") && uaCheck().isWeChatBrowser) {
const lo = window.location;
lo.href = `${lo.origin}${lo.pathname}?type=${type}&payload=${payload}&meta=${encodeURI(meta!)}&encode=1`;
}
上面代码中,params 就是 URLSearchParams 的实例,uaCheck 来源于库 ua-check。
代码实现
项目在 react + ts 中,微信全局 api 需要现在全局上定义个类型,在 global.d.ts 注册微信的全局引用:
export const thisIsAModule = true; // <-- definitely in a module
declare global {
var wx: any;
}
接着编写分享文件:
我创建了个 wechatShare.ts 文件来封装相关微信分享逻辑:
import { apiGetUserShareWechatSignature } from "lib/api";
/** 加载 wechat sdk */
function wechatSDKLoad(): Promise<any> {
if (window.wx) return Promise.resolve(window.wx);
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = `https://res.wx.qq.com/open/js/jweixin-1.6.0.js`;
document.head.append(script);
script.onload = () => resolve(window.wx);
});
}
/** 微信 api 是否已经准备好了 */
let ready = false;
/**
*
* @param cb 微信 api 准备好的时候的回调函数
*/
export async function wechatReady(cb: (wx: any) => void) {
// 二次执行直接执行回调
if (ready) return void cb(window.wx);
// 获取签名并加载微信 sdk
const [res, wechat] = await Promise.all([apiGetUserShareWechatSignature(window.location.href), wechatSDKLoad()]);
const d = res.data.data;
wechat.config({
debug: false,
appId: d.appId,
timestamp: d.timestamp,
nonceStr: d.noncestr,
signature: d.signature,
jsApiList: [
"updateAppMessageShareData", // 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
"updateTimelineShareData", // 自定义“分享到朋友圈”及“分享到 QQ 空间”按钮的分享内容
],
});
wechat.ready(() => {
cb(wx);
ready = true;
});
wechat.error((e: Error) => console.error(e));
}
interface ShareParams {
title: string; // 分享标题
desc: string; // 分享描述
link: string; // 分享链接,该链接域名或路径必须与当前页面对应的公众号 JS 安全域名一致
imgUrl: string; // 分享图标
success?(): void; // 设置成功
}
/** 分享给朋友或到朋友圈圈 */
export function wechatShare(params: ShareParams) {
wechatReady((wechat) => {
wechat.updateAppMessageShareData(params);
wechat.updateTimelineShareData(params);
});
}
使用就比较方便了,在需要使用的地方对 wechatShare
进行进入,然后执行就行:
wechatShare({
title: "分享的标题",
desc: "分享的描述",
imgUrl: "图片路径",
link: window.location.href.split("#")[0], // 不能包含 url 的片段部分,不然也会报错
});
打完收工,垃圾微信 sdk 再说一次!