前言提示:本文记录的是使用uniapp开发的H5+APP项目,H5端使用微信自定义分享功能,文中有关APP的兼容,如果不需要兼容APP的可以忽略
一、引入
首先安装 jweixin-module 包
npm install jweixin-module --save
二、封装工具方法
为了方便使用,新建一个 wechat.js 文件:
// #ifdef H5
import http from "./http";
import wx from "jweixin-module";
// 需要调用的微信api列表
export const WXAPI = [
"chooseWXPay",
"updateAppMessageShareData",
"updateTimelineShareData",
"onMenuShareAppMessage",
"scanQRCode",
"getLocation",
];
// 微信分享朋友默认配置
const shareOptionsDefalut = {
title: "这是标题", // 分享标题
desc: "这是描述", // 分享描述
imgUrl: "图片地址", // 封面图
};
export default {
/**
* 判断是否在微信中
*/
isWechat() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/micromessenger/i) == "micromessenger") {
return true;
} else {
return false;
}
},
/**
* 通过config接口注入权限验证配置
* @param {Object} cb 需要执行的函数
*/
getWxConfig(cb) {
http("POST", "/shop/wx/shareFriend", {
url: encodeURIComponent(window.location.href),
}).then((res) => {
if (res.success) {
wx.config({
debug: false, // 是否开启调试模式
appId: res.data.appId, // 必填,公众号的唯一标识
timestamp: res.data.timestamp, // 必填,生成签名的时间戳
nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.signature, // 必填,签名,见附录1
jsApiList: WXAPI,
});
if (cb) {
cb();
}
}
});
},
/**
* 唤起微信分享
* @param {Object} sharedata 分享需要的参数
* @param {Object} cb 成功回调
* @param {Object} errorCb 失败回调
*/
callWexinShare(
sharedata = shareOptionsDefalut,
cb = () => {},
errorCb = () => {}
) {
this.getWxConfig(() => {
wx.ready(() => {
console.log("---config注入成功---,开始使用sdk接口");
// 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
wx.updateAppMessageShareData({
title: sharedata.title || shareOptionsDefalut.title,
desc: sharedata.desc || shareOptionsDefalut.desc,
// 微信对分享图有限制,具体看踩坑
imgUrl:
(sharedata.imgUrl || shareOptionsDefalut.imgUrl) +
"?x-oss-process=image/resize,w_120,m_lfit/format,png/quality,q_80",
link: window.location.href,
success: (res) => {
cb(res);
},
cancel: (cancelMsg) => {
errorCb(cancelMsg);
},
});
// 自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容
wx.updateTimelineShareData({
title: sharedata.title || shareOptionsDefalut.title,
imgUrl:
(sharedata.imgUrl || shareOptionsDefalut.imgUrl) +
"?x-oss-process=image/resize,w_120,m_lfit/format,png/quality,q_80",
link: window.location.href,
success: (res) => {
cb(res);
},
cancel: (cancelMsg) => {
errorCb(cancelMsg);
},
});
});
wx.error((res) => {
console.log("---注入失败,查看失败原因---", res);
});
});
},
};
// #endif
-
对工具函数简单说明下
- isWechat 判断当前是否是微信环境
- getWxConfig(关键) 请求后端接口,注入配置信息
- callWexinShare 对微信分享接口的二次封装
-
注意事项
- 整个 wechat.js 文件里最好用条件编译包裹起来【#ifdef H5、#endif】,不然打包 APP 后会出现报错(APP 没有 window 对象)
- callWexinShare 函数的成功回调和失败回调参数都需要有一个默认值,不然 updateAppMessageShareData 的 success 回调中会报错‘cb is not defined’(这个当时我也没注意到,不过在 onMenuShareTimeline 这个接口倒不会报错,怪不得是即将废弃的接口,新接口更加规范了)
三、页面中使用
- 在 main.js 中将 wechat 绑定在 vue 全局对象上,方便后续使用
import wechat from "@/utils/wechat.js";
Vue.prototype.$wechatSdk = wechat;
- 在 App.vue 中的 onLaunch 周期里,使用 uni.addInterceptor 去监听页面的每次变化
根据官方文档说的“同一个 url 仅需调用一次,对于变化 url 的 SPA 的 web app 可在每次 url 变化时进行调用”
onLaunch() {
// #ifdef H5
const naviArr = [
'navigateTo',
'redirectTo',
'reLaunch',
'switchTab',
'navigateBack',
]
for (let i of naviArr) {
uni.addInterceptor(i, {
success:(e)=>{
this.watchRouter()
},
})
}
this.watchRouter() // 首次进入页面
// #endif
},
- 然后在 methods 里调用 callWexinShare 方法
methods:{
watchRouter() {
if (this.$wechatSdk?.isWechat()) {
this.$wechatSdk.callWexinShare()
}
}
}
- (看需求)因为项目需求需要在一些特定页面根据页面的信息配置分享内容,如作者主页、商品详情页
async getInfo() {
const res = await api()
this.goodDetail = res.data
// #ifdef H5
// 微信自定义分享
if (this.$wechatSdk?.isWechat()) {
this.$wechatSdk.callWexinShare({
title: this.goodDetail.title,
desc: this.goodDetail.desc,
imgUrl: this.goodDetail.imgUrl,
})
}
// #endif
}
四、踩坑
- 使用 uni.addInterceptor 去监听页面跳转的 api,忽略了浏览器的返回按钮(会出现分享的页面的配置内容还是上一个页面的),所以要在 onUnload 页面卸载的时候重置回默认配置
onUnload() {
// #ifdef H5
if (this.$wechatSdk?.isWechat()) {
this.$wechatSdk.callWexinShare()
}
// #endif
},
- 有一种场景:A 页面进入 B 页面,B 页面调接口获取详情,然后用详情去配置分享内容,B 页面进入 C 页面再返回 B 页面,不管是 uni.navigateBack 返回页面还是浏览器返回页面都会把分享内容重置回默认配置,这时候再分享 B 页面,就不是根据接口返回的内容配置的了。因为配置 B 页面分享内容是放在调接口的时候,所以想了两个方法解决:第一种简单粗暴,直接在 onShow 的时候再去调接口获取详情,这种不太友好;第二种是第一次进入页面的时候把详情信息存在本地,然后返回的时候在 onShow 里判断是否有详情信息,如果有则更新分享配置:
async getInfo() {
const res = await api()
this.goodDetail = res.data
// #ifdef H5
uni.setStorageSync("wxshareData", this.goodDetail)
// 微信自定义分享
if (this.$wechatSdk?.isWechat()) {
this.$wechatSdk.callWexinShare({
title: this.goodDetail.title,
desc: this.goodDetail.desc,
imgUrl: this.goodDetail.imgUrl,
})
}
// #endif
}
onShow() {
// #ifdef H5
// 从上一个页面返回到这个页面的时候判断缓存,有则更新微信分享配置
const wxshareData = uni.getStorageSync('wxshareData');
if (wxshareData) {
if (this.$wechatSdk?.isWechat()) {
this.$wechatSdk.callWexinShare({
title: wxshareData.title,
desc: wxshareData.desc,
imgUrl: wxshareData.imgUrl,
})
}
}
// #endif
}
- 微信 SDK 对分享图标是有限制的!!!
图片格式:微信 SDK 支持的分享图标格式为 JPEG、PNG 格式,不支持 GIF 格式。
图片大小:微信 SDK 对分享图标的大小有限制,图片大小不能超过 32KB。
图片尺寸:微信 SDK 对分享图标的尺寸也有限制,建议分享图标的尺寸为 120px * 120px。
图片质量:为了保证分享图标的清晰度,建议分享图标的质量在 80%以上。
这个是最坑的,sdk 文档也没有说明,最后还是 GPT 上找到的!(内心 os:怪不得江湖上都吐槽微信,这次算是领教了)
我的解决方案是采用 oss 图片压缩对图片进行压缩处理,就是在图片链接后拼接"?x-oss-process=image/resize,w_120,m_lfit/format,png/quality,q_80",详细参数可以参考oss 图片缩放
五、其他
- 微信-JS-SDK 说明文档
- 微信公众号的 js 安全域名不可以设置 ip 段,而 微信公众平台-测试号 可以,因此可以在本地测试