抖音直玩​

WARNING

💡 模块名: GameHelper.TTFeed

抖音直玩 ​抖音Feed直玩是抖音侧新提供的渠道能力。以游戏内的高价值信息为深度玩家的召回抓手,比如活动事件开启,体力恢复满了等信息。通过预加载能力,实现抖音推荐预览流无缝进入游戏的体验,将预加载完成的游戏在推荐流中分发给符合条件的用户。

订阅用户:在游戏中订阅后, 游戏自行将的重要事件以及重要事件开始时间和结束时间上报给服务器。当玩家退出游戏刷抖音视频的时候,抖音会拉取我们上报的事件。当成功拉取到事件时,抖音会自行根据算法推送给订阅过的玩家

非订阅用户:抖音可能会将游戏推送给未在游戏中订阅的用户。

官方的链路图如下:

1. 前置工作 ​1.1 游戏设计、素材准备 - 策划、产品、发布 ​抖音能力链接,请策划同学自行阅读理解渠道功能的详情:https://developer.open-douyin.com/docs/resource/zh-CN/mini-game/develop/guide/open-ability/minigame-feedpush-setting-guide#d9246cd0

步骤操作人示意图描述阅读理解、点位设计、素材准备策划、产品https://developer.open-douyin.com/docs/resource/zh-CN/mini-game/develop/guide/open-ability/minigame-feedpush-setting-guide#d9246cd01. 阅读理解,点位设计:理解了抖音Feed直玩的内容后,决定好需要通过「直出游戏」能力提醒的信息场景。总共有3种场景(离线收益、体力恢复、重要事件[也就是DIY]),可以只选1种,也可以选多种。2. 素材准备:设计在对应场景下的事件文案信息以及素材,准备好后提给发布同事 - 游戏内的订阅文案及订阅授权弹窗 UI图片 - 在抖音推荐流展示的文案+UI(含游戏内的气泡提醒)方案提审、获取订阅ID发布1. 方案提审:在运营-运营能力-推荐流游戏直出能力,将上一步的素材填写到申请页面中,提交审批。2. 获取订阅ID:方案审核通过后,平台将会自动生成 Content_id(订阅ID)。 该订阅id需要给到研发用于调用直玩相关功能1.2 测试设备注册 - 测试 ​步骤操作人示意图描述注册测试设备测试- 进入渠道能力板块:先登录抖音后台,然后进入运营-运营能力-推荐流游戏直出能力。点击进入第三阶段-联调测试- 添加测试设备 - 测试: - 如果测试同学自己的账号设备已经出现在名单里,一定要先删除 - 然后点击《添加设备》,此时会出一个二维码。使用真机抖音扫码后,即可添加。最好在后台刷新验证一下。建议每个设备都写下备注- 添加测试设备 - 研发:将二维码发给有后台权限那个研发扫一下2. SDK接入 - 研发 ​2.1 入口判断和事件流 ​当玩家冷启动游戏后,需要先根据isFeedEnter是否为直玩场景进入。如果不是,则直接调用reportGameReady。

如果为直玩场景,则需进一步根据feedScene判断是否为根据订阅事件刷进来的用户。如果不是,则说明用户只是偶然看到广告点进来的。

如果是根据订阅事件刷进来的用户,首先要根据feedScene和feedExtra校验刷进来的事件是否仍有效果。如果不生效了,则调用reportDelete删除作废的事件。如果仍生效,则先reportDelete删除事件,再进行发奖和功能激活等操作。

当玩家通过直玩卡片进入后,点击右上角...重启小游戏,其入口判断的值仍与首次进入时一样。所以游戏不能直接依赖抖音的入口判断,要自己校验一遍这个事件是否真的生效了!!!

例子(复访版) ​javascript// 大厅入口页面.ts

