账号与多语言
先阅读 SDK 可用性与错误处理。以下示例使用宿主注入的全局对象,游戏不需要索取账号凭据。
玩家主动操作后登录
在需要账号的操作之前调用 checkSession()。若返回 false,通过玩家主动操作触发 login(),登录界面由宿主管理。cancelled 是正常的用户选择;消息传输、弹窗或账号资料同步失败则会拒绝 Promise。
收到 success 后直接继续当前操作,不需要刷新、轮询或再次检查本次操作的登录状态。下一次独立操作再重新检查。请求进行中应禁用发起按钮。
<button id="player-button">Show player</button>
<output id="player-info" aria-live="polite"></output>async function readPlayerAfterClick() {
const sdk = window.combos;
if (!sdk) return null;
const { methods } = await sdk.init();
if (!methods.includes("getUserInfo")) return null;
if (!(await sdk.checkSession())) {
const result = await sdk.login();
if (result.status !== "success") return null;
}
return sdk.getUserInfo();
}
const button = document.querySelector<HTMLButtonElement>("#player-button");
const output = document.querySelector<HTMLOutputElement>("#player-info");
button?.addEventListener("click", async () => {
if (!output) return;
button.disabled = true;
try {
const player = await readPlayerAfterClick();
output.textContent = player
? player.nickName || "Player"
: "Player information is unavailable.";
} catch {
output.textContent = "Unable to read player information. Please try again.";
} finally {
button.disabled = false;
}
});示例按钮和提示是游戏内的演示文案,可按游戏语言调整。辅助函数在能力缺失或登录取消时返回 null,真正的失败交给点击处理函数捕获。
读取玩家信息
getUserInfo() 不接收参数,在登录状态检查通过或登录成功后调用。未登录时以 session_required 拒绝请求。
| 字段 | 含义 |
|---|---|
appId | 当前游戏的应用标识 |
openId | 玩家在该应用内的身份标识 |
nickName | 显示昵称,可能为空字符串 |
avatarUrl | 头像地址,可能为空字符串 |
locale | 玩家已保存的公开产品语言,如 en、zh-CN;未保存时为当前产品语言 |
为缺失的显示信息提供默认值。应用内身份应保留其应用范围,不要把这份展示数据当作自己的后端凭据或授权证明。结果不包含平台用户 ID、邮箱或云能力会话。
翻译已显示的游戏文案
先展示源文案,再请求翻译。sourceLocale 表示源文案的语言,不是你希望翻译到的目标语言;目标语言由宿主当前产品语言决定。sourceTexts 传入完整的源字符串或模板,翻译结果也以这些原文作为 key。
<button data-source-text="Play"></button>
<button data-source-text="Pause"></button>async function localizeLabels() {
const nodes = [...document.querySelectorAll<HTMLElement>("[data-source-text]")];
const sourceTexts = nodes.map(node => node.dataset.sourceText ?? "");
nodes.forEach((node, index) => { node.textContent = sourceTexts[index]; });
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) => {
const source = sourceTexts[index];
node.textContent = result.translations[source] || source;
});
} catch {
// Keep the source copy on screen.
}
}
void localizeLabels();结果为 { needed: false } 或 { needed: true, locale, translations }。无需翻译、缺少某个 key、宿主不支持或请求失败时都保留原文。SDK 收到无效结果也会退回 needed: false。以文本方式显示译文,不要作为原始 HTML 插入。动态数值应在稳定模板翻译完成后再填入;修改示例的英文源文案时,也要更新 sourceLocale。
可选云能力接口参考
当前 Web 宿主不声明以下四个方法。 只有 init().methods 明确包含对应方法时才能使用。这份接口契约不代表发布游戏后就自动获得 AI 能力。
type Authorization = {
decision: "AUTHORIZATION_DECISION_GRANTED" | "AUTHORIZATION_DECISION_DENIED";
decidedAtMs: number;
};
type AuthSetting = Partial<Record<"ai_model", Authorization>>;
type CloudAbilitySession = { session: string; expiresAtMs: number };| 方法 | 参数与结果 |
|---|---|
getSetting() | 无参数,返回 AuthSetting;缺少某项表示尚未询问过 |
authorize({ scope: "ai_model" }) | 宿主管理授权弹窗,返回 Authorization |
openSetting() | 无参数,打开宿主设置并返回 AuthSetting |
getCloudAbilitySession() | 无参数,返回短期 CloudAbilitySession |
AUTHORIZATION_DECISION_DENIED 是正常授权结果,不是传输失败。不要写入 UNSPECIFIED 零值。时间单位为毫秒,不要向这些方法传用户、设备或游戏 ID。返回的会话只保存在内存中,遵守 expiresAtMs,游玩结束即丢弃,不放进持久化存储、日志或 URL。