跳到主要内容

在微信小程序里做带参分享 + 转化漏斗

一句话定义:在小程序的 onShareAppMessage / onShareTimeline 里把 inviter 等参数塞进 path / query,接收方页面 onLoad 解析出来落到 Cloudbase 数据库,再用云函数生成带 scene 的 wxacode 海报,组成一条可统计的拉新链路。

预计耗时:30 分钟 | 难度:基础

适用场景

  • 适用:已经接入 add-auth-wechat-miniprogram,想做邀请奖励 / 拉新分销 / 渠道追踪
  • 适用:需要给营销活动生成可大量分发的小程序码海报
  • 不适用:跨 App 分享(走不同的 SDK)
  • 不适用:H5 网页分享

环境要求

依赖版本
微信基础库(分享到聊天)1.2.4
微信基础库(分享到朋友圈)2.11.3
@cloudbase/js-sdk2.27.3
wx-server-sdklatest(用于云调用 wxacode)

另外需要:

第一步:分享按钮带参

在要被分享出去的页面里(假设是 pages/product/product.js),实现 onShareAppMessage

// pages/product/product.js
Page({
data: {
productId: '',
},

onLoad(options) {
this.setData({ productId: options.id });
},

onShareAppMessage(res) {
// res.from: 'menu' (右上角分享) | 'button' (业务按钮)
const inviter = getApp().globalData.user?.customUserId || '';
return {
title: '我刚下单了这个,你也来看看',
path: `/pages/product/product?id=${this.data.productId}&inviter=${inviter}&channel=share`,
imageUrl: '/assets/share-cover.png', // 5:4 PNG/JPG,选填,不传用默认截图
};
},
});

页面布局上,要让用户主动触发,需要在 wxml 里加一个 <button open-type="share"> 业务按钮。

返回值的几个易疏漏点:

  • path 必须以 / 开头
  • imageUrl 不传走默认截屏(微信会截当前可视区域),线上活动页通常自己提供一张固定图,避免截图时机不一致
  • 想异步组装(比如要 await 一次接口)时,把整个返回值改成 { title, path, imageUrl, promise: someAsync() }

第二步:接收方解析参数 + 落库

被分享方点开后还是同一个页面,但 onLoadoptions 会带上分享链接里的 query。

// pages/product/product.js,继续上面那段
import { db, auth } from '../../libs/cloudbase';
import { ensureLogin } from '../../libs/login';

Page({
async onLoad(options) {
this.setData({ productId: options.id });

const inviter = options.inviter;
const channel = options.channel;
if (!inviter) return;

await ensureLogin();
const me = auth.currentUser?.customUserId;
if (!me || me === inviter) {
// 邀请人和被邀请人是同一个,跳过
return;
}

// 落库到 share_events,用 inviter+invitee 复合唯一约束防重
await db.collection('share_events').add({
inviter,
invitee: me,
productId: options.id,
channel,
enteredAt: db.serverDate(),
});
},
});

注意:

  • share_events 集合的权限模式建议设为「仅创建者可读写」,被邀请方写自己的记录,_openid 自动带上
  • 重复进入应避免重复落库。最简洁的做法是云函数侧拿 (inviter, invitee, productId) 做唯一索引,前端只管发,后端去重
  • 如果做奖励发放,落库不等于发放,发放走云函数 + 内部状态机,不要直接信前端

第三步:朋友圈分享

朋友圈分享的接口是 onShareTimeline,基础库 ≥ 2.11.3 才支持,且 query 限制比群分享严:

Page({
onShareTimeline() {
const inviter = getApp().globalData.user?.customUserId || '';
return {
title: '我刚下单了这个,你也来看看',
query: `id=${this.data.productId}&inviter=${inviter}`,
imageUrl: '/assets/share-square.png', // 1:1 PNG/JPG
};
},
});

差异点:

  • 朋友圈分享不能改 path,只能用「当前页面 + query」,所以接收方拿到的还是当前页
  • query 不要带 &channel=share 这种业务标识也行,但建议加,后面统计要用
  • 用户的微信版本如果低于 7.0.15 / 基础库低于 2.11.3,微信里直接看不到「分享到朋友圈」按钮,这时分享方的 onShareTimeline 不会被调用,业务上可以不显式判断
  • 朋友圈打开是一个「单页模式」,部分 wx API 不可用,不要在落库逻辑里依赖这些 API