onLoad() {

if (GameHelper.TTFeed.isFeedEnter) {

console.log("!!!!!!!!判断为直玩进入");

if(!GameHelper.TTFeed.feedScene) {

console.log(`无feedScene, 属于非事件订阅用户进入,正常链路`);

GameHelper.TTFeed.reportGameReady();

} else{

// 就算抖音说是直玩进入,也告诉了feedScene,一定要先判断一下是不是真的可用!!!(比如金币体力真的满了)

// isVliadFeed代表你的直玩事件是否有效,这里直接假设判断有效

const isVliadFeed = true;

if (isVliadFeed) {

//如果是需要跳转到某个直玩场景就切场景,且在对应场景加载好后调用reportGameReady

cc.director.loadScene("TEST_TTFeed");

} else {

console.log(`非有效场景,先reportGameReady, 再删除事件,再走正常链路`);

GameHelper.TTFeed.reportGameReady();

GameHelper.TTFeed.reportDelete(.......)

}

}

} else{

console.log("!!!!!!!!判断为非直玩进入, 正常链路");

GameHelper.TTFeed.reportGameReady();

}

}

// 直玩场景.ts

start() {

// Feed场景加载完可交互后, 首先上报reportGameReady。

GameHelper.TTFeed.reportGameReady();

}抖音要求当拉到事件并推给玩家时,事件必须是可触发状态,所以整套流程必须是比较完整的闭环,比如上报了一个10分钟后的世界boss事件,玩家游玩途中把世界boss打掉了,需要及时上报删除,避免抖音拉到过期数据。

2.1.1 Feed直玩获客版能力 ​抖音Feed直玩新增一个获客版能力,指抖音通过推荐算法给已接入直玩能力的游戏推荐更多适配的新用户(没玩过游戏的用户刷抖音时刷到游戏的直玩卡片)

判断获客版进入的用户 ​通过feedGameChnl接口判断直玩用户类型

获客版:GameHelper.TTFeed.FeedEnterType.NEW_USER

复访版:GameHelper.TTFeed.FeedEnterType.OLD_USER

例子 ​在上面的基础上我们再添加获客版的逻辑

javascript// 大厅入口页面.ts

onLoad() {

if (GameHelper.TTFeed.isFeedEnter) {

console.log("!!!!!!!!判断为直玩进入");

if(GameHelper.TTFeed.feedGameChnl === GameHelper.TTFeed.FeedEnterType.NEW_USER){

//获客版启动逻辑

//跳转获客场景

//上报reportGameReady

...

GameHelper.TTFeed.reportGameReady();

}else if(GameHelper.TTFeed.feedGameChnl === GameHelper.TTFeed.FeedEnterType.OLD_USER){

//复访版启动逻辑

if(!GameHelper.TTFeed.feedScene) {

console.log(`无feedScene, 属于非事件订阅用户进入,正常链路`);

GameHelper.TTFeed.reportGameReady();

} else{

// 就算抖音说是直玩进入,也告诉了feedScene,一定要先判断一下是不是真的可用!!!(比如金币体力真的满了)

// isVliadFeed代表你的直玩事件是否有效,这里直接假设判断有效

const isVliadFeed = true;

if (isVliadFeed) {

//如果是需要跳转到某个直玩场景就切场景,且在对应场景加载好后调用reportGameReady

cc.director.loadScene("TEST_TTFeed");

} else {

console.log(`非有效场景,先reportGameReady, 再删除事件,再走正常链路`);

GameHelper.TTFeed.reportGameReady();

GameHelper.TTFeed.reportDelete(.......)

}

}

}

} else{

console.log("!!!!!!!!判断为非直玩进入, 正常链路");

GameHelper.TTFeed.reportGameReady();

}

}

// 直玩场景.ts

start() {

// Feed场景加载完可交互后, 首先上报reportGameReady。

GameHelper.TTFeed.reportGameReady();

}接入方案 ​本体包通过直玩获客(判断为获客版)

有联机功能在进入游戏会注册角色的游戏在直玩预加载阶段先不要进行注册创角

用户feed流所见的游戏是:与本体一致单机版本游玩模式

用户通过直玩进入后,游戏侧静默为用户进行注册,并做游戏进程的继承和延续

建议获客版进入的场景为游戏引导界面

