SDK
本 SDK 提供 游戏 与原生客户端(iOS、Android)之间的安全双向通信能力,帮助第三方开发者调用原生能力。
暴露的全局 API 名称:window.GameTokSDK
提供能力:
| 动作 | 说明 |
|---|---|
| GET_PROFILE | 获取当前用户资料 |
| GET_PROFILES | 批量获取用户资料(按 uid 数组) |
| STORAGE_SET | 写入本地键值存储(用于保存设置、进度等) |
| STORAGE_GET | 读取本地键值存储(获取先前保存的数据) |
| ADD_SCORE | 上报分数(用于排行榜/分享等) |
| GET_PERMISSION_MIC | 获取麦克风权限(安卓) |
| TOPUP | 充值,游戏中金币不足,可以调起客户端充值 |
| ROUND_START | 开局通知(每局开始时上报,与平台局次、能量等策略相关) |
| ROUND_END | 局末通知(每局结束时上报,round_id 须与本局 ROUND_START 一致) |
| SHOW_ENERGY_INSUFFICIENT_DIALOG | 体力(能量)不足,通知平台展示体力不足弹窗(fire-and-forget) |
| onAudioSuspend | 监听音频暂停事件(平台要求游戏静音时触发) |
| offAudioSuspend | 移除音频暂停事件监听 |
| onAudioResume | 监听音频恢复事件(平台允许游戏恢复声音时触发) |
| offAudioResume | 移除音频恢复事件监听 |
| onAutoStartGame | 监听客户端“开始游戏”指令(效果等同点击游戏内 start 按钮) |
| offAutoStartGame | 移除“开始游戏”指令监听 |
| onExitAndResetGame | 监听客户端“结束并重置游戏”指令(游戏结束并回到初始状态) |
| offExitAndResetGame | 移除“结束并重置游戏”指令监听 |
| REQUEST_EXIT | 游戏自带「返回首页」按钮被点击,通知平台回首页(fire-and-forget,平台随后下发 EXIT_AND_RESET_GAME) |
集成示例
以下示例展示如何在页面中引入 SDK 并调用各项能力。
1.1 引入代码
方式一:通过 <script> 直接引入打包产物
<script src="https://play.letskix.com/res/game/sdk-js/GameTokSDK.js"></script>
<script>
console.log('GameTokSDK version loaded:', !!window.GameTokSDK);
</script>本地开发(未嵌入 App、在浏览器里调试):在引入 SDK 后调用 **GameTokSDK.enableMock()** 即可,Promise 类接口会走内置模拟数据,无需原生客户端。正式发布或提审包中请勿调用,否则用户会看到虚假数据。
<script src="https://play.letskix.com/res/game/sdk-js/GameTokSDK.js"></script>
<script>
GameTokSDK.enableMock();
</script>真机测试(已嵌入 App 的 WebView):需要看日志时,在引入 SDK 后调用 **GameTokSDK.enableDebug()**(返回 Promise,会在页面加载 vConsole,并打印与原生通信相关日志)。不要与 enableMock 同时使用。
<script src="https://play.letskix.com/res/game/sdk-js/GameTokSDK.js"></script>
<script>
GameTokSDK.enableDebug();
</script>1.2 调用示例
以下示例统一采用 Promise 的 then/catch 调用方式。成功时返回统一响应对象,失败时通过 Promise.reject 抛出错误。
1.2.1 获取个人资料
// 调用示例
GameTokSDK.getProfile()
.then(({ action, error, data }) => {
console.log('获取个人资料成功:', data);
})
.catch((e) => {
console.error('获取个人资料失败:', e);
});返回示例(JSON):
{
"action": "GET_PROFILE",
"error": false,
"data": {
"uid": 1024780,
"avatar": "https://game-load-sa.lobah.net/avatar/1.jpg",
"userName": "Guest",
"userCoins": 0,
"level": 0,
"gameLevel": 0,
"rankImg": "",
"gender": 0,
"testAccount": false,
"guest": true
}
}字段说明(重点):
| 字段 | 类型 | 说明 |
|---|---|---|
| uid | number | 用户唯一 ID |
| avatar | string | 头像 URL |
| userName | string | 用户昵称 |
| userCoins | number | 用户当前金币余额 |
| level | number | 用户成长等级(账号体系) |
| gameLevel | number | 段位(基于游戏对战 / 排位);0 表示没有段位(如新人、未参与排位) |
| rankImg | string | 段位图片地址;无段位时为空字符串 |
| gender | number | 性别枚举:0 = 未知,1 = 男,2 = 女 |
| testAccount | boolean | 是否测试账号 / 平台审核账号 |
| guest | boolean | 是否游客(未登录正式账号) |
1.2.2 批量获取用户资料
适用于排行榜、好友列表、对局结算等需要一次性拉取 多名用户 基本信息的场景,避免对 getProfile 高频循环调用。
/**
* 批量获取用户资料
* @param uids 必填,待查询的 uid 数组(建议单次 1 ~ 50 个)
*/
GameTokSDK.getProfiles({ uids: [1234567, 1234568, 1234569] })
.then(({ action, error, data }) => {
console.log('批量获取成功:', data);
// data 就是 Profile 数组,可直接遍历或按 uid 自行映射
const map = new Map(data.map(p => [p.uid, p]));
console.log('1234567 ->', map.get(1234567));
})
.catch((e) => {
console.error('批量获取失败:', e);
});参数说明:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uids | number[] | 是 | 待查询的 uid 列表,长度建议 1 ~ 50。为空数组、非数组或包含非法元素(如 "abc"、null、负数、小数)时,SDK 直接 reject(SDKError),错误码 INVALID_PARAMS = 1003,不会 向原生发送 |
返回示例(JSON):
{
"action": "GET_PROFILES",
"error": false,
"data": [
{
"uid": 1024780,
"avatar": "https://game-load-sa.lobah.net/avatar/1.jpg",
"userName": "Guest",
"userCoins": 0,
"level": 0,
"gameLevel": 0,
"rankImg": "",
"gender": 0,
"testAccount": false,
"guest": true
},
{
"uid": 1024781,
"avatar": "https://game-load-sa.lobah.net/avatar/2.jpg",
"userName": "Alice",
"userCoins": 200,
"level": 3,
"gameLevel": 5,
"rankImg": "https://game-load-sa.lobah.net/rank/5.png",
"gender": 2,
"testAccount": false,
"guest": false
}
]
}1.2.3 存储键值
/**
* 存储键值
* @param key 需要存储的自定义键值
* @param value 需要存储的值 可以是字符串,也可以是对象
*/
GameTokSDK.storageSet({ key: 'settings', value: { theme: 'dark', volume: 0.8 } })
.then(() => {
console.log('存储成功');
})
.catch((e) => {
console.error('存储失败:', e);
});返回示例(JSON):
{
"action": "STORAGE_SET",
"error": false,
"data": null
}1.2.4 读取键值
/**
* 读取键值
* @param key 需要读取的定义好的键值
*/
GameTokSDK.storageGet({ key: 'settings' })
.then((result) => {
console.log('读取成功:', result.data.value); // 可能是对象或字符串
})
.catch((e) => {
console.error('读取失败:', e);
});返回示例(JSON):
{
"action": "STORAGE_GET",
"error": false,
"data": {
"value": {
"theme": "dark",
"volume": 0.8
}
}
}1.2.5 上报分数
/**
* 对于不同的游戏,可能需要上报的是分数,也可能是关卡、等级
* 如果是分数,就可以这样传{score:300,scoreType:'score',remark:'score'}
* 如果是等级,就可以传 {score:1,scoreType:'level',remark:'level'}
* @param score 需要上报的值 这个值需要为正整数
* @param scoreType 数据类别(由业务自定义,作为上传数据的说明)
* @param remark 自定义说明 (可以和scoreType一致)
*/
GameTokSDK.addScore({ score: 10, scoreType: 'score',remark:'score' })
.then(() => {
console.log('加分成功');
})
.catch((e) => {
console.error('加分失败:', e);
});返回示例(JSON):
{
"action": "ADD_SCORE",
"error": false,
"data": null
}1.2.6 获取麦克风权限
/**
* 获取麦克风权限(安卓)
* 用于在游戏中请求用户授予麦克风权限,以便使用语音相关功能。
* 无返回值,仅触发原生端弹出权限请求。
*/
GameTokSDK.getPermissionMic();1.2.7 充值(TOPUP)
重要: 用户取消支付、支付失败等结果 仍走 then,请在 then 里根据 **data.code** 判断是否成功。只有 SDK不可用、超时等异常才会进入 **catch**。
/**
* 充值
* @param amount 充值金额(具体单位与客户端约定一致)
*/
GameTokSDK.topup({ amount: 100 })
.then(({ action, error, data }) => {
const code = data && data.code;
if (code === 200) {
console.log('充值成功:', data);
} else {
console.warn('充值未完成或失败, code:', code, data);
}
})
.catch((e) => {
console.error('充值请求异常(如SDK不可用):', e);
});返回示例(JSON,成功):
{
"action": "TOPUP",
"error": false,
"data": {
"code": 200,
"message": "ok"
}
}
code 的值定义:
200 成功,
401 充值失败(充值异常)
402 充值失败(主动取消)1.2.8 开局通知(ROUND_START)
每局游戏 正式开始后 调用一次。round_id 可选,建议不传:缺省时 SDK 自动生成全局唯一的对局 ID(round_ 前缀)并在内部记住,roundEnd() 会自动带出同一个值。可选 timestamp(毫秒时间戳,不传则使用当前时间)。无 Promise 返回值,发后即忘。
// 推荐用法:什么都不传,round_id 由 SDK 生成并自动关联本局
GameTokSDK.roundStart();
// 兼容用法:自行传入 round_id(须保证每局全局唯一、绝不跨局复用,
// 切勿使用 1、2、3 这类会话内递增序号——刷新页面后会与历史局撞号)
GameTokSDK.roundStart({ round_id: 'round-' + crypto.randomUUID() });需要读取当前局 ID 时(如传给 showEnergyInsufficientDialog 归因):
const roundId = GameTokSDK.getCurrentRoundId(); // roundStart 后有值,roundEnd 后为 null上一局未
roundEnd又再次roundStart时,视为开新局,SDK 直接覆盖当前局 ID(旧局按未正常结束处理,平台侧有容错)。
1.2.9 局末通知(ROUND_END)
每局 结束后(输/赢/超时都算结束)调用。round_id 可选:缺省自动带出与本局 roundStart 相同的值;自行传入时须与开局一致。可选 timestamp。无 Promise 返回值。
// 推荐用法:与 roundStart() 配对,全程不管 round_id
GameTokSDK.roundStart();
// ... 本局逻辑 ...
GameTokSDK.roundEnd();
// 兼容用法:显式传入(须与本局 roundStart 的 round_id 相同)
GameTokSDK.roundEnd({ round_id: myRoundId, timestamp: Date.now() });若当前没有进行中的对局(从未 roundStart、或已经 roundEnd 过)且未显式传 round_id,SDK 会在控制台告警且 不会 向原生发送。
1.2.10 体力不足弹窗(SHOW_ENERGY_INSUFFICIENT_DIALOG)
游戏通过 getEnergy() / onEnergyUpdate()(见 1.2.11)获知体力不足(如 balance < cost_per_round,无法开新局)时,调用此接口请求平台在游戏容器层展示体力不足弹窗(内含签到领体力、去获取体力等引导)。游戏侧不判断体力规则、不处理弹窗 UI,只负责触发。无 Promise 返回值,发后即忘。
注意:平台自身也会在开局扣费、局末检测等时机主动弹这个弹窗,游戏侧调用是补充触发(典型场景:玩家点「开始」按钮但游戏已知体力不够时,主动请求弹窗而不是静默无响应)。
/**
* 体力不足弹窗
* @param scene 可选,触发场景(业务自定义,如 round_start、continue)
* @param round_id 可选,关联的对局 ID,便于平台归因(可用 getCurrentRoundId() 取)
*/
GameTokSDK.showEnergyInsufficientDialog({
scene: 'round_start',
round_id: GameTokSDK.getCurrentRoundId() || undefined,
});
// 也可不传参数
GameTokSDK.showEnergyInsufficientDialog();KC League 流程:开局前由游戏服务端向平台服务端
entry-check校验,返回canStart: false时同样调用本接口,并把校验返回的字段原样附上(fire-and-forget 通道透传任意 JSON 字段,无需 SDK 改版)。调用后游戏停在封面、START 按钮恢复可点;玩家充值/签到后若平台希望直接开局,会下发AUTO_START_GAME,游戏无需自行重试。javascriptGameTokSDK.showEnergyInsufficientDialog({ scene: 'kc_entry_check', energyBalance: 0, // entry-check 返回的余额,原样带上 blockReason: 'NO_ENERGY' // entry-check 返回的枚举,原样带上 });
发送示例(JSON):
{
"action": "SHOW_ENERGY_INSUFFICIENT_DIALOG",
"data": {
"scene": "round_start",
"round_id": "round-1732000000-abc123"
}
}1.2.11 体力查询与推送(getEnergy / onEnergyUpdate)
体力(能量)的扣除、弹窗、充值全部由平台完成,游戏只需要两件事:展示体力 HUD、体力不足时把「开始」按钮置灰。数据来源两条:
getEnergy()(请求-应答):初始化时主动查一次;onEnergyUpdate(handler)(平台推送):每次体力变化(开局扣费、签到、充值、局末检测等)后平台推最新值,游戏据此刷新 HUD。
两者返回/推送同一数据结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| balance | number | null | 体力余额;体力功能未启用时为 null,游戏应隐藏体力 UI、按不限体力运行 |
| charge_enabled | boolean | 该游戏是否开启每局扣除 |
| cost_per_round | number | 每局消耗体力数 |
| reason | string | 变化原因(仅推送带):initial / round_charge / round_end_check / checkin / recharge_check |
| seq | number | 单调递增序号,消费方须按 seq 丢弃乱序旧值(推送不保证按序到达) |
// 初始化:查一次 + 注册推送
const { data } = await GameTokSDK.getEnergy();
if (data.balance === null) {
hideEnergyHud(); // 体力功能未启用,降级为不限体力
} else {
renderEnergyHud(data.balance, data.cost_per_round);
}
let lastSeq = -Infinity;
GameTokSDK.onEnergyUpdate((payload) => {
if (payload.seq <= lastSeq) return; // 丢弃乱序旧值
lastSeq = payload.seq;
renderEnergyHud(payload.balance, payload.cost_per_round);
setStartButtonEnabled(payload.balance === null || payload.balance >= payload.cost_per_round);
});最后值同步补偿:与音频事件相同,onEnergyUpdate 的 options.sync 默认 true——注册时若 SDK 已缓存过体力值(来自更早的推送或 getEnergy() 应答),会异步补发一次,晚注册也不会错过当前状态;传 { sync: false } 关闭。另提供 offEnergyUpdate / onceEnergyUpdate(签名同音频事件),以及只读缓存:
const { last, seq } = GameTokSDK.getEnergyState(); // last 为最新体力数据(按 seq 单调),无数据时为 null本地调试(Mock):enableMock() 后 getEnergy() 返回内置模拟值 { balance: 100, charge_enabled: true, cost_per_round: 8 },可用自定义 handler 覆盖:
GameTokSDK.enableMock({ GET_ENERGY: () => ({ balance: 3, charge_enabled: true, cost_per_round: 8, seq: Date.now() }) });ENERGY_UPDATE 推送来自宿主,Mock 模式没有;调试时可在控制台手动派发:
window.dispatchEvent(new MessageEvent('message', { data: JSON.stringify({
action: 'ENERGY_UPDATE',
data: { balance: 0, charge_enabled: true, cost_per_round: 8, reason: 'round_charge', seq: Date.now() }
})}));1.2.12 音频事件监听(onAudioSuspend / offAudioSuspend / onAudioResume / offAudioResume)
当平台需要游戏静音(如用户进入直播间、系统来电等场景),会向游戏推送音频暂停事件;当允许恢复声音时,会推送音频恢复事件。游戏应在收到事件后及时暂停/恢复所有音效和背景音乐。
这是事件监听接口,不是 Promise 接口,无返回值。
// 监听音频暂停事件
function handleAudioSuspend(payload) {
console.log('收到静音通知:', payload);
// 暂停游戏中所有音效、背景音乐
myGame.muteAll();
}
GameTokSDK.onAudioSuspend(handleAudioSuspend);
// 监听音频恢复事件
function handleAudioResume(payload) {
console.log('收到恢复声音通知:', payload);
// 恢复游戏中所有音效、背景音乐
myGame.unmuteAll();
}
GameTokSDK.onAudioResume(handleAudioResume);移除监听:
// 移除音频暂停监听(传入注册时的同一函数引用)
GameTokSDK.offAudioSuspend(handleAudioSuspend);
// 移除音频恢复监听
GameTokSDK.offAudioResume(handleAudioResume);**options.sync 参数(状态同步):**
onAudioSuspend 和 onAudioResume 支持第二个可选参数 options,其中 sync(默认 true)用于处理"注册时机晚于事件触发"的场景:
sync: true(默认)—— 若注册监听时音频已经处于暂停/恢复状态,回调会在下一个微任务中被立即同步调用一次,确保游戏不会错过之前的状态变化。sync: false—— 只监听后续新的事件推送,不做注册时的状态同步。
// 默认 sync: true,若此时音频已被暂停,回调会立即触发一次
GameTokSDK.onAudioSuspend((payload) => {
myGame.muteAll();
});
// 关闭状态同步,仅监听后续事件
GameTokSDK.onAudioSuspend((payload) => {
myGame.muteAll();
}, { sync: false });推荐用法: 在游戏初始化阶段尽早注册监听,并保持 sync: true(默认),这样即使注册时平台已经发送过静音指令,游戏也能正确同步状态。
1.2.13 游戏控制事件监听(onAutoStartGame / offAutoStartGame / onExitAndResetGame / offExitAndResetGame)
客户端/壳子可向游戏推送两类控制指令(客户端 => H5):
- AUTO_START_GAME:通知游戏自动开始,效果等同于点击游戏里的 start 按钮。触发场景有两个:①玩家在平台排行榜弹层点"再玩一次"、平台核过体力后发出;②进场自动开局——玩家从小程序海报页点"立即开始"进入时,平台在游戏就绪后直接发出,可能在游戏刚加载完成、玩家没有任何游戏内操作时到达。
- EXIT_AND_RESET_GAME:客户端通知游戏结束,并回到初始状态(立即终止本局、清理倒计时/动画,回到初始或待开始画面)。
⚠️ 接入体力/排行榜链路的游戏必须实现这两个监听:平台的体力竞态兜底(开局后才发现体力不足)依赖
EXIT_AND_RESET_GAME收回对局,签到/充值后的续玩与进场自动开局依赖AUTO_START_GAME开局;未实现会导致体力不足时游戏无法被平台拦截。
这是事件监听接口,不是 Promise 接口,无返回值。 AUTO_START_GAME 支持迟注册一次性补发:指令到达时若尚无监听(如进场自动开局早于游戏初始化完成),SDK 会暂存最近一条,待首个 onAutoStartGame 注册时异步补发一次并清除——因此正常在初始化阶段注册监听即可,不会错过进场指令。EXIT_AND_RESET_GAME 为纯瞬时指令、无补偿(它只在局中发出,游戏必然已完成初始化),请在游戏初始化阶段尽早注册监听。
// 监听“开始游戏”指令
function handleAutoStart(payload) {
console.log('收到开始游戏指令:', payload);
myGame.start(); // 等同点击游戏内 start 按钮
}
GameTokSDK.onAutoStartGame(handleAutoStart);
// 监听“结束并重置游戏”指令
function handleExitReset(payload) {
console.log('收到结束并重置指令:', payload);
myGame.exitAndReset(); // 结束当前局并回到初始状态
}
GameTokSDK.onExitAndResetGame(handleExitReset);移除监听:
// 传入注册时的同一函数引用
GameTokSDK.offAutoStartGame(handleAutoStart);
GameTokSDK.offExitAndResetGame(handleExitReset);仅监听一次:
GameTokSDK.onceAutoStartGame((payload) => {
myGame.start();
});
GameTokSDK.onceExitAndResetGame((payload) => {
myGame.exitAndReset();
});客户端推送的消息格式:
{ "action": "AUTO_START_GAME" }{ "action": "EXIT_AND_RESET_GAME" }1.2.14 游戏自带返回按钮(requestExit / REQUEST_EXIT)
若游戏界面自带「返回首页 / 退出」按钮,玩家点击时调用 requestExit() 通知平台「我要回首页」。平台收到后会下发 EXIT_AND_RESET_GAME,游戏在既有的 onExitAndResetGame 监听里收尾(终止本局、清理动画、回到待开始画面)即可——requestExit() 本身不改变任何对局状态,也不会清空当前 round_id。
这是 fire-and-forget 接口:无 Promise、无返回值、不做去重(重复点击由平台侧去重)。参数全部可省,仅供排障关联:
/**
* 玩家点击游戏内「返回首页」按钮
* @param reason 可选,触发原因,缺省 'player_button'
* @param state 可选,点击时游戏所处状态(如 'IDLE' / 'PLAY' / 'RESULT'),仅供排障
* @param timestamp 可选,毫秒时间戳,不传则使用当前时间
*/
GameTokSDK.requestExit();
// 带排障信息
GameTokSDK.requestExit({ reason: 'player_button', state: 'PLAY' });
// 真正的收尾仍在这里完成(接入前须已注册,见 1.2.13)
GameTokSDK.onExitAndResetGame(() => myGame.exitAndReset());若当前有进行中的对局(
roundStart之后、roundEnd之前),SDK 会自动把round_id一并带出,便于平台关联本局;无需手动传入。
发送示例(JSON):
{
"action": "REQUEST_EXIT",
"data": {
"reason": "player_button",
"state": "PLAY",
"round_id": "round_xxx",
"timestamp": 1717000000000
}
}字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| reason | string | 触发原因,缺省 player_button |
| state | string | 可选,点击时的游戏状态,仅供排障 |
| round_id | string | 可选,局中点击时由 SDK 自动带出 |
| timestamp | number | 毫秒时间戳,缺省为当前时间 |
⚠️ 不要在
requestExit()之后自行 reset 游戏——统一等EXIT_AND_RESET_GAME到达再收尾,避免平台侧弹窗/结算与游戏画面不同步。
参数与返回结构
- 通用调用参数示例(参考,具体参数以各能力为准):
- getProfile:``(通常无需额外参数)
- getProfiles:
{ uids: number[] }(必填,非空数组;返回Profile[],结构等同getProfile.data的数组形式) - storageSet:
{ key: string, value: any } - storageGet:
{ key: string } - addScore:
{ score: number, scoreType: string } - getPermissionMic:``(通常无需额外参数)
- topup:
{ amount: number, ... }(其它字段以客户端协议为准) - roundStart / roundEnd:
{ round_id: string, timestamp?: number } - showEnergyInsufficientDialog:
{ scene?: string, round_id?: string }(可选;fire-and-forget,无返回值) - onAudioSuspend / onAudioResume:
(handler: Function, options?: { sync?: boolean }) - offAudioSuspend / offAudioResume:
(handler: Function) - onAutoStartGame / onExitAndResetGame:
(handler: Function) - offAutoStartGame / offExitAndResetGame:
(handler: Function) - requestExit:
{ reason?: string, state?: string, timestamp?: number }(全部可选;fire-and-forget,无返回值;局中自动带出round_id)
- 成功返回统一结构:
{
action: string; // 本次调用的动作名(如 'GET_PROFILE')
error: false; // 成功时为 false(失败时 promise 会直接 reject)
data: any; // 原生回包内容,字段由具体动作定义
}- 失败行为:
**topup:** 业务成功/失败/取消等 多数在then中 通过**data.code** 区分;catch多为SDK异常、超时等。- 其它 Promise 接口: 失败时 Promise 将直接 reject 一个
Error对象;建议在.catch中记录错误并进行重试或提示。
重要说明
为确保 SDK 正常工作,请勿覆盖或删除以下关键全局对象:
window.GameTokSDK(SDK 主接口)
示例(错误用法,请勿复制):
// 危险!将导致 iOS 或 Android 通信失效
window.GameTokSDK = {};
window.GameTokSDK = null;
delete window.GameTokSDK;完整示例
// 获取用户资料
GameTokSDK.getProfile({})
.then((resp) => {
console.log('Profile:', resp.data);
})
.catch((e) => {
console.error('获取个人资料失败:', e);
});
// 批量获取用户资料(用于排行榜、好友列表等场景)
GameTokSDK.getProfiles({ uids: [10001, 10002, 10003] })
.then(({ data }) => {
const map = new Map(data.map(p => [p.uid, p]));
console.log('10001 profile:', map.get(10001));
})
.catch((e) => {
console.error('批量获取失败:', e);
});
// 存储数据
GameTokSDK.storageSet({ key: 'config', value: { lang: 'zh-CN' } })
.then(() => {
console.log('存储成功');
})
.catch((e) => {
console.error('存储失败:', e);
});
// 读取数据
GameTokSDK.storageGet({ key: 'config' })
.then((resp) => {
console.log('Config:', resp.data.value);
})
.catch((e) => {
console.error('读取失败:', e);
});
// 加分示例
GameTokSDK.addScore({ score: 5, scoreType: 'score' })
.then(() => {
console.log('Score added');
})
.catch((e) => {
console.error('加分失败:', e);
});
// 获取麦克风权限(安卓,无返回值)
GameTokSDK.getPermissionMic();
// 充值:在 then 里用 data.code 判断(如 200 表示成功)
GameTokSDK.topup({ amount: 100 })
.then(({ data }) => {
if (data && data.code === 200) {
console.log('充值成功', data);
} else {
console.log('充值未成功', data);
}
})
.catch((e) => console.error('充值异常', e));
// 局次通知(round_id 前后一致)
const rid = 'r-' + Date.now();
GameTokSDK.roundStart({ round_id: rid });
GameTokSDK.roundEnd({ round_id: rid });
// 音频事件监听(在游戏初始化阶段注册)
GameTokSDK.onAudioSuspend((payload) => {
console.log('静音', payload);
myGame.muteAll();
});
GameTokSDK.onAudioResume((payload) => {
console.log('恢复声音', payload);
myGame.unmuteAll();
});
// 游戏自带「返回首页」按钮:只通知平台,收尾等 EXIT_AND_RESET_GAME
document.getElementById('btn-home').onclick = () => GameTokSDK.requestExit({ state: 'PLAY' });