300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 前端wx-jssdk的使用及企微和微信下分享等功能自定义处理

前端wx-jssdk的使用及企微和微信下分享等功能自定义处理

时间:2024-02-16 01:55:01

相关推荐

前端wx-jssdk的使用及企微和微信下分享等功能自定义处理

前端wx-jssdk的使用及企微和微信下分享等功能自定义处理

一、前端wx-jssdk的使用

wx-jssdk使用需要微信公众平台内进行设置(进入公众号设置的“功能设置”里填写“JS接口安全域名“的操作)及后端配合才能真正使用,下文是讲述前端如何使用。

wx-jssdk的接口文档

1、导包

在main.ts中(以vite+react项目中为例),为什么在main.ts中进行使用呢?其实在index.html文件中调用也是可以的,因为我要用到一些公共方法,并且保证要完成加载在线wx-jssdk包完后,再进行挂载等步,实现异步变同步处理更方便,就放在main.ts中。放在index.html 并保证异步变同步完全加载完wx-jssdk包就行,即:支持使用 AMD/CMD 标准模块加载方法加载

import React from 'react';import ReactDOM from 'react-dom';import {BrowserRouter } from 'react-router-dom';import App from './app';import {getEnv,WECHAT_ENV } from '@/utils';//import '@/utils/setup.ts';//import '@/assets/css/reset.less';//import '@/assets/css/base.less';//import '@/assets/font/iconfont.css';const script = document.createElement('script');// @ts-ignorescript.crossorigin = 'anonymous';const sdkVerion = getEnv() === WECHAT_ENV.qyWechat ? 'jweixin-1.2.0.js' : 'jweixin-1.6.0.js';// 开发环境和线上环境的wxsdk的路径有所区别// script.src = process.env.NODE_ENV === 'development' ? `./public/lib/${sdkVerion}` : `./lib/${sdkVerion}`;script.src = `https://res./open/js/${sdkVerion}`;script.onerror = () => {console.log('qy-wx-sdk:loadError');};script.onload = () => {console.log({wx });// 必须等wxsdk 加载完之后,才能渲染页面ReactDOM.render(<BrowserRouter basename={`/${import.meta.env.VITE_APP_NAME}`}><App /></BrowserRouter>,document.getElementById('root'));};document.head.appendChild(script);

2、使用

wx-jssdk提供了企微和微信环境下的一些方法进行使用:(wx-jssdk的接口文档、企业微信-wxjssdk)

wx.config(obj):config接口注入权限验证配置wx.ready():config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。wx.error():通过error接口处理失败验证wx.checkJsApi({ jsApiList: [],success(res) {console.log(res);},}):判断当前客户端版本是否支持指定JS接口,jsApiList: 需要检测的JS接口列表,所有JS接口列表,见JS接口列表;企业微信-wxjssdkwx.agentConfig():

config注入的是企业的身份与权限,而agentConfig注入的是应用的身份与权限。尤其是当调用者为第三方服务商时,通过config无法准确区分出调用者是哪个第三方应用,而在部分场景下,又必须严谨区分出第三方应用的身份,此时即需要通过agentConfig来注入应用的身份信息。企业微信-wxjssdk内有详细讲解wx.invoke():获取进入H5页面的入口环境,企业微信-wxjssdk

封装的getTicket