官方预期效果 ​BadGood需求描述2.1.2 API ​实用属性 ​属性类型说明SCENEObject场景事件枚举OFFLINE :1 离线收益场景STAMINA :2 体力恢复场景CUSTOM :3 重要事件掉落(自定义)FeedEnterTypeObject直玩类型枚举OLD_USER:1 复访版,老用户NEW_USER:2 获客版, 新用户通过直玩卡片进入OTHER:0 非直玩isFeedEnterboolean是否为直玩卡片进入feedScenenumber直玩卡片进入的场景,对标事件上报传入的scenefeedExtrastring直玩卡片进入的参数,对标事件上报传入的extrafeedGameChnlnumber直玩类型,值对应FeedEnterTypeGameHelper.TTFeed.reportGameReady ​上报游戏准备事件给抖音, 每次冷启动仅可上报1次, 不要重复上报

直玩卡片进入时(isFeedEnter为true):仅能在feedScene对标的场景可交互时内部校验feedScene不可用时、对标事件失效时调用

非直玩卡片进入时(isFeedEnter为false):请在首场景可交互时调用

只要接入抖音Feed直玩,那么无论是否为直玩进入,无论直玩通知的事件是否有效,每次冷启动必须调用一次

参数 ​无

例子 ​javascript// 直玩场景.ts

start() {

// Feed场景加载完可交互后, 首先上报reportGameReady。

GameHelper.TTFeed.reportGameReady();

}GameHelper.TTFeed.reportAdd ​添加直玩场景的一个事件注册

服务端是通过type+scene+intentId 组成一个唯一标识符对数据库做增删改查操作。其中scene和intentId由业务层传入,所以删除事件时传入的scene和intentId需要和上报时传入的一致

startTime与endTime的时间间隔,最多为30天!否则将无法上报和入库!

参数 ​属性类型默认值是否必填说明optObject/是上报参数opt的参数: ​属性类型默认值是否必填说明scenenumber/是事件场景值。请使用TTFeed.SCENE枚举contentIdsstring[]/是该场景的订阅内容ID, 就算只有一个也请写成数组。由发布同学提供, 后台字段为content_id一般调用一次API只填一个intentIdnumber/是由研发/策划给这个事件自行定义的一个uuid, 会与scene结合起来作为事件的唯一标识.上报相同的scene和intentId会进行事件覆盖更新extrastring长度限制100以内/是透传给抖音的参数,可以在feedExtra里获取。如果不需要请传空字符串.在玩家通过抖音feed直玩进入游戏时,通过GameHelper.TTFeed.feedExtra获取到本信息。如果不需要请传空字符串startTimenumber/是事件的开始时间, 13位时间戳endTimenumber/是事件的结束时间, 13位正整数例子 ​javascriptaddBingo() {

let startTime = Date.now();

let endTime = startTime + 1000 * 60 * 180; //180分钟

console.log("addBingo: ", startTime, endTime);

GameHelper.TTFeed.reportAdd({

scene: GameHelper.TTFeed.SCENE.CUSTOM,

contentIds: ["xxxxxx"],

intentId: 8187656,

extra: "8187656",

startTime: startTime,

endTime: endTime,

});

}GameHelper.TTFeed.reportDelete ​删除直玩场景的一个事件注册。请在如下情况调用,宗旨是保持事件闭环:

直玩进入且可以发奖,发奖前调用

直玩进入但不可发奖, 删除过期事件

事件的行为过期了,顺便调用

其他闭环情景

参数 ​属性类型默认值是否必填说明optObject/是上报参数opt的参数: ​属性类型默认值是否必填说明scenenumber/是场景值。请使用TTFeed.SCENE枚举intentIdnumber/是由研发/策划给这个事件自行定义的一个uuid, 会与scene结合起来作为事件的唯一标识例子 ​javascriptdelBingo() {

console.log("delBingo");

GameHelper.TTFeed.reportDelete({

scene: GameHelper.TTFeed.SCENE.CUSTOM,

intentId: 8187656,

});

}2.1.3 示例代码 ​以下仅为一个示例代码,不代表必须这样做!!!! 各游戏自行根据理解实现功能,

javascript// 大厅代码.ts

