Skip to content

SDK

This SDK provides secure bidirectional communication between the game and the native clients (iOS and Android), enabling third‑party developers to invoke native capabilities.

Exposed global API name: window.GameTokSDK

Capabilities:

ActionDescription
GET_PROFILEGet the current user profile
PURCHASEInitiate a purchase (e.g., in‑app purchase)
STORAGE_SETWrite to local key‑value storage (settings, progress, etc.)
STORAGE_GETRead from local key‑value storage (retrieve previously saved data)
ADD_SCOREReport a score (leaderboards, sharing, etc.)
GET_PERMISSION_MICRequest microphone permission (Android)
TOPUPTop up when in‑game currency is low; opens the client top‑up flow
ROUND_STARTRound start notification (call once per round start; tied to platform round/energy policies)
ROUND_ENDRound end notification (call when a round ends; round_id must match this round's ROUND_START)
onAudioSuspendListen for audio suspend event (triggered when the platform requires the game to mute)
offAudioSuspendRemove audio suspend event listener
onAudioResumeListen for audio resume event (triggered when the platform allows the game to restore sound)
offAudioResumeRemove audio resume event listener

Integration examples

The following shows how to include the SDK on a page and call each capability.

1.1 Including the script

Option 1: Load the bundle via <script>

html
<script src="https://play.letskix.com/res/game/sdk-js/GameTokSDK.js"></script>
<script>
  console.log('GameTokSDK version loaded:', !!window.GameTokSDK);
</script>

Local development (not embedded in the app, debugging in a browser): After loading the SDK, call GameTokSDK.enableMock(). Promise‑based APIs will use built‑in mock data; no native client is required. Do not call this in production or store submission builds, or users will see fake data.

html
<script src="https://play.letskix.com/res/game/sdk-js/GameTokSDK.js"></script>
<script>
  GameTokSDK.enableMock();
</script>

Device testing (WebView inside the app): When you need logs, after loading the SDK call GameTokSDK.enableDebug() (returns a Promise; loads vConsole on the page and logs native bridge traffic). Do not use together with enableMock.

html
<script src="https://play.letskix.com/res/game/sdk-js/GameTokSDK.js"></script>
<script>
  GameTokSDK.enableDebug();
</script>

1.2 Usage examples

All examples use then / catch with Promises. On success, a unified response object is returned; on failure, the Promise rejects.

1.2.1 Get profile

javascript
// Example call
GameTokSDK.getProfile()
  .then(({ action, error, data }) => {
    console.log('Profile loaded:', data);
  })
  .catch((e) => {
    console.error('Failed to get profile:', e);
  });

Sample response (JSON):

json
{
  "action": "GET_PROFILE",
  "error": false,
  "data": {
    "uid": 1234567,
    "avatar": "https://profile-file-pre.lobah.net/files/2024/11/15/3/fd1c01ac6640466f92a59c0aaa6b0112_lp_profile_img_frame_male_17.png",
    "userName": "Tim tim",
    "userCoins": 0,
    "level": 0,
    "gender": 0,
    "testAccount": true,
    "guest": true
  }
}

1.2.2 In‑app purchase (e.g., buy an item)

javascript
/**
 * In‑app purchase
 * @param productId Product ID; must be defined beforehand in the developer console (https://developer.lobah.net/)
 */
GameTokSDK.purchase({ productId: 'HAB.WATER.10.COINS' })
  .then(({ data }) => {
    // Success vs failure must be determined from the returned code here
    console.log('Purchase finished:', data);
  })
  .catch((e) => {
    console.error('Error:', e);
  });

Sample response (JSON):

json
{
  "action": "PURCHASE",
  "error": false,
  "data": {
    "purchaseResultCode": 0,
    "testAccount": false,
    "userBalance": 22514
  }
}

purchaseResultCode values:

  • 0: Purchase succeeded
  • 11: Invalid product_id
  • 12: Insufficient user coins
  • 13: Duplicate or invalid reference_id
  • 14: User is a guest; guests cannot purchase
  • 16: Invalid product_id
  • 20: Other error

1.2.3 Store key‑value

javascript
/**
 * Store a key‑value pair
 * @param key   Custom key
 * @param value Value; may be a string or an object
 */
GameTokSDK.storageSet({ key: 'settings', value: { theme: 'dark', volume: 0.8 } })
  .then(() => {
    console.log('Stored successfully');
  })
  .catch((e) => {
    console.error('Store failed:', e);
  });

Sample response (JSON):

json
{
  "action": "STORAGE_SET",
  "error": false,
  "data": null
}

1.2.4 Read key‑value

javascript
/**
 * Read a key‑value pair
 * @param key Predefined key to read
 */
GameTokSDK.storageGet({ key: 'settings' })
  .then((result) => {
    console.log('Read OK:', result.data.value); // object or string
  })
  .catch((e) => {
    console.error('Read failed:', e);
  });

Sample response (JSON):

json
{
  "action": "STORAGE_GET",
  "error": false,
  "data": {
    "value": {
        "theme": "dark",
        "volume": 0.8
    }
  }
}

1.2.5 Report score

javascript
/**
 * Depending on the game, you may report score, stage, or level.
 * For score: { score: 300, scoreType: 'score', remark: 'score' }
 * For level: { score: 1, scoreType: 'level', remark: 'level' }
 * @param score     Value to report; must be a positive integer
 * @param scoreType Category (business‑defined label for the uploaded data)
 * @param remark    Optional note (may match scoreType)
 */

GameTokSDK.addScore({ score: 10, scoreType: 'score', remark: 'score' })
  .then(() => {
    console.log('Score reported');
  })
  .catch((e) => {
    console.error('Report failed:', e);
  });

Sample response (JSON):

json
{
  "action": "ADD_SCORE",
  "error": false,
  "data": null
}

1.2.6 Microphone permission

javascript
/**
 * Request microphone permission (Android)
 * Use in‑game to prompt the user for mic access (e.g., voice features).
 * No return value; only triggers the native permission UI.
 */
GameTokSDK.getPermissionMic();

1.2.7 Top up (TOPUP)

Important: User cancel, payment failure, etc. still resolve via then. In then, check data.code for success. catch is only for SDK unavailability, timeouts, and similar errors.

javascript
/**
 * Top up
 * @param amount Amount (units as agreed with the client)
 */
GameTokSDK.topup({ amount: 100 })
  .then(({ action, error, data }) => {
    const code = data && data.code;
    if (code === 200) {
      console.log('Top‑up succeeded:', data);
    } else {
      console.warn('Top‑up incomplete or failed, code:', code, data);
    }
  })
  .catch((e) => {
    console.error('Top‑up request error (e.g., SDK unavailable):', e);
  });

Sample response (JSON, success):

json
{
  "action": "TOPUP",
  "error": false,
  "data": {
    "code": 200,
    "message": "ok"
  }
}

code values:
200 Success
401 Top-up failed (error)
402 Top-up failed (user cancelled)

1.2.8 Round start (ROUND_START)

Call once after a round actually starts. round_id is required (unique ID for this round, generated by the game). Optional timestamp (ms; defaults to now if omitted). No Promise return — fire‑and‑forget.

javascript
/**
 * Round start notification
 * @param round_id Unique ID for this round
 * @param timestamp Optional start time (ms)
 */
GameTokSDK.roundStart({
  round_id: 'round-' + Date.now(),
  timestamp: Date.now(),
});

If round_id is missing, the SDK logs a warning and does not send to native.

1.2.9 Round end (ROUND_END)

Call when the round ends. round_id must match this round's roundStart. Optional timestamp. No Promise return.

javascript
/**
 * Round end notification
 * @param round_id Same as this round's roundStart
 * @param timestamp Optional end time (ms)
 */
const roundId = 'round-' + Date.now();
GameTokSDK.roundStart({ round_id: roundId });
// ... round logic ...
GameTokSDK.roundEnd({ round_id: roundId, timestamp: Date.now() });

1.2.10 Audio event listeners (onAudioSuspend / offAudioSuspend / onAudioResume / offAudioResume)

When the platform requires the game to mute (e.g., the user enters a live room, a system call comes in, etc.), an audio suspend event is pushed to the game; when sound is allowed to resume, an audio resume event is pushed. The game should promptly mute/unmute all sound effects and background music upon receiving these events.

This is an event listener interface, not a Promise interface, and has no return value.

javascript
// Listen for audio suspend event
function handleAudioSuspend(payload) {
  console.log('Mute notification received:', payload);
  // Mute all sound effects and background music in the game
  myGame.muteAll();
}

GameTokSDK.onAudioSuspend(handleAudioSuspend);

// Listen for audio resume event
function handleAudioResume(payload) {
  console.log('Resume sound notification received:', payload);
  // Restore all sound effects and background music in the game
  myGame.unmuteAll();
}

GameTokSDK.onAudioResume(handleAudioResume);

Remove listeners:

javascript
// Remove audio suspend listener (pass the same function reference used when registering)
GameTokSDK.offAudioSuspend(handleAudioSuspend);

// Remove audio resume listener
GameTokSDK.offAudioResume(handleAudioResume);

options.sync parameter (state synchronization):

onAudioSuspend and onAudioResume support a second optional options parameter, where sync (default true) handles the case where the listener is registered after the event has already fired:

  • sync: true (default) — If audio is already in a suspended/resumed state when the listener is registered, the callback will be called once immediately in the next microtask, ensuring the game does not miss previous state changes.
  • sync: false — Only listens for subsequent new event pushes; no state sync on registration.
javascript
// Default sync: true — if audio is already suspended, callback fires immediately once
GameTokSDK.onAudioSuspend((payload) => {
  myGame.muteAll();
});

// Disable state sync, only listen for subsequent events
GameTokSDK.onAudioSuspend((payload) => {
  myGame.muteAll();
}, { sync: false });

Recommended usage: Register listeners as early as possible during game initialization and keep sync: true (default), so the game can correctly sync state even if the platform has already sent a mute instruction before registration.

Parameters and response shape

  • Typical call parameters (reference; see each API for exact fields):
    • getProfile: `` (usually no extra parameters)
    • purchase: { productId: string }
    • storageSet: { key: string, value: any }
    • storageGet: { key: string }
    • addScore: { score: number, scoreType: string }
    • getPermissionMic: `` (usually no extra parameters)
    • topup: { amount: number, ... } (other fields per client protocol)
    • roundStart / roundEnd: { round_id: string, timestamp?: number }
    • onAudioSuspend / onAudioResume: (handler: Function, options?: { sync?: boolean })
    • offAudioSuspend / offAudioResume: (handler: Function)
  • Successful responses share this shape:
typescript
{
  action: string;      // Action name for this call (e.g. 'GET_PROFILE')
  error: false;        // false on success (on failure the Promise rejects)
  data: any;           // Native payload; fields depend on the action
}
  • Failure behavior:
    • topup: Most business outcomes (success/failure/cancel) resolve in then via data.code; catch is for SDK errors and timeouts.
    • Other Promise interfaces: On failure the Promise rejects with an Error; handle in .catch (log, retry, or show UI).

Important notes

Do not overwrite or remove these globals, or the SDK will break:

  • window.GameTokSDK (main SDK entry)

Example (do not do this):

javascript
// Dangerous — breaks iOS / Android bridge
window.GameTokSDK = {};
window.GameTokSDK = null;
delete window.GameTokSDK;

Full example

javascript
// Profile
GameTokSDK.getProfile({})
        .then((resp) => {
          console.log('Profile:', resp.data);
        })
        .catch((e) => {
          console.error('Failed to get profile:', e);
        });

// Store
GameTokSDK.storageSet({ key: 'config', value: { lang: 'zh-CN' } })
        .then(() => {
          console.log('Stored successfully');
        })
        .catch((e) => {
          console.error('Store failed:', e);
        });

// Read
GameTokSDK.storageGet({ key: 'config' })
        .then((resp) => {
          console.log('Config:', resp.data.value);
        })
        .catch((e) => {
          console.error('Read failed:', e);
        });

// Purchase
GameTokSDK.purchase({ productId: 'HAB.WATER.10.COINS' })
        .then((resp) => {
          console.log('Purchase:', resp.data);
        })
        .catch((e) => {
          console.error('Purchase failed:', e);
        });

// Score
GameTokSDK.addScore({ score: 5, scoreType: 'score' })
        .then(() => {
          console.log('Score added');
        })
        .catch((e) => {
          console.error('Score report failed:', e);
        });

// Microphone (Android, no return value)
GameTokSDK.getPermissionMic();

// Top up: check data.code in then (200 = success)
GameTokSDK.topup({ amount: 100 })
        .then(({ data }) => {
          if (data && data.code === 200) {
            console.log('Top-up succeeded', data);
          } else {
            console.log('Top-up not successful', data);
          }
        })
        .catch((e) => console.error('Top-up error', e));

// Round notifications (same round_id)
const rid = 'r-' + Date.now();
GameTokSDK.roundStart({ round_id: rid });
GameTokSDK.roundEnd({ round_id: rid });

// Audio event listeners (register during game initialization)
GameTokSDK.onAudioSuspend((payload) => {
  console.log('Mute', payload);
  myGame.muteAll();
});

GameTokSDK.onAudioResume((payload) => {
  console.log('Resume sound', payload);
  myGame.unmuteAll();
});

Swipe & Play Endless Game Together