import ajax from '@/utils/ajax';import {ConfigOptions, JSApiList } from 'wx-jssdk';import {getEnv,WECHAT_ENV } from '@/utils';// 普通签名export const getTicket = async (jsApiList, callback, isShowError = true, maxRequestCount = 3) => {// 开发+真机调试模式,要初始化JS_SDK if (process.env.NODE_ENV === 'development' && !process.env.WX_JS_SDK_ENABLED) return;let url = '';// 如果是 iOS 设备,则使用第一次进入App时的 URL 去请求 wxConfig,不然的话会导致 iOS 中分享的链接描述信息或者图标不对if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent) && env === 2) {url = encodeURIComponent(localStorage.getItem('entryUrl'));// 有保存在localstorage中的页面路径} else {// console.log('签名地址=======================', window.location.href)url = encodeURIComponent(window.location.href);}const params = {appId: newAppId || appId,corpId: env === 2 ? authCorpId : currentCorpId,wechatType: env,jsUrl: url,agentId,};console.log('getTicket', `path=${location.pathname} url=${decodeURIComponent(params.jsUrl)}`);try {const res = await ajax('getTicket', params, isShowError); // 后端定义的接口 这里的ajax是自定义的const {retdata = {} } = res;const {appId, noncestr, signature, timestamp, nextUpdateTime } = retdata;const obj = {debug: false, // 是否开启调试模式appId, // appidtimestamp, // 时间戳nonceStr: noncestr, // 随机字符串signature, // 签名jsApiList,openTagList: ['wx-open-launch-weapp'],};if (env === 1) {obj.beta = true;obj.appId = currentCorpId;}wx.config(obj);wx.ready(function () {if (typeof callback === 'function') callback(jsApiList);});wx.error((res) => {console.log('%c zjs wx.error res:', 'color: #0e93e0;background: #aaefe5;', res);if (typeof callback === 'function' && maxRequestCount > 0) callback(new Error('error'));});} catch (e) {console.log('%c zjs getTicket err:', 'color: #0e93e0;background: #aaefe5;', e);setTimeout(() => {maxRequestCount > 0 && getTicket(jsApiList, callback, isShowError, --maxRequestCount);}, 1000);}};// 企业微信下一些自建应用签名export const agentConfig = async (jsApiList: JSApiList[],callback: Function,shareUrl = '',isShowError = true,maxRequestCount = 3) => {getTicket([...jsApiList, 'agentConfig'],async (error: string) => {if (error === 'error') {// 过期或者签名错误 重新获取setTimeout(() => {maxRequestCount > 0 && agentConfig(jsApiList, callback, shareUrl, isShowError, --maxRequestCount);}, 1000);} else {const params = {type: WECHAT_ENV.qyWechat,jsUrl: window.location.href,};const res = await ajax({api: 'getTicket', params });const {retdata = {} } = res;const {corpId: corpid, noncestr: nonceStr, agentid, signature, timestamp }: any = retdata;wx.checkJsApi({jsApiList: ['agentConfig'],success(res) {console.log(res);},});const obj = {corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致agentid, // 必填,企业微信的应用idtimestamp, // 必填,生成签名的时间戳nonceStr, // 必填,生成签名的随机串signature, // 必填,签名,见附录1jsApiList,// openTagList: ['wx-open-launch-weapp'],success: (res: ILooseStrObj) => {console.log('agentConfig ok', res);if (typeof callback === 'function') callback(jsApiList);},fail(res: ILooseStrObj) {console.log('agentConfig fail', res);if (typeof callback === 'function') callback('error');},};console.log('agentConfig obj', obj);wx.agentConfig(obj);}},shareUrl);};

上面公用的一些方法