onLoad() {

if (GameHelper.TTFeed.isFeedEnter) {

console.log("!!!!!!!!判断为直玩进入");

if(GameHelper.TTFeed.feedGameChnl === GameHelper.TTFeed.FeedEnterType.NEW_USER){

//获客版启动逻辑

//跳转获客场景

...

}else if(GameHelper.TTFeed.feedGameChnl === GameHelper.TTFeed.FeedEnterType.OLD_USER){

//复访版启动逻辑

if(!GameHelper.TTFeed.feedScene) {

console.log(`无feedScene, 属于非事件订阅用户进入,正常链路`);

GameHelper.TTFeed.reportGameReady();

} else{

// 就算抖音说是直玩进入,也告诉了feedScene,一定要先判断一下是不是真的可用!!!(比如金币体力真的满了)

// isVliadFeed代表你的直玩事件是否有效,这里直接假设判断有效

const isVliadFeed = true;

if (isVliadFeed) {

//如果是需要跳转到某个直玩场景就切场景,且在对应场景加载好后调用reportGameReady

cc.director.loadScene("TEST_TTFeed");

} else {

console.log(`非有效场景,先reportGameReady, 再删除事件,再走正常链路`);

GameHelper.TTFeed.reportGameReady();

GameHelper.TTFeed.reportDelete(.......)

}

}

}

} else {

console.log("!!!!!!!!判断为非直玩进入");

// 如果非直玩进入,则在首页可交互时,直接上报reportGameReady

GameHelper.TTFeed.reportGameReady();

}

}

// 直玩场景TEST_TTFeed.ts

// 直玩场景.ts

start() {

// Feed场景加载完可交互后, 首先上报reportGameReady。

GameHelper.TTFeed.reportGameReady();

// 在进行游戏发奖逻辑操作

if (!GameHelper.TTFeed.feedExtra) {

console.log(this.PREFIX, `无feedExtra,针对场景${GameHelper.TTFeed.feedScene}的唯一事件发奖`);

switch (GameHelper.TTFeed.feedScene) {

case GameHelper.TTFeed.SCENE.OFFLINE:

// 这里先调用reportDelete接口进行删除事件上报,再发奖

break;

case GameHelper.TTFeed.SCENE.STAMINA:

// 这里先调用reportDelete接口进行删除事件上报,再发奖

break;

case GameHelper.TTFeed.SCENE.CUSTOM:

// 这里先调用reportDelete接口进行删除事件上报,再发奖

break;

default:

break;

}

} else {

console.log(this.PREFIX, `发现feedExtra信息: ${GameHelper.TTFeed.feedExtra}`);

switch (GameHelper.TTFeed.feedExtra) {

case "8187654":

// 建议先进行事件上报,再进行游戏逻辑操作

this.delStamina();

console.log(this.PREFIX, "领体力 - 发奖完成");

break;

case "8187656":

this.delBingo();

console.log(this.PREFIX, "binGo活动 - 发奖完成");

break;

default:

break;

}

}

}

addStamina() {

let startTime = Date.now() + 1000 * 60 * 60; //1小时后事件开始

let endTime = startTime + 1000 * 60 * 120; //从开始时间计算持续2小时

console.log("addStamina: ", startTime, endTime);

GameHelper.TTFeed.reportAdd({

scene: GameHelper.TTFeed.SCENE.STAMINA,

contentIds: ["xxxxxx"],

intentId: 8187654, //业务层自定义的id

extra: "8187654", // 建议为了方便,直接把intentiD转为字符串传进来,无论一个scene底下是否有多个intentId

startTime: startTime,

endTime: endTime,

});

}

delStamina() {

console.log("delStamina");

GameHelper.TTFeed.reportDelete({

scene: GameHelper.TTFeed.SCENE.STAMINA,

intentId: 8187654,

});

}2.2 订阅机制 ​在策划指定的事件订阅点位,调用订阅接口。

请勿高频调用,渠道存在频控。一般来说,我们希望玩家先进行订阅,再发送事件上报。

建议游戏每次冷启动第一次仍走API进行一遍判断,然后将状态值缓存到内存中,后续直接根据缓存的状态值来判断是否订阅成功了

真机测试:订阅接口只能在真机测试。

弹框逻辑:抖音侧是根据scene来判断是否弹框的,每个场景的首次订阅会弹框。

例如场景CUSTOM首次订阅事件id 111,会弹框。当场景CUSTOM再次订阅事件id 222,此时不会弹框。GameHelper.TTFeed.subscribe ​参数 ​属性类型默认值是否必填说明scenenumber/是场景值。请使用TTFeed.SCENE枚举contentIdsstring[]/是该场景的订阅内容ID, 就算只有一个也请写成数组。由发布同学提供, 后台字段为content_idsuccess(res)=>void/否订阅成功回调fail(err)=>void/否订阅失败回调例子 ​typescriptprivate isSubscribe = false;

