跳到主要内容

CustomCommand 接口

使用 CustomCommand 实现自定义 API 接口流程如下:

在宿主中注入 CustomCommand 监听​

方式一:针对特定命令设置监听器​

const gameHandle = /* RuntimeGameHandle instance */;

gameHandle.setCustomCommandListener('sampleLogin', (request, handle) => {
// Validate parameters
if (!request.username) {
handle.fail(20001, 'invalid username');
return;
}

if (!request.nonce) {
handle.fail(20001, 'invalid nonce');
return;
}

// Simulate async operation
setTimeout(() => {
handle.success({
username: request.username + '_login',
age: 18,
nonce: request.nonce
});
}, 100);
});

方式二:注册多个自定义命令​

const gameHandle = /* RuntimeGameHandle instance */;

class CustomCommandHandler {
constructor(gameHandle) {
this.gameHandle = gameHandle;
this.registerCommands();
}

registerCommands() {
// Register multiple commands
this.gameHandle.setCustomCommandListener('sampleLogin', (request, handle) => {
this.handleLogin(request, handle);
});

this.gameHandle.setCustomCommandListener('getUserInfo', (request, handle) => {
this.handleGetUserInfo(request, handle);
});
}

handleLogin(request, handle) {
// Validate parameters
if (!request.username) {
handle.fail(20001, 'invalid username');
return;
}

if (!request.nonce) {
handle.fail(20001, 'invalid nonce');
return;
}

// Perform login
performLogin(request.username, request.password)
.then(result => {
handle.success({
username: result.username + '_login',
age: 18,
nonce: request.nonce
});
})
.catch(error => {
handle.fail(20002, error.message);
});
}

handleGetUserInfo(request, handle) {
// Get user info
getUserInfo(request.userId)
.then(userInfo => {
handle.success(userInfo);
})
.catch(error => {
handle.fail(20003, error.message);
});
}
}

// Register handler
const handler = new CustomCommandHandler(gameHandle);

在 JavaScript 里实现 API 接口​

JavaScript 中可以访问 tj 和 cusObj 变量。tj 用于调用和添加 API,cusObj 用于存放内部使用的功能。

tj.customCommand​

通过 tj.customCommand 来调用对应的宿主方法。

tj.sampleLogin = function(obj) {
tj.customCommand('sampleLogin', obj);
};

obj 参数除了包含对应接口参数,还包含接口回调。回调参数定义如下:

参数名类型必填说明
successFunction是接口调用成功的回调函数
failFunction否接口调用失败的回调函数
completeFunction否接口调用结束的回调函数(调用成功、失败都会执行)

API 调用示例​

tj.sampleLogin({
username: 'test',
nonce: 123,
success: function(res) {
console.log(`sampleLogin: user=${res.username}, age=${res.age}, nonce=${res.nonce}`);
},
fail: function(res) {
console.error(`login fail: ${res.errorCode}, ${res.errorMsg}`);
},
complete: function() {
console.log('sampleLogin completed');
}
});

tj.customCommandSync​

通过 tj.customCommandSync 来实现对宿主接口的同步调用。

tj.sampleLoginSync = function(obj) {
return tj.customCommandSync('sampleLogin', obj);
};

同步调用示例

try {
const result = tj.sampleLoginSync({
username: 'test',
nonce: 123
});
console.log('Login result:', result);
} catch (error) {
console.error('Login failed:', error);
}

传入自定义初始化 JavaScript​

通过文件路径注入​

const { TJConstants } = require('webglhost-runtime-pc');
const path = require('path');

const options = {
[TJConstants.CUSTOM_SCRIPT_FILES]: [
path.join(__dirname, 'scripts', 'auth.js'),
path.join(__dirname, 'scripts', 'ad.js')
]
};

await gameHandle.setGameStartOptions(options);

auth.js 示例

// auth.js
tj.sampleLogin = function(obj) {
tj.customCommand('sampleLogin', obj);
};

tj.getUserInfo = function(obj) {
tj.customCommand('getUserInfo', obj);
};

ad.js 示例

// ad.js
tj.showAd = function(obj) {
tj.customCommand('showAd', obj);
};

tj.hideAd = function(obj) {
tj.customCommand('hideAd', obj);
};

通过字符串内容注入​

const { TJConstants } = require('webglhost-runtime-pc');

const options = {
[TJConstants.CUSTOM_SCRIPT_CONTENTS]: [
`
tj.sampleLogin = function(obj) {
tj.customCommand('sampleLogin', obj);
};
`,
`
tj.getUserInfo = function(obj) {
tj.customCommand('getUserInfo', obj);
};
`
]
};

await gameHandle.setGameStartOptions(options);

混合使用文件和字符串​

const { TJConstants } = require('webglhost-runtime-pc');
const path = require('path');

const options = {
// Load from files
[TJConstants.CUSTOM_SCRIPT_FILES]: [
path.join(__dirname, 'scripts', 'auth.js')
],

// Inject inline scripts
[TJConstants.CUSTOM_SCRIPT_CONTENTS]: [
`
tj.quickLogin = function(obj) {
tj.customCommand('sampleLogin', obj);
};
`
]
};

