抖音官方文档
文章目录
-
- 简述
- 代码详细实现步骤
-
- 步骤1:SDK初始化与生命周期监听
-
- 1.1 在SDK初始化时注册 OnShow 监听
- 1.2 实现 OnShow 回调,检测侧边栏启动
- 步骤2:检查侧边栏可用性(CheckScene)
- 步骤3:显示/隐藏主界面复访入口
-
- 3.1 在界面显示时检查可用性
- 3.2 处理入口点击事件
- 3.3 领取后隐藏入口
- 步骤4:侧边栏任务引导界面
-
- 4.1 初始化界面状态
- 4.2 处理"去首页侧边栏"按钮
- 4.3 处理"立即领奖"按钮
- 步骤5:跳转到侧边栏
- 步骤6:从侧边栏返回时刷新界面
- 步骤7:判断是否从侧边栏启动
- 步骤8:发放奖励
-
- 检查今日领取状态
- 隐藏主界面入口
- 核心代码说明
-
- 关键API说明
- 场景值说明
- 最后发包
简述
整个流程是这样的 1.你需要在大厅界面某个位置加一个按钮,可以叫“入口有奖”,“奖励入口”之类 2.你需要做一个引导的界面包含一下内容 
接下来详细讲一下如何实现 方案示意 
流程如下 
代码详细实现步骤
步骤1:SDK初始化与生命周期监听
文件:GameLaunch.cs
1.1 在SDK初始化时注册 OnShow 监听
private static void InitDouyinSdkOnce()
{
#if SOLARENGINE_BYTEDANCE && !UNITY_EDITOR
if (_douyinSdkInited) return;
Debug.Log("[GameLaunch] 开始初始化抖音SDK");
// 初始化SDK
TT.InitSDK((isSuccess) =>
{
_douyinSdkInited = isSuccess;
Debug.Log($"[GameLaunch] 抖音SDK初始化{(isSuccess ? "成功" : "失败")}");
});
// 🔔 关键:立即注册 OnShow 监听(必须在SDK初始化后立即注册)
TT.GetAppLifeCycle().OnShow += OnAppShow;
Debug.Log("[GameLaunch] 已注册 TT.OnShow 生命周期监听");
#endif
}
说明:
- 必须在 TT.InitSDK 之后立即注册 OnShow 监听
- OnShow 会在冷启动、热启动(从后台返回)时触发
- 这是检测从侧边栏启动的关键
1.2 实现 OnShow 回调,检测侧边栏启动
/// <summary>
/// TT.OnShow 回调:监听应用前台事件(冷启动、热启动)
/// </summary>
private static void OnAppShow(Dictionary<string, object> param)
{
#if SOLARENGINE_BYTEDANCE && !UNITY_EDITOR
Debug.Log("========== TT.OnShow 触发 ==========");
if (param != null)
{
// 保存最新的 OnShow 参数(供后续查询使用)
_latestOnShowParams = param;
// 打印所有参数(用于调试)
Debug.Log($"[GameLaunch] OnShow 参数数量: {param.Count}");
foreach (var kvp in param)
{
Debug.Log($" – {kvp.Key} = {kvp.Value}");
}
// 🔍 解析场景值(scene)
int scene = 0;
if (param.ContainsKey("scene"))
{
object sceneObj = param["scene"];
if (sceneObj is int)
scene = (int)sceneObj;
else if (sceneObj is string)
int.TryParse((string)sceneObj, out scene);
}
Debug.Log($"[GameLaunch] OnShow 场景值 scene = {scene}");
// 🎯 检查是否是侧边栏场景值(十进制)
// 21036: 抖音首页侧边栏-最近使用
// 21012: 抖音首页侧边栏-生活动态玩游
// 101036: 抖极首页侧边栏
bool isFromSidebar = (scene == 21036 || scene == 21012 || scene == 101036);
if (isFromSidebar)
{
Debug.Log("[GameLaunch] ✅ OnShow检测到从侧边栏启动");
// 🔄 如果 UIDouyinSidebarTask 界面正在显示,刷新它
RefreshSidebarTaskUI();
}
else
{
Debug.Log($"[GameLaunch] ❌ OnShow 非侧边栏启动 (scene={scene})");
}
}
else
{
Debug.LogWarning("[GameLaunch] OnShow 参数为 null");
}
Debug.Log("========== TT.OnShow 处理完成 ==========");
#endif
}
说明:
- scene 参数是侧边栏启动的主要判断依据
- 支持三个场景值:21036、21012、101036
- 检测到侧边栏启动后,刷新任务界面显示最新状态
步骤2:检查侧边栏可用性(CheckScene)
文件:DouyinSidebarRevisitService.cs
/// <summary>
/// 检查当前宿主是否支持侧边栏场景
/// </summary>
public static async UniTask<bool> CheckSidebarSceneSupportedAsync()
{
#if SOLARENGINE_BYTEDANCE && !UNITY_EDITOR
try
{
Debug.Log("[DouyinSidebarRevisitService] 开始检查侧边栏场景支持…");
var tcs = new UniTaskCompletionSource<bool>();
// 🔍 调用 CheckScene 检查是否支持侧边栏
TT.CheckScene(
scene: "sidebar",
success: (result) =>
{
Debug.Log($"[DouyinSidebarRevisitService] CheckScene 成功: {result}");
tcs.TrySetResult(result);
},
fail: (msg) =>
{
Debug.LogWarning($"[DouyinSidebarRevisitService] CheckScene 失败: {msg}");
tcs.TrySetResult(false);
},
complete: () =>
{
Debug.Log("[DouyinSidebarRevisitService] CheckScene 完成");
}
);
bool isSupported = await tcs.Task;
Debug.Log($"[DouyinSidebarRevisitService] ✅ 侧边栏支持结果: {isSupported}");
return isSupported;
}
catch (Exception ex)
{
Debug.LogError($"[DouyinSidebarRevisitService] CheckScene 异常: {ex.Message}");
return false;
}
#else
await UniTask.Yield();
return false;
#endif
}
说明:
- 使用 TT.CheckScene("sidebar") 检查当前宿主是否支持侧边栏
- 异步方法,返回 UniTask<bool>
- 仅在支持的宿主(抖音/抖极)上返回 true
步骤3:显示/隐藏主界面复访入口
文件:UIMain_OnlineRewardManager.cs
3.1 在界面显示时检查可用性
/// <summary>
/// 刷新 BGDT 入口可见性
/// </summary>
private async UniTaskVoid RefreshBGDTEntryVisibilityAsync()
{
if (BGDTRoot == null) return;
// ✅ 检查今日是否已领取(已领取则隐藏入口)
bool hasReceivedToday = GameLaunch.HasReceivedSidebarRewardToday();
if (hasReceivedToday)
{
Debug.Log("[UIMain_OnlineRewardManager] 今日已领取侧边栏奖励,隐藏入口");
BGDTRoot.SetActive(false);
return;
}
// 已检查过就直接复用结果(避免频繁调用CheckScene)
if (_bgdtSupportChecked)
{
BGDTRoot.SetActive(_isBgdtSidebarSceneSupported);
return;
}
// 🔍 调用 CheckScene 检查侧边栏可用性
_bgdtSupportChecked = true;
_isBgdtSidebarSceneSupported = await DouyinSidebarRevisitService.CheckSidebarSceneSupportedAsync();
BGDTRoot.SetActive(_isBgdtSidebarSceneSupported);
}
说明:
- 优先检查今日是否已领取(已领取则直接隐藏)
- 使用缓存避免重复调用 CheckScene
- 仅在支持侧边栏且未领取时显示入口
3.2 处理入口点击事件
/// <summary>
/// 点击 BGDT 侧边栏入口按钮
/// </summary>
public void OnClickBGDTSidebar()
{
Debug.Log("[UIMain_OnlineRewardManager] 点击侧边栏复访入口");
// 🎨 打开侧边栏任务引导界面
if (UIDouyinSidebarTask != null)
{
UIDouyinSidebarTask.gameObject.SetActive(true);
UIDouyinSidebarTask.InitializeUI();
}
}
3.3 领取后隐藏入口
/// <summary>
/// 领取奖励后隐藏 BGDTRoot(由 GameLaunch 调用)
/// </summary>
public void HideBGDTRootAfterClaim()
{
if (BGDTRoot != null)
{
Debug.Log("[UIMain_OnlineRewardManager] 领取奖励后隐藏 BGDTRoot");
BGDTRoot.SetActive(false);
}
}
步骤4:侧边栏任务引导界面
文件:UIDouyinSidebarTask.cs
4.1 初始化界面状态
/// <summary>
/// 初始化界面:根据当前状态显示不同内容
/// </summary>
public void InitializeUI()
{
Debug.Log("[UIDouyinSidebarTask] 初始化界面");
// 🔍 检查状态
bool isFromSidebar = GameLaunch.IsFromSidebarLatest();
bool hasReceivedToday = GameLaunch.HasReceivedSidebarRewardToday();
Debug.Log($"[UIDouyinSidebarTask] 状态检查 – 从侧边栏启动: {isFromSidebar}, 今日已领取: {hasReceivedToday}");
// 🎯 状态1:今日已领取
if (hasReceivedToday)
{
descriptionText.text = "今日已领取过侧边栏奖励\\n明天再来吧!";
goToSidebarBtn.SetActive(false);
OkBtn.SetActive(false);
}
// 🎯 状态2:已从侧边栏返回,可以领奖
else if (isFromSidebar)
{
descriptionText.text = "🎉 恭喜完成任务!\\n点击下方按钮领取奖励";
goToSidebarBtn.SetActive(false);
OkBtn.SetActive(true);
}
// 🎯 状态3:未完成任务,引导去侧边栏
else
{
descriptionText.text =
"📌 完成以下任务可获得 1 个广告券:\\n\\n" +
"1️⃣ 点击下方【去首页侧边栏】按钮\\n" +
"2️⃣ 在侧边栏中找到本游戏图标\\n" +
"3️⃣ 点击图标返回游戏即可领奖";
goToSidebarBtn.SetActive(true);
OkBtn.SetActive(false);
}
}
说明:
- 根据三种状态动态显示界面:
- 未完成任务:显示 3 步指引 + "去首页侧边栏"按钮
- 已完成未领取:显示恭喜信息 + "立即领奖"按钮
- 今日已领取:显示提示信息,隐藏所有按钮
4.2 处理"去首页侧边栏"按钮
/// <summary>
/// 点击"去首页侧边栏"按钮
/// </summary>
private void OnClickGoToSidebar()
{
Debug.Log("[UIDouyinSidebarTask] 点击【去首页侧边栏】按钮");
// 🚀 调用跳转侧边栏
DouyinSidebarRevisitService.NavigateToSidebar();
}
4.3 处理"立即领奖"按钮
/// <summary>
/// 点击"立即领奖"按钮
/// </summary>
private void OnClickOK()
{
Debug.Log("[UIDouyinSidebarTask] 点击【立即领奖】按钮");
// 🎁 发放奖励
GameLaunch.GrantSidebarReward();
// 关闭界面
gameObject.SetActive(false);
}
步骤5:跳转到侧边栏
文件:DouyinSidebarRevisitService.cs
/// <summary>
/// 跳转到侧边栏
/// </summary>
public static void NavigateToSidebar()
{
#if SOLARENGINE_BYTEDANCE && !UNITY_EDITOR
Debug.Log("[DouyinSidebarRevisitService] 准备跳转到侧边栏…");
var data = new Dictionary<string, object>
{
{ "scene", "sidebar" }
};
// 🚀 调用 navigateToScene 跳转到侧边栏
TT.NavigateToScene(
data: data,
success: () =>
{
Debug.Log("[DouyinSidebarRevisitService] NavigateToScene 成功");
},
fail: (msg) =>
{
Debug.LogWarning($"[DouyinSidebarRevisitService] NavigateToScene 失败: {msg}");
},
complete: () =>
{
Debug.Log("[DouyinSidebarRevisitService] NavigateToScene 完成");
}
);
#else
Debug.LogWarning("[DouyinSidebarRevisitService] 仅在抖音环境下支持跳转侧边栏");
#endif
}
说明:
- 使用 TT.NavigateToScene 跳转
- 传入参数 { "scene": "sidebar" }
- 跳转成功后,用户可在侧边栏看到游戏图标
步骤6:从侧边栏返回时刷新界面
文件:GameLaunch.cs
/// <summary>
/// 刷新侧边栏任务界面(从侧边栏返回时调用)
/// </summary>
private static void RefreshSidebarTaskUI()
{
Debug.Log("[GameLaunch] 尝试刷新侧边栏任务界面");
// 🔍 查找 UIMain_OnlineRewardManager
var rewardManager = GameObject.FindObjectOfType<UIMain_OnlineRewardManager>();
if (rewardManager == null)
{
Debug.LogWarning("[GameLaunch] 未找到 UIMain_OnlineRewardManager");
return;
}
// 🔍 获取 UIDouyinSidebarTask 组件
if (rewardManager.UIDouyinSidebarTask == null)
{
Debug.LogWarning("[GameLaunch] UIDouyinSidebarTask 组件为 null");
return;
}
// 🔍 检查界面是否激活
if (!rewardManager.UIDouyinSidebarTask.gameObject.activeSelf)
{
Debug.Log("[GameLaunch] UIDouyinSidebarTask 界面未激活,无需刷新");
return;
}
// 🔄 刷新界面
Debug.Log("[GameLaunch] 刷新侧边栏任务界面");
rewardManager.UIDouyinSidebarTask.InitializeUI();
}
说明:
- 当 OnShow 检测到从侧边栏返回时调用
- 三层判空保护确保安全
- 仅在界面激活时刷新
- 刷新后自动显示"立即领奖"按钮
步骤7:判断是否从侧边栏启动
文件:GameLaunch.cs
/// <summary>
/// 检查最近一次启动是否来自侧边栏
/// </summary>
public static bool IsFromSidebarLatest()
{
#if SOLARENGINE_BYTEDANCE && !UNITY_EDITOR
if (_latestOnShowParams == null)
{
Debug.Log("[GameLaunch] _latestOnShowParams 为 null,尝试读取 GetLaunchOptionsSync");
// 如果还没有 OnShow 参数,尝试使用 GetLaunchOptionsSync(冷启动场景)
try
{
var launchOptions = TT.GetLaunchOptionsSync();
if (launchOptions != null && launchOptions.scene != null)
{
int scene = int.Parse(launchOptions.scene);
bool result = (scene == 21036 || scene == 21012 || scene == 101036);
Debug.Log($"[GameLaunch] GetLaunchOptionsSync scene={scene}, isFromSidebar={result}");
return result;
}
}
catch (Exception ex)
{
Debug.LogError($"[GameLaunch] GetLaunchOptionsSync 异常: {ex.Message}");
}
return false;
}
// 🔍 方法1:检查场景值 (scene)
int scene = 0;
if (_latestOnShowParams.ContainsKey("scene"))
{
object sceneObj = _latestOnShowParams["scene"];
if (sceneObj is int)
scene = (int)sceneObj;
else if (sceneObj is string)
int.TryParse((string)sceneObj, out scene);
}
// 检查是否是侧边栏场景值(十进制)
// 21036: 抖音首页侧边栏-最近使用
// 21012: 抖音首页侧边栏-生活动态玩游
// 101036: 抖极首页侧边栏
bool isFromSidebarByScene = (scene == 21036 || scene == 21012 || scene == 101036);
// 🔍 方法2:检查 launch_from 和 location 参数(备用方案)
bool isFromSidebarByLaunchParams = false;
if (_latestOnShowParams.ContainsKey("launch_from") && _latestOnShowParams.ContainsKey("location"))
{
string launchFrom = _latestOnShowParams["launch_from"]?.ToString() ?? "";
string location = _latestOnShowParams["location"]?.ToString() ?? "";
isFromSidebarByLaunchParams =
string.Equals(launchFrom, "homepage", StringComparison.OrdinalIgnoreCase) &&
string.Equals(location, "sidebar_card", StringComparison.OrdinalIgnoreCase);
}
// ✅ 使用逻辑或:任意一种方式判断成功即可
bool result = isFromSidebarByScene || isFromSidebarByLaunchParams;
Debug.Log($"[GameLaunch] IsFromSidebarLatest: scene={scene}, byScene={isFromSidebarByScene}, byParams={isFromSidebarByLaunchParams}, result={result}");
return result;
#else
return false;
#endif
}
说明:
- 双重判断机制,提高准确性:
- 场景值判断:scene == 21036/21012/101036
- 参数判断:launch_from=“homepage” && location=“sidebar_card”
- 优先使用 _latestOnShowParams,降级到 GetLaunchOptionsSync
步骤8:发放奖励
文件:GameLaunch.cs
/// <summary>
/// 发放侧边栏复访奖励(由 UIDouyinSidebarTask 调用)
/// </summary>
public static void GrantSidebarReward()
{
#if SOLARENGINE_BYTEDANCE
Debug.Log("[GameLaunch] 用户点击领取侧边栏复访奖励");
// 🔍 检查今日是否已领取过
string todayKey = "SidebarRevisit_" + System.DateTime.Now.ToString("yyyyMMdd");
int hasReceived = PlayerPrefs.GetInt(todayKey, 0);
Debug.Log($"[GameLaunch] 今日领取状态 ({todayKey}): {hasReceived}");
if (hasReceived == 0)
{
// ✅ 标记今日已领取
PlayerPrefs.SetInt(todayKey, 1);
PlayerPrefs.Save();
Debug.Log("[GameLaunch] 已标记今日领取状态");
// 🎁 发放奖励:1个广告券(与看广告逻辑一致)
Debug.Log("[GameLaunch] 开始发放广告券…");
HamburgGameManager.Instance.AddTicket();
// 💬 显示奖励提示
ToastHelper.ShowToast("侧边栏复访奖励:+1广告券");
// 📊 上报事件(用于数据分析)
EventUplogManager.Instance.TryLogEventV2("sidebar_revisit_reward_success");
Debug.Log("[GameLaunch] ✅ 侧边栏复访奖励发放成功:+1广告券");
// 🚫 通知隐藏主界面入口(今日已领取)
HideBGDTRoot();
}
else
{
Debug.Log("[GameLaunch] ⚠️ 今日已领取过侧边栏复访奖励,不重复发放");
ToastHelper.ShowToast("今日已领取过侧边栏奖励");
}
#endif
}
说明:
- 使用 PlayerPrefs 存储每日领取状态(Key: SidebarRevisit_yyyyMMdd)
- 每日限制领取一次
- 调用 HamburgGameManager.Instance.AddTicket() 发放广告券
- 发放后自动隐藏主界面入口
检查今日领取状态
/// <summary>
/// 检查今日是否已领取侧边栏奖励
/// </summary>
public static bool HasReceivedSidebarRewardToday()
{
string todayKey = "SidebarRevisit_" + System.DateTime.Now.ToString("yyyyMMdd");
return PlayerPrefs.GetInt(todayKey, 0) == 1;
}
隐藏主界面入口
/// <summary>
/// 隐藏主界面的侧边栏入口(今日已领取后调用)
/// </summary>
private static void HideBGDTRoot()
{
Debug.Log("[GameLaunch] 通知隐藏 BGDTRoot(今日已领取)");
var rewardManager = GameObject.FindObjectOfType<UIMain_OnlineRewardManager>();
if (rewardManager != null)
{
rewardManager.HideBGDTRootAfterClaim();
}
else
{
Debug.LogWarning("[GameLaunch] 未找到 UIMain_OnlineRewardManager");
}
}
核心代码说明
关键API说明
| TT.InitSDK | 初始化抖音SDK | 游戏启动时 |
| TT.GetAppLifeCycle().OnShow | 监听应用前台事件 | SDK初始化后立即注册 |
| TT.CheckScene("sidebar") | 检查侧边栏可用性 | 显示入口前 |
| TT.NavigateToScene | 跳转到侧边栏 | 用户点击"去侧边栏"按钮 |
| TT.GetLaunchOptionsSync() | 获取启动参数 | 冷启动时降级方案 |
场景值说明
| 21036 | 首页侧边栏-最近使用 | 抖音 |
| 21012 | 首页侧边栏-生活动态玩游 | 抖音 |
| 101036 | 首页侧边栏 | 抖极 |
⚠️ 重要:场景值为十进制数字,不要加前导 0(会被解析为八进制)
最后发包
Unity抖音小游戏从打包到上架流程