第四步:云函数生成带参 wxacode 海报

线下场景或者批量推广时,需要给每个邀请人生成一张带 inviter 的小程序码。云函数走云调用直接拿:

cloudfunctions/genWxacode/index.js:

const cloud = require('wx-server-sdk');
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });

exports.main = async (event) => {
const { inviter, productId } = event;

// scene 最长 32 字符,只能是 ASCII 可见字符,所以一般用紧凑 key=value 格式
const scene = `i=${inviter}&p=${productId}`;
if (scene.length > 32) {
return { ok: false, error: 'SCENE_TOO_LONG', scene };
}

try {
const res = await cloud.openapi.wxacode.getUnlimited({
scene,
page: 'pages/product/product',
checkPath: false, // 联调期为 true 容易因为页面没发布而报错
envVersion: 'release', // release / trial / develop
width: 430,
});

// res.buffer 是 PNG 二进制
const upload = await cloud.uploadFile({
cloudPath: `wxacodes/${inviter}-${Date.now()}.png`,
fileContent: res.buffer,
});

return { ok: true, fileID: upload.fileID };
} catch (err) {
return { ok: false, errcode: err.errCode, errmsg: err.errMsg };
}
};

接收方页面里要做的额外一步:小程序通过扫描码进入时,onLoad 拿到的不是 options.id 之类的 query,而是 options.scene,需要解码:

onLoad(options) {
let inviter = options.inviter;
let productId = options.id;

// 扫码进入,scene 是 URL encode 过的 'i=xxx&p=yyy'
if (!inviter && options.scene) {
const decoded = decodeURIComponent(options.scene);
const params = Object.fromEntries(
decoded.split('&').map((kv) => kv.split('=')),
);
inviter = params.i;
productId = params.p;
}

// 后续逻辑同第二步
}

要点:

  • scene 上限 32 字符,且只支持 ASCII 可见字符,长 openid(28 位)塞进去基本没空间放别的,推荐用 userIndex(数据库里另一张映射表)做短码
  • getUnlimited 没有数量上限,适合大批量;另一个接口 wxacode.get 单小程序总额度 10 万张,慎用
  • checkPath 在联调阶段建议设 false,等页面发布后再开

第五步:转化漏斗查询

数据落到了 share_events,要看转化拿 db.command 聚合一下:

// 控制台 → 数据库 → share_events → 数据查询(高级模式)
db.collection('share_events')
.aggregate()
.group({
_id: '$inviter',
invitees: $.addToSet('$invitee'),
count: $.sum(1),
})
.sort({ count: -1 })
.limit(20)
.end();

或者在云函数里跑日报,见 schedule-cloud-function-cron-job

运行验证

  1. 在微信开发者工具里,产品详情页右上角 → 转发给「文件传输助手」
  2. 用第二个测试账号点开链接,Console 应该看到 inviter 参数被解析
  3. 控制台 → 数据库 → share_events,有一条 inviter=A、invitee=B 的记录
  4. 朋友圈分享要在真机上才能正常验证,开发者工具不支持
  5. 调一次 genWxacode 云函数,在 wxacodes/ 目录看到生成的 PNG,扫码后能进对应商品页

常见错误

错误现象原因修复
转发后参数全部丢失path 没以 / 开头改成 /pages/...
朋友圈分享不弹按钮没实现 onShareTimeline 或基础库版本太低实现 onShareTimeline,在 app.json 里把 minimum 提到 2.11.3
wxacode.getUnlimited41030page 路径在已发布版本里不存在checkPath 改 false 或先发布一次小程序
wxacode 报 scene 不合法scene 里有中文或特殊字符改用纯 ASCII,中文字段先存数据库,scene 只放短 ID
同一用户进入多次重复落库没有去重share_events 加复合唯一索引 inviter+invitee+productId,或者云函数 set({ ... }, { merge: true })

相关文档

下一步