Combos SDK API 参考
SDK 1.1.0 · 核对日期:2026-10-13。本文完整说明游戏通过 window.combos 使用的 JavaScript API:10 个全局方法,以及 TikTok 客户端的 4 个方法。每个方法都有输入、返回值、失败行为和示例。想从头做一个游戏,先看 TikTok 实战教程;需要按钮绑定示例,参见账号与多语言。
调用通过 Combos 宿主完成。这些是 JavaScript 方法,不是 REST 路径:游戏无需配置 API 地址、API Key、HTTP 响应信封,也无需手工发送 postMessage。Promise 成功返回的就是结果本身,外层没有 data。
运行环境与 TypeScript 准备
支持该能力的 Combos 播放器会注入 SDK。不要再加载第二份运行时脚本,也不要覆盖 window.combos。独立网页或本地预览中可能没有这个对象,应在浏览器代码里先判断,并保留基础玩法。服务端渲染期间不要读取 window。
需要编辑器补全时,把公开类型声明 保存为游戏源码旁的 combos-host-sdk.d.ts,确保 TypeScript 项目包含该目录。声明文件只提供类型,不安装 SDK。下文 TTLiveClient 等类型通过 import type 引入,不产生运行时依赖。
curl --fail --location https://combos.converge.ai/host-sdk.d.ts --output ./combos-host-sdk.d.tsasync function readCapabilities() {
const sdk = window.combos;
if (!sdk) return [];
const { methods } = await sdk.init();
return methods;
}每个 TypeScript 代码块都是独立辅助函数,由你的界面调用并处理 Promise 异常。名字带 AfterClick 的函数应绑定玩家主动操作。示例函数中的 null 按代码表示能力不可用或登录取消,不是 SDK 新增的返回值。JSON 展示原始请求或返回结构,身份和时间均为示例值;示例界面文案应按游戏语言调整。
接口速查
| 方法 | 用途 | 宿主请求超时 |
|---|---|---|
init() | 查询宿主能力 | 3 秒,随后兼容降级 |
checkSession() | 查询当前登录态 | 10 秒 |
login() | 打开宿主登录流程 | 5 分钟 |
getUserInfo() | 读取游戏内玩家身份 | 10 秒 |
requestI18n(params) | 翻译已显示的原文 | 30 秒 |
getSetting() | 读取 Cloud Ability 授权记录 | 10 秒 |
authorize(params) | 申请一个权限 | 5 分钟 |
openSetting() | 打开宿主权限设置 | 5 分钟 |
getCloudAbilitySession() | 获取短期会话凭据 | 10 秒 |
getTTLiveClient() | 取得当前页面的客户端 | 同步,无网络请求 |
client.connect(options) | 建立互动连接 | 独立生命周期,无固定总超时 |
client.getLiveStatus() | 查询互动状态 | 先获取会话,再执行最多 5 秒的 HTTP 查询 |
client.onStatusChange(listener) | 订阅状态变化 | 同步 |
client.disconnect() | 停止客户端 | 同步 |
首次宿主调用还可能花最多 3 秒查询能力。这些是 SDK 的等待期限,不是服务可用性承诺。公开方法不接受自定义 timeout、AbortSignal、成功回调式参数或额外身份参数。
先确认当前宿主支持什么
以 init().methods 为准,不能只判断函数是否存在。当前 Web 宿主支持 checkSession 和 login;getUserInfo 需要可信的游戏上下文,requestI18n 需要 Play 宿主提供翻译能力,TikTok 需要对应能力和已登记的启动上下文。旧版 Web 或 App 宿主可能不同。
当前 Web 宿主不声明 getSetting、authorize、openSetting、getCloudAbilitySession 这四项能力。本文保留它们的契约,供明确声明支持的宿主使用。发布游戏不会自动开通 Cloud Ability 或 TikTok。方法不在能力列表中时,SDK 会在发送该方法的宿主请求之前以 unsupported 拒绝。
getTTLiveSession 是内部能力名称。使用 getTTLiveClient() 前要检查它,但不存在公开的 combos.getTTLiveSession() 方法。全局 API 也没有 logout、通用 request、云存档、支付、排行榜或礼物注册方法。
初始化与账号
combos.init()
combos.init(): Promise<ICombosHostInitResult>
参数:无。是否需要登录:否。返回:包含 methods 数组的 Promise,数组列出宿主支持的能力名称。它不会登录、打开弹窗,也不会建立 TikTok 连接。
并发调用共用一次查询,结果在当前游戏页面内缓存;其他宿主方法也会自动初始化。有效数组里的未知名称和重复项会被过滤。查询失败、结果结构无效或 3 秒内无回复时,返回 ['checkSession', 'login'];有效的空数组仍是空数组。这个兼容降级不能证明独立页面有可用宿主,后续调用仍可能超时。没有公开的强制刷新参数。
下面是响应结构示例,不能把这份列表硬编码成所有宿主都支持的能力。
interface ICombosHostInitResult {
methods: Array<
| 'checkSession' | 'login' | 'getUserInfo' | 'requestI18n'
| 'getSetting' | 'authorize' | 'openSetting'
| 'getCloudAbilitySession' | 'getTTLiveSession'
>;
}{
"methods": ["checkSession", "login", "getUserInfo", "requestI18n", "getTTLiveSession"]
}combos.checkSession()
combos.checkSession(): Promise<boolean>
参数:无。是否需要登录:否。返回:宿主报告已登录时为 true,否则为 false。只读取状态,不打开登录界面。SDK 只有在结果严格等于布尔值 true 时才认为已登录,不接受字符串或对象等真值。
每次独立的账号操作之前即时查询,不要长期缓存:检查后登录态也可能变化。传输错误和超时会拒绝 Promise,不能把它们当成正常的 false 或已经退出登录。返回 false 后,由玩家选择是否登录。同一次操作里 login() 成功后直接继续,无需再次检查。
async function readSession() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('checkSession')) return null;
return sdk.checkSession();
}combos.login()
combos.login(): Promise<ICombosHostLoginResult>
参数:无;不要传账号 ID、密码或 token。是否需要登录:否。副作用:需要时打开宿主登录流程。应由玩家操作触发,等待期间禁用发起按钮。
status | 含义与下一步 |
|---|---|
success | 可以继续当前操作;无需刷新、轮询或再次检查登录态 |
cancelled | 玩家取消,返回游戏即可,不进入报错循环或自动重开弹窗 |
取消是正常返回。弹窗被阻止、传输失败、登录态同步失败或超时会拒绝 Promise。返回结构无效或状态未知时,SDK 报 request_failed。当前 Web 宿主对已登录玩家直接返回 success。结果不含凭据或玩家资料;资料需要单独查询。
interface ICombosHostLoginResult {
status: 'success' | 'cancelled';
}async function loginAfterClick() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('checkSession') || !methods.includes('login')) return null;
if (await sdk.checkSession()) return { status: 'success' as const };
return sdk.login();
}{ "status": "success" }combos.getUserInfo()
combos.getUserInfo(): Promise<ICombosHostUserInfo>
参数:无。前提:宿主声明 getUserInfo、存在可信游戏上下文且玩家已登录。未登录调用报 session_required。之前检查过登录态,也要处理实际请求时会话失效的情况。
| 字段 | 类型与必填性 | 含义 |
|---|---|---|
appId | 必填,非空 string | 当前游戏的应用身份;不是 Post 链接或游戏自行传入的项目 ID |
openId | 必填,非空 string | 玩家在该应用内的身份,应与 appId 一起使用 |
nickName | 必填 string,可为空 | 展示昵称,需要准备缺省名称 |
avatarUrl | 必填 string,可为空 | 展示头像,缺失或加载失败时使用备用头像 |
locale | 必填,非空 string | 玩家已保存的公开产品语言,如 en、zh-CN;未保存时为当前产品语言 |
结果没有邮箱、手机号、平台用户 ID、登录 token 或 Cloud Ability 会话。不能用 openId 推断跨应用身份,也不能把浏览器返回结果作为自己服务端的鉴权证明。昵称按文本展示,不作为 HTML。身份缺失、展示字段不是字符串等无效结果会报 request_failed;宿主或后端还可能返回其他错误码。
interface ICombosHostUserInfo {
appId: string;
openId: string;
nickName: string;
avatarUrl: string;
locale: string;
}async function readPlayerAfterClick() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('checkSession') || !methods.includes('login') || !methods.includes('getUserInfo')) return null;
if (!(await sdk.checkSession())) {
const login = await sdk.login();
if (login.status === 'cancelled') return null;
}
return sdk.getUserInfo();
}{
"appId": "app_example",
"openId": "player_example",
"nickName": "Alex",
"avatarUrl": "",
"locale": "en"
}游戏多语言
combos.requestI18n(params)
combos.requestI18n(params: ICombosHostRequestI18nParams): Promise<ICombosHostI18nResult>
登录要求:当前 Web 翻译桥接没有登录前置条件,但宿主必须声明 requestI18n。先显示原文,翻译作为异步增强,不应阻塞游戏首屏。
| 参数 | 类型 | 必填 | 含义 |
|---|---|---|---|
sourceLocale | string | 是 | 提交文本的原始语言,如 en、zh-CN,不是目标语言 |
sourceTexts | string[] | 是 | 游戏中已经显示的原始字符串或稳定模板,保留精确内容 |
没有 targetLocale 参数,目标语言由宿主当前产品语言决定。当前 Web 实现会去掉语言标识两端空白、跳过空字符串和非字符串项、去重相同原文,并按每批 50 条向翻译服务请求。50 是内部批次大小,不是 SDK 公开的入参数量上限。建议按小批稳定界面文案调用,确保有机会在 30 秒内完成,不要逐动画帧请求。
interface ICombosHostRequestI18nParams {
sourceLocale: string;
sourceTexts: string[];
}
type ICombosHostI18nResult =
| { needed: false }
| { needed: true; locale: string; translations: Record<string, string> };{
"sourceLocale": "en",
"sourceTexts": ["Play", "Score: {score}"]
}{
"needed": true,
"locale": "zh-CN",
"translations": { "Play": "开始", "Score: {score}": "得分:{score}" }
}| 返回字段 | 含义 |
|---|---|
needed: false | 保留全部原文;这个分支没有 locale 和 translations |
needed: true | 有翻译结果,但映射仍可能不完整 |
locale | 宿主选择的目标语言,仅在 needed 为 true 时存在 |
translations | 原始字符串 → 翻译字符串;键是精确原文,不是业务自定义 ID |
源语言与宿主语言等价、没有有效文本、翻译不可用、当前 Web 后端翻译失败,都可能正常返回 { needed: false }。SDK 也会把无效的翻译回包转成这一分支。不支持的方法和传输超时仍可能抛错。映射里缺失或为空的项逐条保留原文,使用 textContent 更新,不能用 innerHTML。
先翻译 Score: {score} 这样的模板,再填动态值;SDK 不负责插值。应用翻译模板前检查必需占位符是否保留。多次调用应保留最初原文,不要拿已经翻译过的文本搭配旧 sourceLocale 再请求。
async function translateVisibleLabels(nodes: HTMLElement[]) {
const sourceTexts = nodes.map(node => node.textContent ?? '');
const sdk = window.combos;
if (!sdk) return;
try {
const { methods } = await sdk.init();
if (!methods.includes('requestI18n')) return;
const result = await sdk.requestI18n({ sourceLocale: 'en', sourceTexts });
if (!result.needed) return;
nodes.forEach((node, index) => {
node.textContent = result.translations[sourceTexts[index]] || sourceTexts[index];
});
} catch {
// Source text stays visible.
}
}可选 Cloud Ability 接口
当前 Web 宿主不声明下面四个方法,每项都要单独检查。示例仅用于支持它们的宿主,不会借调用自动开通能力。即使玩家授权成功,也不代表游戏所有者已启用底层能力。
type CombosHostPermissionScope = 'ai_model';
type CombosHostAuthorizationDecision =
| 'AUTHORIZATION_DECISION_UNSPECIFIED'
| 'AUTHORIZATION_DECISION_GRANTED'
| 'AUTHORIZATION_DECISION_DENIED';
interface ICombosHostPlayableAuthorization {
decision: CombosHostAuthorizationDecision;
decidedAtMs: number;
}
type ICombosHostAuthSetting = Readonly<
Partial<Record<CombosHostPermissionScope, ICombosHostPlayableAuthorization>>
>;
interface ICombosHostAuthorizeParams { scope: CombosHostPermissionScope }
interface ICombosHostCloudAbilitySession { session: string; expiresAtMs: number }| 字段或取值 | 契约 |
|---|---|
scope | 当前只定义 'ai_model',authorize 必填 |
decision | 运行时接受 AUTHORIZATION_DECISION_GRANTED 或 AUTHORIZATION_DECISION_DENIED |
AUTHORIZATION_DECISION_UNSPECIFIED | 导出的类型联合里包含这个零值,但 SDK 不接受它作为有效返回的授权决定 |
decidedAtMs | 必填有限数值,Unix 毫秒时间;不是秒,也不是过期时间 |
缺少 ai_model 键 | 玩家尚未被询问过当前游戏的该权限,与拒绝不同 |
session | 必填非空凭据字符串,敏感且短期有效,仅保留在内存中 |
expiresAtMs | 必填有限数值,Unix 毫秒过期时间;不承诺固定有效时长 |
这些接口不接收用户、设备、项目、Post 或游玩实例 ID。可信上下文与登录、权限界面由宿主负责。执行受保护操作前满足该宿主的登录要求;拒绝权限后不要循环弹窗。
combos.getSetting()
combos.getSetting(): Promise<ICombosHostAuthSetting>
参数:无。超时:10 秒。读取当前玩家对当前游戏的授权记录,不打开权限设置。返回 ICombosHostAuthSetting,缺少 ai_model 记录时 {} 是合法结果。
SDK 只保留已知的 ai_model 权限。该键存在时,必须包含同意或拒绝的决定及有限数值 decidedAtMs,无效记录报 request_failed。不能把缺失当成拒绝;玩家修改设置后,也不能继续使用旧决定。
{
"ai_model": {
"decision": "AUTHORIZATION_DECISION_GRANTED",
"decidedAtMs": 1791800000000
}
}async function readPermissionSettings() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('getSetting')) return null;
return sdk.getSetting();
}combos.authorize(params)
combos.authorize(params: ICombosHostAuthorizeParams): Promise<ICombosHostPlayableAuthorization>
参数:必填对象,包含 scope: 'ai_model';没有默认值,不接受通配符、权限数组或调用方自行指定的决定。超时:5 分钟。交互式权限请求由宿主控制,应从玩家操作发起。
返回单条授权记录,不是整个设置对象。AUTHORIZATION_DECISION_DENIED 是正常返回,只有 GRANTED 才能继续相应授权操作;拒绝后不自动重复请求。该接口没有 cancelled 返回契约,关闭界面的含义应按实际授权记录或异常处理,不能套用登录接口的状态。不支持、回包无效、传输错误和超时都会拒绝 Promise。
async function requestAiPermissionAfterClick() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('authorize')) return null;
return sdk.authorize({ scope: 'ai_model' });
}{ "decision": "AUTHORIZATION_DECISION_DENIED", "decidedAtMs": 1791800000000 }combos.openSetting()
combos.openSetting(): Promise<ICombosHostAuthSetting>
参数:无。超时:5 分钟。从玩家操作打开宿主权限设置,返回操作后的 ICombosHostAuthSetting,不接受用来静默授予权限的设置对象。
用返回值刷新界面,处理权限缺失或被拒绝的情况。它返回的不是布尔值、单条授权记录或登录状态;记录校验与 getSetting() 相同。不支持、回包无效和宿主或传输失败会抛错,SDK 没有规定独立的取消状态。
async function openPermissionsAfterClick() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('openSetting')) return null;
return sdk.openSetting();
}combos.getCloudAbilitySession()
combos.getCloudAbilitySession(): Promise<ICombosHostCloudAbilitySession>
参数:无。超时:10 秒。在支持的宿主中,返回当前游玩的 { session, expiresAtMs }。调用本身不弹授权界面,也不保证能访问任意 AI 模型,需要处理登录、授权与能力可用性错误。
凭据只保存在内存,并仅用于该宿主所说明的 Cloud Ability 接入。不要放进日志、截图、URL、本地存储或源码。使用前检查过期时间,需要时重新获取,玩家或游玩实例变化时丢弃旧值。公开 API 没有 refreshToken、TTL 参数,也没有通用服务端鉴权保证。无效结果报 request_failed。
async function obtainCloudSession() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes('getCloudAbilitySession')) return null;
const value = await sdk.getCloudAbilitySession();
if (value.expiresAtMs <= Date.now()) throw new Error('Session already expired');
return value; // Keep in memory only; never log or persist this value.
}TikTok 客户端参考
目前真实 TikTok 接入还没有可用的开通路径。下面描述接口契约,不意味着新发布的游戏可以接收真实礼物。目前可以制作游戏、运行模拟器和发布到 Combos;真实接入需要等待平台提供开通流程。
客户端管理的是当前游戏的 TikTok 互动会话,不是主播整体直播状态。它负责传输、心跳、会话续期与重连;游戏负责支持的指令、效果执行、持久化去重和真实结果。礼物映射概念、发布步骤、准备材料与可运行项目见完整教程。
combos.getTTLiveClient()
combos.getTTLiveClient(): TTLiveClient
参数:无。返回:同步返回 TTLiveClient,取对象时不发起网络请求。同一 SDK 和游戏页面内重复调用得到同一实例,不要让多个组件各自建立竞争的连接控制器。
按下面示例检查能力列表中的 getTTLiveSession。拿到客户端对象不代表宿主支持、已登录、完成启动登记或已经连接。真实连接前先完成账号流程。平台密钥、CAS 凭据、launchData 和 WebSocket 地址均由内部处理,这里没有传入它们的参数。
async function getTikTokClient() {
const sdk = window.combos;
if (!sdk || typeof sdk.getTTLiveClient !== 'function') return null;
const { methods } = await sdk.init();
if (!methods.includes('getTTLiveSession')) return null;
return sdk.getTTLiveClient();
}client.connect(options)
client.connect(options: TTLiveConnectOptions): Promise<void>
参数:必填 options 对象,其中 onCommand 必须是返回 boolean 或 Promise<boolean> 的函数。公开签名没有房间 ID、主播 ID、token、重连配置或超时参数。
收到连接的 ready 帧后返回 Promise<void>。这不证明礼物效果已发生,也不保证持续在线,状态需要单独订阅。重连期间 Promise 可能一直等待,因此先提供停止入口,再等待连接结果。已处于连接意图中时再次调用,会共用等待中的连接或立即成功,不会替换原处理函数;更换处理函数前先断开。
缺少 onCommand 会以普通 Error 拒绝;就绪前主动断开或进入终止状态也会拒绝等待中的 Promise。临时网络或会话故障通常进入恢复过程,不会立即抛错。不同消息 ID 的异步处理函数可能并发执行,游戏应串行修改共享状态或使用事务。
interface TTLiveConnectOptions {
onCommand: (command: TTLiveCommand) => boolean | Promise<boolean>;
}
interface TTLiveCommand {
messageId: string;
instruction: string;
count: string;
timestamp: string;
}| 回调字段 | 类型与校验 | 游戏需要做什么 |
|---|---|---|
messageId | 非空 string,SDK 1.1.0 最多接受 256 个字符 | 不透明幂等键,执行结果与效果一起持久化 |
instruction | string | 匹配游戏声明的指令;SDK 不替你校验礼物目录 |
count | 十进制数字字符串,保留大整数精度 | 先验证业务数量范围再转换;不要直接 Number。仅 SDK 解析不会拒绝零或前导零 |
timestamp | string | 来源时间的字符串表示,公开类型未保证单位或格式;不能作为身份或严格顺序凭据 |
下面是指令示例,不是礼物注册 API。回调中没有观众 ID、昵称、礼物价格或真实礼物 ID。count 是映射后的指令数量,不一定等于礼物件数或金币价值。
{
"messageId": "example-command-001",
"instruction": "gift_flash",
"count": "3",
"timestamp": "1791800000"
}| 处理函数结果 | SDK 行为 |
|---|---|
true 或 Promise 成功为 true | 回传执行成功;必须等效果和回执提交后才能返回 |
false 或 Promise 成功为 false | 回传确定的拒绝或失败,例如未知指令且未施加效果 |
| 抛错、Promise 拒绝或非布尔结果 | 结果保持未知、不确认;SDK 重连,指令可能再次投递 |
SDK 的内存去重范围有限,主动断开或刷新页面会清空,不能提供持久的“恰好执行一次”保证。把 messageId、效果与结果原子保存,重复投递时返回保存的结果。效果可能部分生效时,不能直接返回 false。Gift Arena 示例提供了事务实现。
下面的辅助函数立即提供取消方法,并注册连接失败处理。传入真实的指令处理函数和不会抛错的界面回调,仍可等待 connected;保存返回的 stop,用于取消等待中的连接或结束已连接会话。
import type { TTLiveClient, TTLiveConnectOptions, TTLiveStatus } from './combos-host-sdk';
function attachTikTok(
client: TTLiveClient,
onCommand: TTLiveConnectOptions['onCommand'],
onStatus: (status: TTLiveStatus) => void,
onConnectionError: (error: unknown) => void,
) {
const unsubscribe = client.onStatusChange(onStatus);
const connected = client.connect({ onCommand });
void connected.catch(onConnectionError);
return {
connected,
stop() {
unsubscribe();
client.disconnect();
},
};
}client.getLiveStatus()
client.getLiveStatus(): Promise<TTLiveStatus>
参数:无。即时查询状态、向订阅者发布结果,并返回 TTLiveStatus;不会启动指令流。内部先取得宿主会话,宿主请求超时 10 秒,首次还可能需要能力查询;之后的状态 HTTP 请求最多等待 5 秒。
网络、HTTP、会话解析或无效状态回包会转成状态结果,通常为 unknown,不能据此认定已结束。宿主返回 tt_not_launched 时,会转成 ended 与 relaunch_game。查询到终止状态还会停止活动客户端。游玩期间优先订阅状态,不要频繁轮询本方法。
interface TTLiveStatus {
state: 'connecting' | 'connected' | 'recovering' | 'ended' | 'unknown';
reason: string;
action: 'none' | 'wait' | 'relaunch_game';
confirmedAtMs: number;
}| 字段或取值 | 含义与操作 |
|---|---|
state: connecting | 正在建立初始连接 |
state: connected | 当前游戏的互动会话已确认 |
state: recovering | SDK 正在恢复传输,等待其重试流程 |
state: unknown | 暂时无法确认,不代表主播下播 |
state: ended | 当前互动会话结束,查看 action |
reason | 诊断字符串,可能为空或新增取值,不是封闭枚举 |
action: none | 没有要求恢复操作 |
action: wait | 等待状态恢复,同时保留取消入口 |
action: relaunch_game | 提示主播从 LIVE Studio 重新打开当前游戏,不是重启直播 |
confirmedAtMs | 最近一次 TikTok 启动或心跳确认的 Unix 毫秒时间,0 表示未知,不是过期时间 |
已知原因包括 platform_unconfirmed、transport_unavailable、client_disconnected、tt_not_launched、session_required。根据 state 和 action 驱动恢复,不要假定原因列表完整,也不要把原始诊断值直接当作面向玩家的正式文案。
import type { TTLiveClient } from './combos-host-sdk';
async function checkTikTokStatus(client: TTLiveClient) {
const status = await client.getLiveStatus();
return status;
}{ "state": "unknown", "reason": "transport_unavailable", "action": "wait", "confirmedAtMs": 0 }client.onStatusChange(listener)
client.onStatusChange(listener: (status: TTLiveStatus) => void): () => void
参数:必填同步监听函数,接收 TTLiveStatus。返回:取消订阅函数。注册时会立即收到当前状态,之后在字段变化时通知;即使 state 不变,心跳确认时间更新也可能触发回调。
界面销毁时取消订阅。取消监听不会断开连接,断开连接也不会移除你的监听函数。监听函数不能抛错,首次立即调用时的异常可能向外传播。示例直接显示协议值用于调试,正式界面应提供本地化状态文案。
import type { TTLiveClient } from './combos-host-sdk';
function showTikTokStatus(client: TTLiveClient, output: HTMLElement) {
const unsubscribe = client.onStatusChange(status => {
output.textContent = `${status.state} · ${status.action}`;
});
return unsubscribe; // Call when the UI is removed.
}client.disconnect()
client.disconnect(): void
参数:无。返回:undefined(void)。停止定时器、待执行重试和连接,清空客户端内存中的执行与结果缓存,并拒绝仍在等待的连接 Promise。发布 unknown / client_disconnected / wait,confirmedAtMs 为 0。
这不是同步结束 TikTok 直播的 API,也不证明服务端已确认结束。它不删除游戏自行保存的回执,不能回滚已经执行中的处理函数。界面需单独取消订阅,防止迟到任务修改已退出的场景,并保留持久回执。之后可以用同一客户端重新连接;清理时重复断开是安全的。
import type { TTLiveClient } from './combos-host-sdk';
function stopTikTok(client: TTLiveClient, unsubscribe: () => void) {
unsubscribe();
client.disconnect();
}错误与恢复方式
宿主方法失败时拒绝 Promise,错误为带字符串 code 和 message 的 Error。按 code 分支,不要匹配自然语言消息。下面不是穷尽列表,宿主和后端错误码可能透传。TikTok 生命周期异常可能是没有 code 的普通 Error;getLiveStatus 则有意把多种失败转成状态值。
区分正常决定和故障:checkSession() === false、登录 cancelled、授权 DENIED、翻译 needed: false 都是正常返回。下面的辅助函数保留这种区别,不依赖特定错误类,也不会记录凭据。
function readErrorCode(error: unknown): string | null {
if (error && typeof error === 'object' && 'code' in error && typeof error.code === 'string') {
return error.code;
}
return null;
}
async function checkAccountSafely() {
const sdk = window.combos;
if (!sdk) return { kind: 'unavailable' as const };
try {
return { kind: 'success' as const, signedIn: await sdk.checkSession() };
} catch (error) {
return { kind: 'error' as const, code: readErrorCode(error) };
}
}| 错误码 | 含义 | 如何处理 |
|---|---|---|
unsupported | 宿主未声明该方法 | 隐藏或禁用可选功能,保留基础玩法 |
timeout | SDK 等待期限结束 | 结束加载状态,提供玩家主动重试;不能假定宿主操作已取消 |
transport_failed | 宿主请求发送失败 | 检查是否处于支持的播放器,保留降级界面 |
request_failed | 宿主失败或回包格式无效 | 捕获错误,核对失败动作,仅在安全时重试 |
disposed | 当前 SDK 页面或客户端已销毁 | 停止该页面的回调和任务,不循环重试 |
session_required | 账号会话不可用 | 提供登录,成功后重试原操作 |
model_not_supported | 宿主或后端拒绝该模型 | 使用相应 Cloud Ability 接入支持的模型 |
100250001 | 权限请求校验失败 | 检查支持的权限范围与宿主可信游戏上下文 |
100260001 / 100260002 | 会话创建或上下文无效,或会话无效 | 重新建立获准的游玩会话,不能自行构造身份和凭据 |
100260004 | 缺少 AI 模型授权 | 尊重授权决定,在支持时走宿主授权流程 |
100260005 | 游戏能力已关闭 | 由游戏所有者确认能力可用性,重复登录不会开通能力 |
这些数字码是已知宿主或后端错误,不意味着当前 Web 宿主开放 Cloud Ability。先检查具体方法的支持条件。未知错误码也要提供可恢复的提示,仅保留不含敏感信息的诊断。
TikTok 的 reason、action 是状态字段,不是宿主错误码。指令处理抛错不会自动发送失败 ACK,不能用 catch(() => false) 包住可能已经生效的操作。宿主请求超时也只是 SDK 不再等待,登录、授权、翻译没有公开的取消方法。避免自动重试造成重复弹窗或重复执行结果不明的操作。
生命周期与接入边界
- 当前页面读取一次能力;每次新的账号操作前即时检查登录态。
- 登录与权限请求绑定玩家操作,取消或拒绝后不自动重新弹出。
- 原文先显示,翻译作为可选增强;场景销毁后丢弃过期的异步界面结果。
- 由一个明确的模块管理当前页面的 TikTok 客户端:订阅状态、用持久化处理函数连接,并允许取消等待。
- 退出互动时取消订阅并断开;保留执行回执,账号或游玩结束时清理敏感会话。
window.combos 没有公开的全局 dispose()、账号变化事件、登录取消句柄或统一请求超时配置。不要通过内部类或未公开的宿主 HTTP 路径补这些能力。下载示例里的函数和存储数量上限是游戏设计,不是 SDK 新增接口。
版本、类型与完整示例
公开 TypeScript 声明 提供编辑器使用的权威类型形状。本文同时核对了 SDK 1.1.0 的运行时校验、超时、Web 宿主能力选择、翻译处理和 TikTok 生命周期。类型存在不等于宿主当前可用,后续 SDK 或宿主版本可能调整行为。
- 账号与多语言:按钮绑定、登录后继续操作、安全更新文字。
- 制作 TikTok 游戏:礼物声明、完整项目、本地验证、发布,以及未来接入和真实 LIVE 验收的准备。
- 下载 Gift Arena:包含事务式指令处理的完整源码。
文档示例会对照公开类型检查,但类型检查与本地模拟器不代表真实账号登录、Cloud Ability 授权或付费礼物已验收。这些流程需要在支持的宿主中,使用有资格的账号和已登记游戏另行验证。