优点:可直接在H5调用,无需依赖webview壳子操作,扫码体验与微信扫一扫基本一致,兼容鸿蒙系统
缺点:无法像微信原生识别多码供用户选择
在H5中实现扫码有多个方式,在尝试各种库后(zxing/library或html5-qrcode)发现还是使用微信sdk更接近于微信扫一扫特效,我先列举一下库的优缺点
zxing/library html5-qrcode:
优点:无需依赖壳子
缺点:不兼容鸿蒙最新系统,扫码是调用的浏览器的摄像头-navigator.mediaDevices,没有扫码特效,需要自行绘制扫码特效,用部分版本鸿蒙系统摄像头会默认放大,码会很模糊,最新系统直接无法调用navigator.mediaDevices,无法识别多码,如果想识别多码,需要结合canvas才能实现类似效果
综上所述:在微信环境中可使用微信sdk调用微信扫一扫,当扫码失败或其他环境则使用库作为备选方案
以下介绍微信sdk的实现步骤
官方文档:微信网页开发 / JS-SDK
前置准备
需要在微信公众平台-公众号申请appid,并将H5域名添加至业务域名
1.初始化sdk
注意:在 H5 里初始化微信JS-SDK(wx.config)时,必须用公众号的 appld,不能用小程序的 appld,且后端用于生成签名的appid应与前端初始化时一致
import wx from 'jweixin-module';
/**
* 初始化微信 JS-SDK
* @param {Object} signatureData - 后端返回的签名数据
* @param {string} signatureData.appId - 公众号的唯一标识
* @param {string} signatureData.timestamp - 生成签名的时间戳
* @param {string} signatureData.noncestr - 生成签名的随机串
* @param {string} signatureData.signature - 签名
*/
async initWxSDK(signatureData) {
return new Promise((resolve, reject) => {
wx.config({
debug: this.config.debug,
appId: signatureData.appId,
timestamp: signatureData.timestamp,
nonceStr: signatureData.noncestr,
signature: signatureData.signature,
jsApiList: this.config.jsApiList,
});
wx.ready(() => {
console.log('微信 JS-SDK 初始化成功');
this.isWxReady = true;
resolve(true);
});
wx.error((res) => {
console.error('微信 JS-SDK 初始化失败:', res);
this.isWxReady = false;
reject(new Error(`微信 JS-SDK 初始化失败: ${JSON.stringify(res)}`));
});
});
}
2.封装微信扫一扫api
/**
* 调用微信扫一扫功能
* @param {Object} options - 扫码配置选项
* @param {number} options.needResult - 默认为0,扫描结果由微信处理,1则直接返回扫描结果
* @param {Array} options.scanType - 可以指定扫二维码还是一维码,默认二者都有
* @returns {Promise} 返回扫码结果
*/
async scanQRCode(options = {}) {
return new Promise((resolve, reject) => {
if (!this.isWxReady) {
reject(new Error('微信 JS-SDK 未就绪,请先初始化'));
return;
}
const defaultOptions = {
needResult: 1, // 直接返回扫描结果
scanType: ['qrCode', 'barCode'], // 支持二维码和条形码
};
const scanOptions = { ...defaultOptions, ...options };
wx.scanQRCode({
needResult: scanOptions.needResult,
scanType: scanOptions.scanType,
success: (res) => {
console.log('扫码成功:', res);
resolve({
success: true,
result: res.resultStr || res.result,
data: res,
});
},
fail: (err) => {
console.error('扫码失败:', err);
reject({
success: false,
error: err,
message: '扫码失败,请重试',
});
},
});
});
}
3.初始化并调用微信扫一扫
async initializeWechat() {
this.scanService = new WeChatScanService();
// 获取签名参数
let data = {
noncestr: "1",
timestamp: new Date().getTime(),
url: window.location.href.split("#")[0],
appId: "xxxx",
};
const sdkParams = await this.scanService.getSdkParams(data);//调用后端获取微信sdk的签名数据
// 初始化微信SDK
await this.scanService.initWxSDK({ ...sdkParams, ...data });
},
async scanCode() {
try {
const result = await this.scanService.scanQRCode();
//result.result就是扫码的内容
} catch (error) {
// uni.$u.toast("扫码失败,请重试");
//这里给备选方案,使用库扫码相关文章可在主页查看,这里不做介绍
}
},
4.常见错误信息见一下文档
完整代码:
/**
* 微信 JS-SDK 扫码功能封装 (使用 jweixin-module)
* 用于在 H5 嵌套在微信小程序中时调用微信扫一扫
*/
import wx from 'jweixin-module';
import { GetApiSignature } from '@/api/common.js';
class WeChatScanService {
constructor() {
this.isWxReady = false;
this.config = {
debug: false, // 生产环境建议设置为 false
jsApiList: ['scanQRCode'], // 需要使用的 JS 接口列表
};
}
/**
* 初始化微信 JS-SDK
* @param {Object} signatureData - 后端返回的签名数据
* @param {string} signatureData.appId - 公众号的唯一标识
* @param {string} signatureData.timestamp - 生成签名的时间戳
* @param {string} signatureData.noncestr - 生成签名的随机串
* @param {string} signatureData.signature - 签名
*/
async initWxSDK(signatureData) {
return new Promise((resolve, reject) => {
wx.config({
debug: this.config.debug,
appId: signatureData.appId,
timestamp: signatureData.timestamp,
nonceStr: signatureData.noncestr,
signature: signatureData.signature,
jsApiList: this.config.jsApiList,
});
wx.ready(() => {
console.log('微信 JS-SDK 初始化成功');
this.isWxReady = true;
resolve(true);
});
wx.error((res) => {
console.error('微信 JS-SDK 初始化失败:', res);
this.isWxReady = false;
reject(new Error(`微信 JS-SDK 初始化失败: ${JSON.stringify(res)}`));
});
});
}
/**
* 调用微信扫一扫功能
* @param {Object} options - 扫码配置选项
* @param {number} options.needResult - 默认为0,扫描结果由微信处理,1则直接返回扫描结果
* @param {Array} options.scanType - 可以指定扫二维码还是一维码,默认二者都有
* @returns {Promise} 返回扫码结果
*/
async scanQRCode(options = {}) {
return new Promise((resolve, reject) => {
if (!this.isWxReady) {
reject(new Error('微信 JS-SDK 未就绪,请先初始化'));
return;
}
const defaultOptions = {
needResult: 1, // 直接返回扫描结果
scanType: ['qrCode', 'barCode'], // 支持二维码和条形码
};
const scanOptions = { ...defaultOptions, ...options };
wx.scanQRCode({
needResult: scanOptions.needResult,
scanType: scanOptions.scanType,
success: (res) => {
console.log('扫码成功:', res);
resolve({
success: true,
result: res.resultStr || res.result,
data: res,
});
},
fail: (err) => {
console.error('扫码失败:', err);
reject({
success: false,
error: err,
message: '扫码失败,请重试',
});
},
});
});
}
/**
* 检查是否在微信环境中
*/
isInWechat() {
return /micromessenger/i.test(navigator.userAgent);
}
//获取微信sdk参数
async getSdkParams(data) {
try {
const res = await GetApiSignature(data);
if (res.code === 0 && res.data) {
return res.data;
} else {
throw new Error(res.message || '获取微信签名失败');
}
} catch (error) {
console.error('获取微信SDK参数失败:', error);
throw error;
}
}
}
export default WeChatScanService;