// 假设到了策划的订阅点位

GameHelper.TTFeed.subscribe({

scene: GameHelper.TTFeed.SCENE.CUSTOM,

contentIds: ["xxxxxxxxx"],

success: (res) => {

console.log("订阅成功", res);

this.isSubscribe = true

},

fail: (err) => {

this.isSubscribe = false;

console.log("业务层订阅失败", err);

},

});

// ...... 其他操作. 本次冷启动后续根据内存的值去判断

if (this.isSubscribe) {

} else {}3. 功能测试 - 研发、测试 ​本功能仅可使用正式的appId进行测试

3.1 订阅测试 ​订阅接口只能在真机测试,记得打开SDK调试模式看打印。

本部分无需上传测试包和刷抖音视频流

弹框逻辑:抖音侧是根据scene来判断是否弹框的,每个场景的首次订阅会弹框。

例如场景CUSTOM首次订阅事件id 111,会弹框。当场景CUSTOM再次订阅事件id 222,此时不会弹框在研发调用的订阅点位,如果是真实调用的SDK方法:

如果用户之前已经订阅过/拒绝过,则SDK会有如下日志打印。首次拉取订阅弹窗且订阅成功首次拉取订阅弹窗且订阅失败已经订阅成功后再调用已经拒绝订阅后再调用如果用户为之前未订阅过,则抖音会弹订阅框。根据玩家的同意和拒绝与否,SDK会额外打印上面的内容3.1.1 FAQ1 - 请勿拒绝订阅授权 ​为了测试方便,订阅弹框时请勿点击X和拒绝。

拒绝订阅后会有1天的间隔时间无法再次拉起订阅弹窗,此时需要调整手机系统时间才行!

3.1.2 FAQ2 - 如何关闭订阅授权再次测试 ​接受订阅后可以通过到设置里关掉,然后重启游戏即可。以达到反复调用订阅接口测试弹框的作用

3.2 Feed事件链路测试 ​订阅接口只能在真机测试,记得打开SDK调试模式看打印。

本部分无需上传测试包和刷抖音视频流

需要测试游戏的整个事件上报链路是否与策划设计相同。一个事件有添加点位,必然也应该有删除的点位。点位这块只能由业务自行设计测试案例。当事件点位触发后,请注意如下的SDK打印即可(需要在开启sdk内部打印)

3.3 事件流刷新和整体验证 ​订阅接口只能在真机测试,记得打开SDK调试模式看打印。

本部分需要上传测试包和刷抖音视频流!

本部分就是全真模拟了。测试前提:

后台权限已经添加

测试设备已经添加

3.3.1 测试前提 - 权限设备 ​请先确保测试的人员有开发者权限,测试设备均已在后台扫码添加。

3.3.2 测试前提 - 有当前时间可触发的事件!!【重要】 ​抖音会推送直玩卡片的一个前提条件,就是用户的事件库里,在当前的时间段,有满足时间条件的事件!!!

请确保测试时,这个游戏用户已经添加了一个满足时间条件的事件(startTime<当前时间<小于endTime)

正常游戏领完奖后,会进行事件删除。注意再次刷新前重新加一下。不然会一直纳闷怎么刷不到卡片

startTime与endTime的时间间隔,最多为30天!

3.3.3 上传测试包 ​需要测试的游戏,请提前打好包,然后按照如下操作进行上传。千万不要忘记勾选《选择测试通道》,上传操作务必小心!!!

如果没《选择测试通道》这个选项,请升级抖音开发者工具

3.3.4 检查弹框 ​抖音侧总共会弹3个弹窗,各弹框逻辑如下