export const WECHAT_ENV = {qyWechat: 1, // 企业微信wechat: 2, // 微信};// 判断当前是微信环境还是企业微信环境export const getEnv = () => {const ua = window.navigator.userAgent.toLowerCase();// eslint-disable-next-lineif (Boolean(ua.match(/MicroMessenger/i)) && Boolean(ua.match(/wxwork/i))) {// 企业微信// console.log('企业微信环境-1')return WECHAT_ENV.qyWechat;// eslint-disable-next-line} else if (Boolean(ua.match(/micromessenger/i))) {// 微信// console.log('微信环境-2')return WECHAT_ENV.wechat;}};// 判断是pc端还是移动端export const isPC = !/Android|webOS|iPhone|iPod|BlackBerry|SymbianOS|Windows Phone/i.test(navigator.userAgent);/*** [changeSearch description]* @param {[type]} oldName 需要修改的search字段* @param {[type]} newStr 替换的新串* @param {[type]} url 当前要替换的link地址 不传默认是 window.location.search* @return {[type]} [description]*/export const changeSearch = (oldName: string, newStr: string, url: string) => {const jsonObj: any = searchToJson(url || window.location.search);if (!oldName) {return url;}jsonObj[oldName] = newStr;const linkUrl = url.split('?')[0] + jsonToSearch(jsonObj);return linkUrl;};/** 将url的search部分转化为json* @param url:String -- url地址* @param codeURI:Boolean -- 是否解码*/export const searchToJson = (url = window.location.href, codeURI = false) => {let setUrl: string = url || '';const search = setUrl.split('?');let result = {};search.forEach((item, index) => {if (index !== 0) {result = item.split('&').reduce((obj, item) => {const arr = item.split('=');return {...obj, [arr[0]]: codeURI ? decodeURIComponent(arr[1]) : arr[1] };}, result);}});return result;};// 获取url参数export const getUrlQueryString = (search: string, name: string) => {const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');const r = search.substr(1).match(reg);if (r !== null) {return r[2];}return '';};

注意bug

背景:在使用到这个ssdk过程中(我使用js-weixin的包是1.2.0版本),我遇到了一个兼容Android和ios的问题,就是在调用jssdk无论是ios还是Android都可以调用,但是当在企业微信中使用到分享相关的api时,在ios是无法调用,在Android是没有问题的,

处理方案:更改调用的js-weixin包,将js-weixin包改为1.0.0的包 ,两个包地址是不一样的:

https://res./wwopen/js/jsapi/jweixin-1.0.0.js

https://res./open/js/jweixin-1.2.0.js

二、 处理系统分享出去自定标题、描述、背景及相关系统功能禁用等

场景一:使用系统携带的分享等功能,但自定义分享的标题、描述等内容

在使用系统带的分享功能时,需要自定义分享出去的背景、背景图、描述及分享的链接时,可以将下面的shareFuc导入,初始化(放componentDidMount或useEffect中)携带对应的参数即可。

const shareObj = {title: '客户认证',desc: '客户自己完成认证',imgUrl: '',linkUrl: ``,//分享的链接,可携带一些参数};useEffect(() => {shareFuc(shareObj);// 下面封装已给出}, [userId]);

场景二:弃用系统自带的分享,自己写弹框,触发分享API

出现这个场景,一方面可能可客户需要,另一方面,可能是分享要进行埋点,记录分享出去的次数。

实现:写一个弹框(如下),将下面每个分享或转发调用相应的API

转发:shareAppMessage,微信好友:shareWechatMessage,微信朋友圈:shareTimeline,这几个直接使用wx.invoke即可

// 微信好友const forwardWeChat = () => {const shareConfig = {title, // 分享标题desc, // 分享描述link: "linkUrl", // 分享链接imgUrl: "imgUrl" , // 分享封面};console.log('企微-微信好友 shareConfig', shareConfig);wx.invoke('shareWechatMessage', shareConfig, (res: any) => {console.log('企微分享微信好友-分享回调', res);if (res.err_msg === 'shareWechatMessage:ok') {//}});};

企微朋友圈:shareToExternalMoments,群发客户:shareToExternalContact;群发客户群:shareToExternalChat,比微信下多了agentConfig处理,是因为这三个api需要配置客户联系功能与版本

import {JSApiList } from 'wx-jssdk';import {agentConfig } from '@/utils/getTicket';// 上面有封装// 群发客户群const groupShareGroup = async (e: any) => {const arrAgent: JSApiList[] = ['shareToExternalChat'];agentConfig(arrAgent,() => {wxInvokeShare('shareToExternalChat', {title, // 分享标题desc,link: "linkUrl", // 分享链接imgUrl:"imgUrl", // 分享封面});},linkUrl);};

注意

问题:在我处理分享的时候踩到了一个坑,就是设置分享的imgUrl参数的时候写的是相对路径(…/…/…/images/common/shareIconImg.png),分享出去的图标无法显示

原因:官方似乎没有给出解释,我觉得是不是图片是本地内,分享出去后,显示的这个内容并没有加载整个项目代码,只是作为参数传过去,由于是图片是相对路径,这样导致加载不到图片,

处理方案:使用base64方法得到图片作为imgUrl参数

场景三:禁用个人微信或企微右上角分享等功能

见下列方法:

企微:hiddenWxQyShareOption,使用API:wx.hideOptionMenu(), wx.showMenuItems(微信:hiddenWxShareOption ,使用:WeixinJSBridge.call(‘hideToolbar’); WeixinJSBridge.call(‘hideOptionMenu’);

函数封装shareFuc、企微和个人微信系统分享等功能禁用封装

// @ts-nocheckimport globalData from '@/config/globalData';import keyDict from '@/config/keyDict';import point from '@/config/point';import {changeSearch, getEnv, searchToJson, getUrlQueryString, isPC, WECHAT_ENV } from '@/utils';//上面公用方法import ajax from '@/utils/ajax';import {getTicket } from '@/utils/getTicket';// 上面定义封装处理import {JSApiList } from 'wx-jssdk';interface IShareProps {title: string;desc: string;linkUrl: string;imgUrl: string;userId: string;cb?: () => void;}interface IShareFunProps {shareObj: IShareProps;jsApiList: JSApiList[];maxRequestCount: number;}/*** [shareFuc description]* @param {[type]} shareObj { title: 标题, desc: 描述, linkUrl: 分享地址(会对地址做拼接,默认不传为当前url), imgUrl: 分享icon, staffId: 经理id,拼接给分享地址}* @param {Array} [jsApiList=[微信api]]* @return {Promise}[description]* @param {type} maxRequestCount 最大失败请求次数,默认 为 3次*/export const shareFuc = async (shareObj: IShareProps, jsApiList = [], maxRequestCount = 3) => {// console.log('shareObj===》', shareObj);const defaultJsApi: JSApiList[] = ['onMenuShareAppMessage', 'onMenuShareTimeline', 'getLocation', 'previewImage'];// 不支持在PC端微信使用js-sdk功能if (isPC) return;const ua = navigator.userAgent.match(/MicroMessenger\/([\d\\.]+)/i);const lowerWeChat = ua ? ua[1] < '6.7.2' : true;// 微信if (getEnv() === 2) {defaultJsApi.push('updateAppMessageShareData', 'updateTimelineShareData');}getTicket([...defaultJsApi, ...jsApiList],async (error: string) => {if (error === 'error') {// 过期或者签名错误 重新获取setTimeout(() => {if (maxRequestCount > 0) {maxRequestCount = --maxRequestCount;shareFuc(shareObj, jsApiList, maxRequestCount);}}, 1000);} else {// 企业微信(微信)下隐藏部分不需要的菜单功能--如分享到同事吧,收藏,转发,微信,朋友圈if (getEnv() === 2) {wx.hideOptionMenu();wx.showMenuItems({menuList: ['menuItem:copyUrl', // 复制链接],// wx.hideMenuItems({// menuList: [//// 'menuItem:setFont', // 字体//// 'menuItem:openWithSafari', // Safari//// 'menuItem:share:email', // 邮件//// 'menuItem:openWithQQBrowser', // QQBrowser//// 'menuItem:share:appMessage', // 转发//// 'menuItem:share:timeline', // 朋友圈//// 'menuItem:share:wechat', // 微信// ], // 要隐藏的菜单项// });});}const {title = '', desc = '', imgUrl = '', linkUrl, cb } = shareObj;// 个人微信处理if (getEnv() === 2) {// 分享给朋友if (wx.updateAppMessageShareData && !lowerWeChat) {wx.updateAppMessageShareData({title, // 分享标题desc, // 分享描述link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl, // 分享图标success: () => {console.log('微信分享给朋友,新Api,没有成功回调');},});} else {wx.onMenuShareAppMessage({title, // 分享标题desc, // 分享描述link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl, // 分享图标type: undefined, // 分享类型,music、video或link,不填默认为linkdataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空success: () => {// 用户点击了分享后执行的回调函数console.log('微信分享给朋友,旧Api');},});}// 分享给朋友圈if (wx.updateTimelineShareData && !lowerWeChat) {wx.updateTimelineShareData({title, // 分享标题link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl, // 分享图标success: () => {// 设置成功console.log('微信分享给朋友圈,新Api');},});} else {wx.onMenuShareTimeline({title, // 分享标题link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl, // 分享图标success: () => {// 设置成功console.log('微信分享给朋友圈,旧Api');},});}} else {// 企业微信wx.onMenuShareAppMessage({title, // 分享标题desc, // 分享描述link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl, // 分享图标success: () => {},cancel: () => {},});wx.onMenuShareTimeline({title, // 分享标题link: linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl, // 分享图标success: () => {// 设置成功console.log('企业微信分享给朋友圈,旧Api');},cancel: () => {// 用户取消分享后执行的回调函数console.log('企业微信分享给朋友圈,旧Api,cancel');},});}// eslint-disable-next-line @typescript-eslint/prefer-optional-chaincb && cb();}},shareObj.linkUrl,false,maxRequestCount);};/*** 禁止企业微信右上角分享(新版本企微是下方)* **/let wxConfigTimer: number;export const hiddenWxQyShareOption = () => {if (getEnv() === WECHAT_ENV.qyWechat) {wxConfigTimer && clearTimeout(wxConfigTimer);wxConfigTimer = window.setTimeout(() => {getTicket([], () => {console.log('企业微信环境屏蔽右上角分享');wx.hideOptionMenu();wx.showMenuItems({menuList: ['menuItem:copyUrl'], //保留复制链接});});}, 200);}};/** 禁止微信右上角分享按钮 */export const hiddenWxShareOption = () => {if (getEnv() === WECHAT_ENV.wechat) {console.log('禁用微信右上角分享和状态栏');if (typeof WeixinJSBridge === 'undefined') {// 这个可以禁用安卓系统的右上角分享(只针对微信端)document.addEventListener('WeixinJSBridgeReady',function () {WeixinJSBridge.call('hideToolbar');WeixinJSBridge.call('hideOptionMenu');},false);} else {// 这个可以禁用ios系统的右上角分享(只针对微信端)WeixinJSBridge.call('hideToolbar');WeixinJSBridge.call('hideOptionMenu');}}};

JS接口列表

type JSApiList =| 'agentConfig'| 'updateAppMessageShareData'| 'updateTimelineShareData'| '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'| 'shareToExternalContact'| 'shareToExternalChat'| 'selectExternalContact'| 'navigateToAddCustomer';

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。