2025-04-07
小程序
00

目录

浏览器和app扫码的实现
微信扫码打开微信小程序
具体方案
支付宝小程序伪代码实现
微信小程序
踩坑

本文要实现的需求如下

通过一个二维码,用户用不同的方式扫码,打开对应的端,具体如下

  1. 用APP扫码,打开APP页面(或者通过h5中转在跳转到原生页面)
  2. 用微信扫码,打开微信小程序页面
  3. 用支付宝扫码,打开支付宝小程序
  4. 其他方式扫码(用浏览器或苹果手机扫码器),打开微信小程序

另外要求二维码能携带动态参数

假设二维码对应的链接如下https://m.warmplace.com/#/scan-qrcode?scheme=${encodeURIComponent("app://warmplace.com/pagea?source=source_xx&shopid=shopid_xx")}

  • 这里shopid是动态的

浏览器和app扫码的实现

伪代码如下

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开发配合。

微信扫码打开微信小程序

微信小程序后台配置扫普通二维码

登录微信小程序后台 点击 开发 —> 开发管理 —> 扫普通二维码 —> 添加

image.png

补充说明下

字段说明
前缀占用规则不占用(可以设置动态参数)
配置校验文件针对域名来的,需要配置校验文件
小程序功能页面对应小程序的页面地址
测试范围开发中选择开发版本,发布后选择线上版本进行验证
测试链接开发中,必须天完整链接,否则测试无效

支付宝扫码打开小程序

image.png

字段说明
前缀占用规则不占用(支持动态参数
配置校验文件针对域名来的,需要配置校验文件
小程序功能页对应小程序的页面地址

开发阶段如何测试

  1. 支付宝扫体验码, 打开 联调设置 --》联调扫码版本
  2. 链接以上面二维码地址为前缀就行了,建议用和微信一样的二维码测试

具体方案

由于支付宝和微信的机制差异较大,所以分开来写伪代码

支付宝小程序伪代码实现

首先来看支付宝,支付宝扫码打开小程序,参数在app启动时获取,为了通用性(后续可能有扫码打开小程序其他页面的需要),封装一个通用方法launchStore.ts,将参数信息存在一个大对象里,通过key(页面路径)取参数信息.

  1. 支付宝小程序启动时(app onLaunch)接收到扫码参数信息
tsx
class App extends Component { onLaunch(launchParams: any) { dealAlipayLaunchParams(launchParams); } // ... }
  1. launchStore.ts的伪代码
ts
interface 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}) }
  1. 在业务代码中取参数信息 getLaunchParams(PAGE_PATH)
  2. 记得在合适的时机销毁扫码信息
    • 比如 在存入扫码信息的时候设置了一个存入时间ts, 取得时候可以根据当前时间-ts,如果大于某个值如30min, 或者当订单创建的时候销毁

微信小程序

微信小程序是在 页面 onLoad钩子接收的, 我们可以在useLayoutEffectcomponentWillMount中调用 dealWeappPageParams(pageParams);

当使用浏览器扫码或微信扫码时 打开微信小程序,但是参数格式略有一些区别,伪代码如下

ts
export 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 // 保留原始以便业务处理 }; }

取参数和销毁扫码信息同支付宝。

踩坑

扫码打开小程序在微信和支付宝都有坑,

先说下微信的坑

  1. 必须是自己的微信扫码,也就是开发者工具和扫码的微信 是同一个人
  2. 如果URL参数有调整比如shopid,需要重新执行第三步,然后在扫码
  3. android 扫码有坑, 将开发版小程序装入微信后,然后扫码讲道理是能如期打开小程序的,但实际小程序一直在loading, 等他loading 5分钟吧,然后杀死小程序进程杀死微信进程,重启打开微信扫码就正常了

支付宝小程序的坑

  1. 在发布平台发布支付宝小程序 体验码,扫码后打开联调设置
    • 联调设置, 点击小程序右上角三个点 --> 点击联调试着 --> 打开开关

参考文档:

本文作者:郭郭同学

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!