await gameHandle.setGameStartOptions(options);

运行中执行 JavaScript​

宿主运行中,可以调用 gameHandle.runCustomScript 来执行 JavaScript 代码。代码中可以访问 tj 和 cusObj 变量。

执行简单脚本​

const script = `
console.log('Running custom script');
return { success: true, timestamp: Date.now() };
`;

gameHandle.runCustomScript(script, (result, error) => {
if (error) {
console.error('Script execution error:', error);
return;
}

console.log('Script result:', result);
});

执行复杂对象返回​

const script = `
console.log('Getting user data');
return {
name: 'john',
age: 18,
isActive: true,
scores: [40.2, 50, 70.2],
profile: {
email: 'john@example.com',
level: 5
}
};
`;

gameHandle.runCustomScript(script, (result, error) => {
if (error) {
console.error('Error:', error);
return;
}

console.log('Name:', result.name);
console.log('Age:', result.age);
console.log('Active:', result.isActive);
console.log('Scores:', result.scores);
console.log('Email:', result.profile.email);
});

与游戏交互​

// Call game API from host
const script = `
// Call game's custom method
if (typeof window.gameAPI !== 'undefined') {
const playerInfo = window.gameAPI.getPlayerInfo();
return playerInfo;
}
return null;
`;

gameHandle.runCustomScript(script, (result, error) => {
if (error) {
console.error('Failed to get player info:', error);
return;
}

console.log('Player info:', result);
});

完整示例​

const { TJHostHandle, TJConstants } = require('webglhost-runtime-pc');
const path = require('path');

class CustomAPIManager {
constructor() {
this.gameHandle = null;
}

async initialize(hostHandle) {
// Create game handle
this.gameHandle = await hostHandle.createGameHandle();

// Setup custom command listeners
this.setupCustomCommands();

// Setup game start options with custom scripts
await this.setupGameOptions();
}

setupCustomCommands() {
// Register login command
this.gameHandle.setCustomCommandListener('login', (request, handle) => {
this.handleLogin(request, handle);
});

// Register getUserInfo command
this.gameHandle.setCustomCommandListener('getUserInfo', (request, handle) => {
this.handleGetUserInfo(request, handle);
});

// Register showAd command
this.gameHandle.setCustomCommandListener('showAd', (request, handle) => {
this.handleShowAd(request, handle);
});
}

async setupGameOptions() {
const options = {
[TJConstants.LAUNCH_KEY]: 'launch-key',
[TJConstants.USER_ID]: 'user-123',

// Load custom scripts from files
[TJConstants.CUSTOM_SCRIPT_FILES]: [
path.join(__dirname, 'custom-scripts', 'auth.js'),
path.join(__dirname, 'custom-scripts', 'ad.js')
],

// Inject inline custom scripts
[TJConstants.CUSTOM_SCRIPT_CONTENTS]: [
`
tj.quickLogin = function(obj) {
tj.customCommand('login', obj);
};
`
]
};

await this.gameHandle.setGameStartOptions(options);
}

handleLogin(request, handle) {
// Validate
if (!request.username || !request.password) {
handle.fail(20001, 'Missing credentials');
return;
}

// Perform login (async)
this.performLogin(request.username, request.password)
.then(result => {
handle.success({
userId: result.userId,
token: result.token,
username: result.username
});
})
.catch(error => {
handle.fail(20002, error.message);
});
}

handleGetUserInfo(request, handle) {
if (!request.userId) {
handle.fail(20003, 'Missing userId');
return;
}

// Get user info
this.getUserInfo(request.userId)
.then(userInfo => {
handle.success(userInfo);
})
.catch(error => {
handle.fail(20004, error.message);
});
}

handleShowAd(request, handle) {
// Show ad
console.log('Showing ad:', request.adId);
handle.success({ shown: true });
}

async performLogin(username, password) {
// Simulate async login
return new Promise((resolve) => {
setTimeout(() => {
resolve({
userId: '12345',
token: 'token-abc',
username: username
});
}, 100);
});
}

async getUserInfo(userId) {
// Simulate async getUserInfo
return new Promise((resolve) => {
setTimeout(() => {
resolve({
userId: userId,
name: 'John Doe',
level: 10,
score: 1000
});
}, 50);
});
}

// Execute custom script at runtime
executeScript(script) {
return new Promise((resolve, reject) => {
this.gameHandle.runCustomScript(script, (result, error) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
}

// Usage
async function main() {
// Initialize SDK
const hostHandle = await new Promise((resolve, reject) => {
TJHostHandle.initialize('sdk-key', 'sdk-secret', (handle, error) => {
if (error) reject(error);
else resolve(handle);
});
});

// Create and setup custom API manager
const apiManager = new CustomAPIManager();
await apiManager.initialize(hostHandle);

// Start game
await apiManager.gameHandle.start();
apiManager.gameHandle.play();

// Execute custom script later
const result = await apiManager.executeScript(`
return { message: 'Hello from runtime script' };
`);
console.log('Script result:', result);
}

main().catch(console.error);