字节跳动小程序开发笔记:广告与支付踩坑总结

1. 激励视频广告支持版本

激励视频广告对客户端版本有要求:

  • 抖音安卓:10.3 及以上
  • 抖音 iOS:10.7 及以上

需要通过 tt.getSystemInfoSync() 判断版本号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 抖音版本验证
function validVer() {
let sys = tt.getSystemInfoSync();
console.log(sys.appName, sys.platform, sys.version, sys);

// 如果不是抖音 App,返回 true (表示不支持激励视频或不需要处理)
if (sys.appName !== "Douyin") {
return true;
}

// 安卓抖音 10.3.0 支持,iOS 10.7.0 支持激励视频
// 此处需补充具体的版本对比逻辑
// ...
}

2. 小程序广告相关设置

2.1 激励视频初始化

建议在加载广告前先进行版本判断。

1
2
3
4
5
6
7
/* 需先做版本判断处理 */
if (!this.verFlag) {
// 抖音高版本,显示模态框或加载广告
this.showModel();
} else {
// 头条 or 低版本处理
}

全局广告对象初始化:

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
/* 全局变量 */
let videoAd = null;

/* 初始化广告对象方法 */
initTTAd() {
let that = this;
if (tt.createRewardedVideoAd) {
/* 设置广告对象 */
videoAd = tt.createRewardedVideoAd({
adUnitId: "你的广告ID",
});

/* 捕捉错误 */
videoAd.onError((err) => {
console.log(err.errCode);
if (err.errCode == "1004") {
// 暂时没有合适的广告,请稍后在试
}
});

/* 监听广告关闭 */
videoAd.onClose((res) => {
if (res.isEnded) {
// 观看成功 给予奖励
} else {
// 中途关闭,不予奖励
}
});
}
}

注意: 字节小程序激励视频全局只有一个 videoAd 实例,重复创建没有用。如果在不同页面使用可能会产生冲突。

推荐参考封装方法:博客园:字节小程序激励视频封装

2.2 Banner 广告组件 (AD)

ad 组件主要支持头条小程序,可通过外部 view 设置样式。

1
2
3
4
5
6
7
8
9
10
<!-- AD组件支持只头条小程序 , 可通过外部view设置样式 -->
<view class="ad" v-if="touTAD">
<ad
unit-id="你的广告ID"
ad-intervals="100"
bindload="adloadhandler"
binderror="aderrorhandler"
bindclose="adclosehandler"
></ad>
</view>

3. 输入框违规字段验证 (后端处理)

内容安全检测流程:先获取 access_token,再调用文本检测接口。

  • 获取 Token: GET https://developer.toutiao.com/api/apps/token
  • 检测文本: POST https://developer.toutiao.com/api/v2/tags/text/antidirt
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
let url = "https://developer.toutiao.com/api/v2/tags/text/antidirt";

/* 1. 构造请求数据 */
let data = {
tasks: [
{
content: "需要验证的用户输入内容",
},
],
};

/* 2. 发送请求 (示例代码) */
// request({
// url: url,
// method: "POST",
// token: token, // 这里的 token 放在 header 或 query 中视具体封装而定
// data: data,
// })

/* 3. 处理响应 */
// 请求成功后,验证 prob 字段
let resData = res.data.data;

// 如果 predictes[0].prob 为 1,表示有不合规字段
let flag = resData.some((item, index) => {
return item.predicts[0].prob == 1;
});

if (flag) {
console.log("包含违规内容");
}

4. 微信 H5 支付 (中间页模式)

注意: iOS 暂不支持虚拟支付,需要做平台判断。

以下是构造字节跳动支付所需的 orderInfo 的核心逻辑(通常在后端进行签名):

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
// 微信支付成功后处理逻辑
function tPay(res, ip = "127.0.0.1", outOrderNo) {
// 1. 获取支付链接,分解 XML (需自行实现 getXMLNodeValue)
let mweb_url = getXMLNodeValue("mweb_url", res.data.toString("utf-8"));

// 2. 字节支付 Secret
let key = "xxxxxxx";

// 3. 构造字节支付需要的 orderInfo 对象
let orderInfo = {
app_id: "80085xxxx", // 头条支付分配给商户 app_id
body: "xx订单", // 商户订单详情
currency: "CNY", // 固定值: CNY
merchant_id: "190xxxx", // 头条支付分配给商户的商户号
notify_url: `http://tp-pay.snssdk.com/cashdesk/test/paycallback`, // 回调地址
out_order_no: outOrderNo, // 商户订单号
payment_type: "direct", // 固定值:direct
product_code: "pay", // 固定值:pay
sign_type: "MD5", // 固定值:MD5
subject: "xx订单", // 商户订单名称
timestamp: createTimeStamp(), // 发送请求的时间戳,精确到秒
total_amount: 100, // 金额,整型,单位:分(不能有小数)
trade_time: createTimeStamp(), // 下单时间戳,精确到秒
trade_type: "H5", // 固定值:H5
uid: "80085xxxx", // uid 可和 app_id 一样
valid_time: "300", // 订单有效期
version: "2.0", // 固定值:2.0
wx_type: "MWEB", // wx_url 非空时传 'MWEB'
wx_url: mweb_url, // 微信返回的 H5 支付链接
};

// 4. 参数排序 (需自行实现 sortStr)
let reStr = sortStr(orderInfo, key, false);

// 5. MD5 签名 (需自行实现 nodMd5)
let sign = nodMd5(reStr);
orderInfo.sign = sign;

// 6. 补充 risk_info (ip 不参与签名)
orderInfo.risk_info = `{"ip":"${ip}"}`;

return orderInfo;
}

扩展阅读: H5 支付详细流程可参考:博客园:字节小程序接入 H5 支付