本文要实现的需求如下
通过一个二维码,用户用不同的方式扫码,打开对应的端,具体如下
另外要求二维码能携带动态参数
假设二维码对应的链接如下https://m.warmplace.com/#/scan-qrcode?scheme=${encodeURIComponent("app://warmplace.com/pagea?source=source_xx&shopid=shopid_xx")}
shopid
是动态的伪代码如下
html<script>
// map维护跳转原生链接的最低版本要求和小程序路径关系
const map = {
// 跳转小程序
// 示例: https://m.warmplace.com/#/scan-qrcode?scheme=app%3A%2F%2Fwarmplace.com%2Fpagea%3Fsource%3Dsource_xx%26shopid%3Dshopid_xx
// scheme示例:"app://warmplace.com/pagea?source=source_xx&shopid=shopid_xx"
'app://warmplace.com/pagea': {
APP_VERSION: '1.0.0',
MP_HITCH_PATH: 'pages/pagea/pagea',
},
};
exec();
asyn function exec() {
/**
* 1. 首先支付宝和微信环境扫码,通过在小程序后台配置的规则
* 平台会为我们自动重定向到相应小程序, 所以不会走这里的逻辑
*/
const { scheme } = this.$route.query;
let config;
for (const [key, val] of Object.entries(map)) {
if (scheme.startsWith(key)) {
config = val;
break;
}
}
if (!config) { // 需升级app版本
await toast.show(`暂不支持该scheme:“${scheme.split('?')[0]}” 请检查`, { duration: 3000 });
// 调用app bridge方法关闭webview
bridge.closeWebView();
return;
}
// 2. 你公司的app
if (/your_app_sign/.test(navigator.userAgent)) {
const { APP_VERSION } = config;
if (tools.versionCompare(env.appVersion, APP_VERSION) >= 0) {
window.location.href = scheme;
// 返回时,不想看到中间页
setTimeout(() => {
Native.closeWebView();
}, 200);
return;
}
await toast.show(`请将APP更新至${APP_VERSION}及以上版本后扫码`, { duration: 3000 });
Native.closeWebView();
return;
}
// 3. 其他环境 微信小程序
// 请求后段接口生成小程序链接
// 示例:window.location.href = 'weixin://dl/business/?t=xxx';
const { jumpUrl } = fetch('https://api.warmplace.cn/get_mp_url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// 'Authorization': 'Bearer your_token_here'
},
body: JSON.stringify({
bizCode: 'xxx',
query: scheme.split('?')[1] || '', // 把核心参数携带过去
envVersion: process.env.NODE_ENV !== 'development' ? 'release' : 'develop', // 正式版传release 开发版传develop
})
})
.then(response => {
// 检查请求是否成功
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 解析 JSON 数据
return response.json();
})
.then(data => {
// 处理返回的数据
console.log('获取到的数据:', data);
const {url} = data
if (url) {
window.location.href = url;
}
})
.catch(error => {
// 处理错误
console.error('请求出错:', error);
});
}
</script>
注: 真正跑通还需要后端开发和APP开发配合。
微信小程序后台配置扫普通二维码
登录微信小程序后台 点击 开发 —> 开发管理 —> 扫普通二维码 —> 添加
补充说明下
字段 | 说明 |
---|---|
前缀占用规则 | 不占用(可以设置动态参数) |
配置校验文件 | 针对域名来的,需要配置校验文件 |
小程序功能页面 | 对应小程序的页面地址 |
测试范围 | 开发中选择开发版本,发布后选择线上版本进行验证 |
测试链接 | 开发中,必须天完整链接,否则测试无效 |
支付宝扫码打开小程序
字段 | 说明 |
---|---|
前缀占用规则 | 不占用(支持动态参数 |
配置校验文件 | 针对域名来的,需要配置校验文件 |
小程序功能页 | 对应小程序的页面地址 |
开发阶段如何测试
由于支付宝和微信的机制差异较大,所以分开来写伪代码
首先来看支付宝,支付宝扫码打开小程序,参数在app启动时获取,为了通用性(后续可能有扫码打开小程序其他页面的需要),封装一个通用方法launchStore.ts
,将参数信息存在一个大对象里,通过key(页面路径)取参数信息.
tsxclass App extends Component {
onLaunch(launchParams: any) {
dealAlipayLaunchParams(launchParams);
}
// ...
}
tsinterface Params {
ts: number;
// key: 小程序页面路径 value: 参数
[key: string]: PageParams;
// 示例
// {source: "source_xx", shopid: "shopid_xx"}
}
export interface PageParams {[key: string]: string;}
// 这个对象用来存储扫码参数信息
const launchParams: Params = {};
export function setLaunchParams(key: string, val: PageParams) {
this.launchParams[key] = {
ts: Date.now(), // 辅助销毁参数使用
...val,
};
}
export function getLaunchParams(path: string) {
return this.launchParams[path]
}
export function removeLaunchParamsByPath(path: string) {
delete this.launchParams[path];
}
/**
* 扫码打开小程序通用方法
* 注意: 这里只记录小程序参数,是否扫码进入还是普通跳转,业务需要根据参数自行判断
*/
export async function dealAlipayLaunchParams(alipayParams?: any) {
let params: PageParams = { };
let scancode_time = '';
let q = '';
const { router } = getCurrentInstance();
let key = 'never';
if (!router?.path) return;
key = router.path;
if (!key.startsWith('/')){ // 支付宝小程序的路径不以“/”开头,这里统一
key = `/${key}`;
}
q = (alipayParams!.query || {})?.qrCode || '';
// 更新params
if (q?.startsWith('https')) {
const str = q.split('?')[1];
params = parseUrlParams(str);
params = parseUrlParams((params.scheme || '').split('?')[1]);
// 测试桩
/* setTimeout(() => {
Taro.showToast({ title : JSON.stringify(params), icon : 'none', duration : 6000 });
}, 5000); */
}
this.launchParams[key] = {
...params,
scancode_time,
q // 保留原始以便业务处理
};
}
export function parseUrlParams(search: string) {
return search.split('&').reduce((sum, item) => {
const [key, value] = item.split('=')
sum[key] = decodeURIComponent(value);
return sum;
}, {} as {[key: string]: string})
}
微信小程序是在 页面 onLoad
钩子接收的, 我们可以在useLayoutEffect
或 componentWillMount
中调用 dealWeappPageParams(pageParams);
当使用浏览器扫码或微信扫码时 打开微信小程序,但是参数格式略有一些区别,伪代码如下
tsexport async dealWeappPageParams(pageParams?: any) {
let params: PageParams = { };
let scancode_time = '';
let q = '';
const { router } = getCurrentInstance();
let key = 'never';
if (!router?.path) return;
// 1. 浏览器扫码的场景 打开微信程序
params = (router?.params || {}) as PageParams;
// 2. 微信扫码 打开微信小程序
q = decodeURIComponent(params.q || '');
({ scancode_time } = params);
// 更新params
if (q?.startsWith('https')) {
const str = q.split('?')[1];
params = parseUrlParams(str);
params = parseUrlParams((params.scheme || '').split('?')[1]);
// 测试桩
/* setTimeout(() => {
Taro.showToast({ title : JSON.stringify(params), icon : 'none', duration : 6000 });
}, 5000); */
}
this.launchParams[key] = {
...params,
scancode_time,
q // 保留原始以便业务处理
};
}
取参数和销毁扫码信息同支付宝。
扫码打开小程序在微信和支付宝都有坑,
先说下微信的坑
支付宝小程序的坑
联调设置, 点击小程序右上角三个点 --> 点击联调试着 --> 打开开关
参考文档:
本文作者:郭郭同学
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!