预启动游戏游戏首帧渲染完成feed直玩游戏已加载完成图例时机说明直玩数据推送到客户端,抖音准备向后台请求加载游戏。类似于正常链路中,看到游戏Icon手指准备去点击进游戏游戏首次出现渲染画面(从黑屏变成有画面,并不代表能交互)出不来问题排查测试设备有没有添加到后台?如果之前添加过,删除后再扫码加一遍游戏启动挂了,先自测调试好首先通过抖音扫码进入游戏的测试版本,在右上角「···」中打开更多面板,在更多面板中选择「打开调试」,开启vconsole能力。然后刷抖音直到出现前面两个弹框后,才能去再次扫码。此时会强制跳游戏,看下控制台reportGameReady 为什么没有被调用3.3.5 检查直玩卡片信息正确 ​当《Feed直玩游戏已加载完成》的弹框出现以后,再刷几个视频就会出现直玩卡片。

此时需要检查直玩卡片的提示内容(见图里红框),是否与发布在后台注册的《生成的推荐页文案描述》字段一致

3.3.6 进入游戏,检查整体链路 ​点击继续游戏后,进入到游戏页面。此时只能根据游戏的具体情况进行测试了。

3.4 获客版能力测试(新) ​抖音目前还没有提供测试方案,研发可以先自己检查下复访(非新用户刷到直玩卡片)情况下抖音直玩进入游戏时feedGameChnl值是否正确,然后正常编写获客版情况下游戏逻辑,给测试提供一个模拟获客版进入游戏的场景

4. 新事件埋点验证 - 测试 ​研发只用正常调用栏目2的方法。新事件,随着业务层的功能调用一起,在SDK内部自动上报。

4.1 直玩进入 ​当玩家时通过刷到抖音Feed卡片进入时,会上报直玩进入事件。需要校验事件的存在性,以及其属性值是否正确

事件名:ttfeed_entry

事件属性

feedscene: number 订阅场景 - 【必有,取值为1/2/3】

1 离线收益场景

2 体力恢复场景

3 重要事件掉落(自定义)

extra: string 业务层透传的信息 - 【可能有,研发传了就要验证】

4.2 订阅准备,订阅成功 ​当研发在策划埋点拉起订阅时,且用户之前没有订阅成功时,会在拉起订阅弹框期间,上报两个事件: 准备订阅、订阅成功(失败就没有)

如果一次性订阅了X个订阅内容ID,事件就会有X份

事件名:ttfeed_subscribe

事件属性

feedtype:number 0-准备订阅 1-订阅成功

feedscene: 订阅场景 number 【必有,取值为1/2/3】

1 离线收益场景

2 体力恢复场景

3 重要事件掉落(自定义)

contentid:订阅内容id string【必有,必须与订阅点位的id一致】

4.3 游戏准备就绪 ​只要接入抖音Feed直玩,那么无论是否为直玩进入,无论直玩通知的事件是否有效,都必然上报一条《游戏就绪行为准备上报》事件

如果上报给渠道成功,则会有一条《游戏就绪行为上报成功》事件。

事件名:ttfeed_game_ready

事件属性

feedtype:number 0 - 准备上报 1-上报成功【必有】FAQ: 为什么游戏没有上报?

ANS:游戏业务中没有调用reportGameReady方法。无论是否为直玩进入,无论直玩通知的事件是否有效,都要调用该方法。

4.4 抖音Feed事件 ​在游戏的策划埋点,上报给Feed服务器增加或删除Feed事件时,SDK会同时上报一条给新事件后台。

这个上报会跟随研发调用reportAdd和reportDelete方法触发。

仅会在Feed服务器事件上报成功时,SDK才会报给新事件

事件名: ttfeed_reportev

事件属性

feedtype: number 0-增加行为 1-删除行为 - 【必有,与行为需一致】

intentid: number 研发定义的行为uuid-【必有,与游戏埋点的内容需一致】

(type=0才传)extra:string 透传的字段,type=0时很关键 【feedtype=0时可能有,研发传了就要验证】

(type=0才传)starttime:number 研发定义的Feed事件生效时间 【feedtype=0时必有】

(type=0才传)endtime:number 研发定义的Feed事件截止时间 【feedtype=0时必有】

5. 完成渠道后台的注册表 - 测试 ​测试完成之后,有测试同学在渠道后台的表打钩。

上传提审包后,点击下一步,告诉发布可以提审即可。

6. 配置正式服务器地址 - 测试 ​配置正式服务器的地址。跟栏目1.3配置的是一个地址