1. 使用接口获取 access_token
接口:GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret
查看文档
2. 获取 jsapi_ticket
接口:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
查看文档
3. 使用 sha1 算法获取签名
var appId = 'wxb0669c109ed772b3';
var jsapi_ticket = ''; // 通过接口获取
var timestamp = (new Date()).getTime(); // 获取 signature 的时间
var nonceStr = 'Wm3WZYTPz0wzccnW'; // 生成signature 的随机字符串
var url = location.href; // 当前网页
var dataUrl = `jsapi_ticket=${jsapi_ticket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${url}`;
var signature = sha1(dataUrl); // 签名
// 其中sha1的算法如下:
function encodeUTF8(s) {
var i, r = [],
c, x;
for (i = 0; i < s.length; i++)
if ((c = s.charCodeAt(i)) < 0x80) r.push(c);
else if (c < 0x800) r.push(0xC0 + (c >> 6 & 0x1F), 0x80 + (c & 0x3F));
else {
if ((x = c ^ 0xD800) >> 10 == 0) //对四字节UTF-16转换为Unicode
c = (x << 10) + (s.charCodeAt(++i) ^ 0xDC00) + 0x10000,
r.push(0xF0 + (c >> 18 & 0x7), 0x80 + (c >> 12 & 0x3F));
else r.push(0xE0 + (c >> 12 & 0xF));
r.push(0x80 + (c >> 6 & 0x3F), 0x80 + (c & 0x3F));
};
return r;
}
// 字符串加密成 hex 字符串
function sha1(s) {
var data = new Uint8Array(encodeUTF8(s))
var i, j, t;
var l = ((data.length + 8) >>> 6 << 4) + 16,
s = new Uint8Array(l << 2);
s.set(new Uint8Array(data.buffer)), s = new Uint32Array(s.buffer);
for (t = new DataView(s.buffer), i = 0; i < l; i++) s[i] = t.getUint32(i << 2);
s[data.length >> 2] |= 0x80 << (24 - (data.length & 3) * 8);
s[l - 1] = data.length << 3;
var w = [],
f = [
function() { return m[1] & m[2] | ~m[1] & m[3]; },
function() { return m[1] ^ m[2] ^ m[3]; },
function() { return m[1] & m[2] | m[1] & m[3] | m[2] & m[3]; },
function() { return m[1] ^ m[2] ^ m[3]; }
],
rol = function(n, c) { return n << c | n >>> (32 - c); },
k = [1518500249, 1859775393, -1894007588, -899497514],
m = [1732584193, -271733879, null, null, -1009589776];
m[2] = ~m[0], m[3] = ~m[1];
for (i = 0; i < s.length; i += 16) {
var o = m.slice(0);
for (j = 0; j < 80; j++)
w[j] = j < 16 ? s[i + j] : rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1),
t = rol(m[0], 5) + f[j / 20 | 0]() + m[4] + w[j] + k[j / 20 | 0] | 0,
m[1] = rol(m[1], 30), m.pop(), m.unshift(t);
for (j = 0; j < 5; j++) m[j] = m[j] + o[j] | 0;
};
t = new DataView(new Uint32Array(m).buffer);
for (var i = 0; i < 5; i++) m[i] = t.getUint32(i << 2);
var hex = Array.prototype.map.call(new Uint8Array(new Uint32Array(m).buffer), function(e) {
return (e < 16 ? "0" : "") + e.toString(16);
}).join("");
return hex;
}
4. 中转页面
<html>
<head>
<title>打开小程序</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<!-- weui 样式 -->
<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.4.1/weui.min.css">
</link>
<style>
.hidden {
display: none;
}
.full {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.public-web-container {
display: flex;
flex-direction: column;
align-items: center;
}
.public-web-container p {
position: absolute;
top: 40%;
}
.public-web-container a {
position: absolute;
bottom: 40%;
}
.wechat-web-container {
display: flex;
flex-direction: column;
align-items: center;
}
.wechat-web-container p {
position: absolute;
top: 40%;
}
.wechat-web-container wx-open-launch-weapp {
position: absolute;
bottom: 40%;
left: 0;
right: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.desktop-web-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.desktop-web-container p {
margin-top: 30px;
}
</style>
<!-- 公众号 JSSDK -->
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<!-- 生成二维码 -->
<script src="https://focusnow-0ggaco3y828a369d-1253255428.tcloudbaseapp.com/statics/qrcode.min.js"></script>
</head>
<body>
<div class="page full">
<!-- 外部手机浏览器页面 -->
<div id="public-web-container" class="hidden">
<p id="public-web-jump-button-loading-text" class="">正在打开 “科瓦模板”...</p>
<a id="public-web-jump-button" href="javascript:" class="weui-btn weui-btn_primary weui-btn_loading" onclick="openWeapp()">
<span id="public-web-jump-button-loading-icon" class="weui-primary-loading weui-primary-loading_transparent">
<i class="weui-primary-loading__dot"></i>
</span>
打开小程序
</a>
</div>
<!-- 微信手机浏览器页面 -->
<div id="wechat-web-container" class="hidden">
<p class="">点击以下按钮打开 “科瓦模板”</p>
<wx-open-launch-weapp id="launch-btn" username="gh_6eac445ec603" path="/pages/component/index/index">
<script type="text/wxtag-template">
<style>
button {
width: 200px;
height: 45px;
text-align: center;
font-size: 17px;
display: block;
margin: 0 auto;
padding: 8px 24px;
border: none;
border-radius: 4px;
background-color: #07c160;
color: #fff;
}
</style>
<button>打开小程序</button>
</script>
</wx-open-launch-weapp>
</div>
<!-- PC浏览器页面 -->
<div id="desktop-web-container" class="hidden">
<div id="qrcode"></div>
<p class="">请在手机打开网页链接</p>
</div>
</div>
<script src="./sha1.js"></script>
<script>
// 固定需要用到的值
var appId = 'wxb0669c109ed772b3';
var jsapi_ticket = 'LIKLckvwlJT9cWIhEQTwfNe6582ARyXzxk5VTETk6qR5Uae5chcZhBP_fEblaLQkoSCqtSrFC-FMGvd3V_6b0w'; // 通过接口获取
var timestamp = (new Date()).getTime(); // 获取 signature 的时间
var nonceStr = 'Wm3WZYTPz0wzccnW'; // 生成signature 的随机字符串
var url = location.href; // 当前网页
var dataUrl = `jsapi_ticket=${jsapi_ticket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${url}`;
var signature = sha1(dataUrl); // 签名
</script>
<script>
/*
微信版本要求为:7.0.12及以上。 系统版本要求为:iOS 10.3及以上、Android 5.0及以上。
参考文档 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html#%E5%BC%80%E6%94%BE%E6%A0%87%E7%AD%BE%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/staticstorage/jump-miniprogram.html
*/
// 获取URLScheme,这里是固定死的,你需要后端开发人员为你准备个接口或云函数返回URLScheme
const getURLScheme = (path, query) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("weixin://dl/business/?t=u80oHnHzEfg")
}, 10);
})
}
// 外部手机浏览器打开URL Scheme,一般会有提示,接受打开即可
const openWeapp = async (onBeforeJump) => {
//获取url scheme
const openlink = await getURLScheme()
if (onBeforeJump) {
onBeforeJump()
}
location.href = openlink
}
// 使用开放标签打开小程序时调用,注入wx.config的配置信息,使用小程序云开发静态网站托管的网页可以绕过鉴权,公众号需要后端接口配合返回鉴权参数
const getWXConfig = async () => {
const config = {
appId, // 已认证的小程序appid或已认证的服务号appid
timestamp, // 必填,使用小程序云开发静态网站托管的网页填任意数字即可,无须鉴权
nonceStr, // 必填,使用小程序云开发静态网站托管的网页填任意非空字符串即可,无须鉴权
signature, // 必填,使用小程序云开发静态网站托管的网页填任意非空字符串即可,无须鉴权
}
return config
}
const start = async () => {
const ua = navigator.userAgent.toLowerCase()
// 企业微信
const isWXWork = ua.match(/wxwork/i) == 'wxwork'
// 微信浏览器
const isWeixin = !isWXWork && ua.match(/MicroMessenger/i) == 'micromessenger'
let isMobile = false
let isDesktop = false
if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|IEMobile)/i)) {
isMobile = true
} else {
isDesktop = true
}
if (isDesktop) {
// 在 pc 上则给提示引导到手机端打开
const containerEl = document.getElementById('desktop-web-container')
containerEl.classList.remove('hidden')
containerEl.classList.add('full', 'desktop-web-container')
// 生成当前页面二维码
new QRCode('qrcode', {
text: document.URL,
width: 200,
height: 200,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
} else if (isWeixin) {
//如果微信浏览器,通过开放标签打开小程序
const containerEl = document.getElementById('wechat-web-container')
containerEl.classList.remove('hidden')
containerEl.classList.add('full', 'wechat-web-container')
const launchBtn = document.getElementById('launch-btn')
launchBtn.addEventListener('error', function(e) {
alert('用户拒绝跳转或跳转异常', e.detail)
})
const config = await getWXConfig()
wx.config({
...config,
debug: true,
jsApiList: ['chooseImage'], // 安卓上必填一个,随机即可
openTagList: ['wx-open-launch-weapp'], // 填入打开小程序的开放标签名
})
} else {
// 在非微信的外部手机浏览器使用URLScheme打开小程序
const containerEl = document.getElementById('public-web-container')
containerEl.classList.remove('hidden')
containerEl.classList.add('full', 'public-web-container')
const buttonEl = document.getElementById('public-web-jump-button')
const buttonLoadingIcon = document.getElementById('public-web-jump-button-loading-icon')
const buttonLoadingText = document.getElementById('public-web-jump-button-loading-text')
try {
// 自动执行,打开URLScheme
await openWeapp(() => {
buttonEl.classList.remove('weui-btn_loading')
buttonLoadingIcon.classList.add('hidden')
buttonLoadingText.classList.add('hidden')
})
} catch (e) {}
}
}
start()
</script>
</body>
</html>