通过二维码访问微信小程序内页

前言

线下扫码、海报、商品详情等场景,经常需要打开微信小程序的某个内页并带上参数。
和支付宝不同,微信小程序不能随意拼一个 https 地址就拉起小程序,通常要用 明文 URL Scheme加密 URL SchemeURL Link
下文以 uni-app 项目为例,说明如何生成链接、做成二维码,以及在小程序里接收参数。
仅面向国内非个人主体小程序;个人主体不支持 URL Scheme 与 URL Link。

后台配置

使用明文 URL Scheme 前,需在微信公众平台声明能力。

  1. 登录 微信公众平台
  2. 左下角账号 → 账号设置 → 基本设置 → 隐私与安全
  3. 开启「明文 Scheme 拉起此小程序」

未声明时,拼出来的明文 Scheme 无法正常拉起小程序。

仅微信访问

明文 Scheme

声明后,可直接拼接 URL,无需调接口。
格式如下:

1
weixin://dl/business/?appid=APPID&path=PATH&query=QUERY&env_version=ENV_VERSION

其中:

  • appid:小程序 AppID,必填
  • path:页面路径,必填;不能带 query,需单独 url_encode
  • query:页面参数,选填,需 url_encode
  • env_version:选填,release 正式版、trial 体验版、develop 开发版;仅微信外打开时生效

假如 AppID 为 wx1234567890abcdef,要打开 /pages_a/goods/goodsdetail,参数 goodsId=46
用 JS 拼接如下:

1
2
3
4
5
let appId = 'wx1234567890abcdef';
let path = encodeURIComponent('/pages_a/goods/goodsdetail');
let query = encodeURIComponent('goodsId=46');
let url = `weixin://dl/business/?appid=${appId}&path=${path}&query=${query}`;
console.info(url);

注意:pathquery 分开传递,不要把 goodsId 写在 path 里。

把上面的 url 生成二维码后,用微信扫一扫即可打开对应内页。
iOS 一般可直接识别;Android 部分场景下扫码识别 weixin:// 不稳定,见下文 H5 中转。

加密 Scheme

若不想暴露 AppID 和页面路径,或需设置有效期,可调用服务端接口 generatescheme 获取加密 Scheme。

接口地址:

1
POST https://api.weixin.qq.com/wxa/generatescheme?access_token=ACCESS_TOKEN

请求体示例(path 不可带 query,参数放 query 字段):

1
2
3
4
5
6
7
8
{
"jump_wxa": {
"path": "/pages_a/goods/goodsdetail",
"query": "goodsId=46",
"env_version": "release"
},
"is_expire": false
}

返回的 openlink 形如:

1
weixin://dl/business/?t=TICKET

可在链接后拼接 cq 作为自定义参数(需 url_encode),例如 &cq=extra%3D1
加密 Scheme 同样适合做成二维码,用微信扫码打开。

支持浏览器/微信

URL Link 是 https 短链,更适合「浏览器扫码 + 微信内打开」。
需服务端调用 generate_urllink 接口生成,格式类似:

1
https://wxaurl.cn/TICKET

或:

1
https://wxmpurl.cn/TICKET

将返回的链接直接生成二维码即可。
微信外打开场景值为 1194;微信内打开会走开放标签,场景值为 1167。
Android 在微信外打开时,通常会先经过官方 H5 中间页再进入小程序。

H5 中转

若使用明文 Scheme 或加密 Scheme,又希望非微信浏览器扫码也能跳转,可像官方文档建议的那样,用 H5 页做中转。
Android 无法像 iOS 那样直接识别 Scheme,需要 location.href 跳转。

项目里动态拼 Scheme 并写入二维码地址的示例:

1
2
3
4
5
6
let appId = 'wx1234567890abcdef';
let goodsId = 46;
let path = encodeURIComponent('/pages_a/goods/goodsdetail');
let query = encodeURIComponent('goodsId=' + goodsId);
let scheme = `weixin://dl/business/?appid=${appId}&path=${path}&query=${query}`;
qrCodeUrl.value = 'https://www.psvmc.cn/wx-mp.html?scheme=' + encodeURIComponent(scheme);

wx-mp.html 在非微信环境下读取 scheme 并跳转:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>小程序跳转</title>
</head>
<style>
body {
padding: 0;
overflow: hidden;
}
#msg {
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
font-size: 6vw;
display: none;
flex-direction: column;
gap: 4vw;
}
#btn {
font-size: 4vw;
padding: 2vw 4vw;
}
</style>
<body>
<div id="msg">
<span id="tip">正在打开小程序…</span>
<button id="btn" style="display:none">点击打开小程序</button>
</div>
<script>
function isWeChat() {
return navigator.userAgent.toLowerCase().includes('micromessenger');
}

function openScheme(scheme) {
window.location.href = scheme;
}

if (isWeChat()) {
document.getElementById('tip').textContent = '请在浏览器中扫码访问';
document.getElementById('msg').style.display = 'flex';
} else {
const url = new URL(window.location.href);
const scheme = url.searchParams.get('scheme');
if (scheme) {
document.getElementById('msg').style.display = 'flex';
openScheme(scheme);
document.getElementById('btn').style.display = 'block';
document.getElementById('btn').onclick = function () {
openScheme(scheme);
};
}
}
</script>
</body>
</html>

部分浏览器会拦截脚本自动跳转,页面上保留「点击打开小程序」按钮更稳妥。
明文 Scheme 在微信内无效,微信内网页应使用开放标签跳转小程序。

支付宝扫码访问

支付宝无法直接扫码打开微信小程序。
可以复用上面的 H5 中转思路:支付宝内打开时提示用户改用浏览器或微信扫码。

检测支付宝客户端并提示的片段:

1
2
3
4
5
6
7
function isAlipay() {
return navigator.userAgent.toLowerCase().includes('alipayclient');
}

if (isAlipay()) {
document.getElementById('tip').textContent = '请使用微信或浏览器扫码访问';
}

与支付宝小程序那篇「微信里提示用浏览器打开」是同一类跨端限制,只能做引导,无法强制跳转。

query 参数获取

Scheme 里 query 传入的参数,在小程序启动时从 options.query 读取。
path 若写在 Scheme 的 path 字段,对应页面 onLoad 里也可拿到路由参数(uni-app 会解析到 options)。

App 层面

App.vueonLaunch / onShow 中:

1
2
3
4
5
6
onLaunch(options) {
console.log('launch query', options.query);
},
onShow(options) {
console.log('show query', options.query);
}

页面层面

页面 onLoad 可直接使用解析后的参数:

1
2
3
onLoad(options) {
console.log('goodsId', options.goodsId);
}

也可通过 uni.getLaunchOptionsSync() 获取启动参数:

1
2
3
4
onLoad() {
let launchOptions = uni.getLaunchOptionsSync();
console.log(launchOptions.query);
}

uni-app 编译到微信端时,上述写法与微信原生 options.query 行为一致。

注意

  1. 只能跳转已发布小程序里存在的页面。
  2. 明文 Scheme、加密 Scheme、URL Link 合计:每天生成上限 50 万条;每天打开上限 600 万次。
  3. 通过 Scheme 拉起时,系统可能弹窗询问是否打开微信,需处理用户拒绝的情况。
  4. 商品详情等动态参数,优先放 Scheme 的 query 字段,不要塞进 path