跳到主要内容

IAppletManagerV3 接口

1. 概述​

IAppletManagerV3 接口用于管理小游戏,提供启动、关闭游戏以及处理游戏事件和 JsApi 调用的功能。

2. 接口定义​

interface IAppletManagerV3 : public WIUnknown {
// Launch applet
virtual void LaunchApplet(
const char* app_id,
const char* launch_config_pb,
size_t launch_config_pb_length,
LaunchCallback callback
) = 0;

// Close applet
virtual void CloseApplet(const char* app_id) = 0;

// Set JsApi handler
virtual void SetJsApiHandler(JsApiHandler jsapi_handler) = 0;

// Set applet event handler
virtual void SetAppletEventHandler(EventHandler event_handler) = 0;

// Send JsApi or event response
virtual void SendJsApiOrEventResponse(
int task_id,
const char* data,
size_t data_size
) = 0;

// Call applet command
virtual void CallAppletCommand(
const char* command_name,
int32_t task_id,
const char* app_id,
const char* data,
size_t data_size
) = 0;
};

3. 回调函数类型​

3.1 LaunchCallback​

游戏启动完成时的回调函数。

typedef void (*LaunchCallback)(
const char* app_id,
int result_code,
const char* error_desc
);

参数说明

  • app_id (const char*): 游戏 ID
  • result_code (int): 结果码
    • 0 (WMPF_ERRCODE_SUCCESS): 启动成功
    • 非 0: 启动失败
  • error_desc (const char*): 错误描述(成功时为空)

3.2 JsApiHandler​

处理游戏发起的 JsApi 调用。

typedef bool (*JsApiHandler)(
const char* app_id,
const char* api_name,
const char* data,
size_t data_size,
int task_id
);

参数说明

  • app_id (const char*): 游戏 ID
  • api_name (const char*): API 名称
  • data (const char*): API 请求数据(JSON 格式)
  • data_size (size_t): 数据大小
  • task_id (int): 任务 ID,用于响应

返回值

  • true: 处理成功
  • false: 处理失败

3.3 EventHandler​

处理游戏发出的事件。

typedef bool (*EventHandler)(
const char* event_name,
const char* data,
size_t data_size,
int task_id
);

参数说明

  • event_name (const char*): 事件名称
  • data (const char*): 事件数据(JSON 格式)
  • data_size (size_t): 数据大小
  • task_id (int): 任务 ID,用于响应

返回值

  • true: 处理成功
  • false: 处理失败

4. 方法详解​

4.1 LaunchApplet​

启动一个游戏实例。

函数签名

void LaunchApplet(
const char* app_id,
const char* launch_config_pb,
size_t launch_config_pb_length,
LaunchCallback callback
);

参数说明

  • app_id (const char*): 游戏 ID(Applet ID),来源于游戏列表 API 返回的 id 字段
  • launch_config_pb (const char*): 启动配置 JSON 字符串
  • launch_config_pb_length (size_t): 配置字符串长度
  • callback (LaunchCallback): 启动完成回调函数

关键 ID 说明

ID 类型说明来源使用位置
app_id (Game ID)游戏的唯一标识符游戏列表 API 返回的 id 字段LaunchApplet 和 CloseApplet 的第一个参数
launchKey游戏启动会话 Key游戏列表 API 返回的 launchKey 字段launch_config_pb JSON 中的 launchKey 字段

启动配置 JSON 格式

{
"launchKey": "https://minihost.tuanjie.cn/api/game/start_session?gameId=xxx",
"accessToken": "your-access-token",
"userId": "user-id",
"debug": true,
"mute": false,
"transparent": false
}
字段类型必填说明
launchKeyString是游戏启动 URL,来源于游戏列表 API 返回的 launchKey 字段
accessTokenString是用户访问令牌,用于身份验证
userIdString是用户 ID
debugBoolean否是否开启调试模式
muteBoolean否是否静音
transparentBoolean否窗口是否透明

获取 app_id 和 launchKey 的流程

  1. 调用游戏列表 API 获取可用游戏列表
  2. 从返回的 JSON 数组中选择要启动的游戏
  3. 使用该游戏的 id 字段作为 LaunchApplet 的 app_id 参数
  4. 使用该游戏的 launchKey 字段作为 launch_config_pb 中的 launchKey 值

游戏列表 API 返回示例:

[
{
"id": "691acb162dcfadc65a0fdb77", // 用作 app_id 参数
"appId": "691ac9ef2dcfadc65a0fb4a6", // Host App ID
"name": "示例游戏",
"launchKey": "691acb162dcfadc65a0fdb77", // 用作 launchConfig.launchKey
"gameType": "webgl"
}
]

代码示例

#include "IAppletManagerV3.h"
#include <iostream>

// Launch callback
void OnLaunchComplete(const char* app_id, int result_code, const char* error_desc) {
if (result_code == WMPF_ERRCODE_SUCCESS) {
std::cout << "Game launched successfully: " << app_id << std::endl;
} else {
std::cerr << "Game launch failed: " << error_desc << std::endl;
}
}

// Get IAppletManagerV3 from IBrowsingService
IAppletManagerV3* appletMgr = nullptr;
service->QueryInterface("IAppletManagerV3", (void**)&appletMgr);

// Game ID and Launch Key - 这些值来源于游戏列表 API
// appId: 游戏列表 API 返回的 "id" 字段
// launchKey: 游戏列表 API 返回的 "launchKey" 字段
const char* appId = "691acb162dcfadc65a0fdb77"; // 从游戏列表 API 获取
const char* launchKey = "691acb162dcfadc65a0fdb77"; // 从游戏列表 API 获取

// Build launch config
char launchConfig[2048];
snprintf(launchConfig, sizeof(launchConfig), R"({
"launchKey": "%s",
"accessToken": "your-access-token",
"userId": "developer",
"debug": true,
"mute": false,
"transparent": false
})", launchKey);

// Launch applet
// 第一个参数 appId 来源于游戏列表 API 返回的 "id" 字段
appletMgr->LaunchApplet(
appId,
launchConfig,
strlen(launchConfig),
OnLaunchComplete
);

std::cout << "Launch request sent, waiting for callback..." << std::endl;

4.2 CloseApplet​

关闭正在运行的游戏实例。

函数签名

void CloseApplet(const char* app_id);

参数说明

  • app_id (const char*): 要关闭的游戏 ID,必须与 LaunchApplet 时使用的 app_id 相同(来源于游戏列表 API 返回的 id 字段)

代码示例

// Close the game - 使用与 LaunchApplet 相同的 app_id
// app_id 来源于游戏列表 API 返回的 "id" 字段
appletMgr->CloseApplet("691acb162dcfadc65a0fdb77");
std::cout << "Game closed" << std::endl;

4.3 SetJsApiHandler​

设置 JsApi 调用处理器。游戏中的 JsApi 调用会通过此处理器回调到宿主应用。

函数签名

void SetJsApiHandler(JsApiHandler jsapi_handler);

参数说明

  • jsapi_handler (JsApiHandler): JsApi 处理函数指针

代码示例

// JsApi handler implementation
bool OnJsApiCall(
const char* app_id,
const char* api_name,
const char* data,
size_t data_size,
int task_id
) {
std::cout << "[JsApi] " << api_name << " from " << app_id << std::endl;
std::cout << "[JsApi] Data: " << std::string(data, data_size) << std::endl;
std::cout << "[JsApi] Task ID: " << task_id << std::endl;

// Process the API call
// ...

// Send response back
const char* response = R"({"code": 0, "message": "success"})";
appletMgr->SendJsApiOrEventResponse(task_id, response, strlen(response));

return true;
}

// Set the handler
appletMgr->SetJsApiHandler(OnJsApiCall);
std::cout << "JsApi handler registered" << std::endl;

4.4 SetAppletEventHandler​

设置游戏事件处理器。游戏发出的事件会通过此处理器回调到宿主应用。

函数签名

void SetAppletEventHandler(EventHandler event_handler);

参数说明

  • event_handler (EventHandler): 事件处理函数指针

代码示例

// Event handler implementation
bool OnGameEvent(
const char* event_name,
const char* data,
size_t data_size,
int task_id
) {
std::cout << "[Event] " << event_name << std::endl;
std::cout << "[Event] Data: " << std::string(data, data_size) << std::endl;

// Handle specific events
if (strcmp(event_name, "game_exited") == 0) {
std::cout << "Game exited" << std::endl;
// Handle game exit (cleanup, etc.)
}

return true;
}

// Set the handler
appletMgr->SetAppletEventHandler(OnGameEvent);
std::cout << "Event handler registered" << std::endl;

4.5 SendJsApiOrEventResponse​

发送对 JsApi 或事件的响应。

函数签名

void SendJsApiOrEventResponse(
int task_id,
const char* data,
size_t data_size
);

参数说明

  • task_id (int): 任务 ID(从 JsApiHandler 或 EventHandler 接收)
  • data (const char*): 响应数据(JSON 格式)
  • data_size (size_t): 数据大小

代码示例

// In JsApi handler
bool OnJsApiCall(
const char* app_id,
const char* api_name,
const char* data,
size_t data_size,
int task_id
) {
// Process API call
// ...

// Build response
const char* response = R"({
"code": 0,
"message": "success",
"data": {
"result": "operation completed"
}
})";

// Send response
appletMgr->SendJsApiOrEventResponse(task_id, response, strlen(response));

return true;
}

4.6 CallAppletCommand​

调用游戏命令(用于扩展功能)。

函数签名

void CallAppletCommand(
const char* command_name,
int32_t task_id,
const char* app_id,
const char* data,
size_t data_size
);

参数说明

  • command_name (const char*): 命令名称
  • task_id (int32_t): 任务 ID
  • app_id (const char*): 游戏 ID
  • data (const char*): 命令数据(JSON 格式)
  • data_size (size_t): 数据大小

支持的命令

命令名称说明数据格式
runCustomScript在游戏中注入并执行 JavaScript 代码{"script": "JS代码"}

代码示例 - 注入 JavaScript

使用 runCustomScript 命令可以在游戏运行时注入自定义 JavaScript 代码:

// Build JavaScript code to inject
std::string jsCode = R"(
(function() {
console.log('Custom script injected!');
// Your custom logic here
return true;
})()
)";

// Escape the script for JSON
std::string escapedScript = EscapeForJson(jsCode);

// Build command data
std::ostringstream oss;
oss << R"({"script":")" << escapedScript << R"("})";
std::string scriptData = oss.str();

// Inject script into the game
appletMgr->CallAppletCommand(
"runCustomScript",
task_id,
app_id,
scriptData.c_str(),
scriptData.length()
);
使用场景

runCustomScript 常用于:

  • 动态注入 UI 元素(如广告展示)
  • 调用游戏内部 API
  • 调试和测试

代码示例 - 通用命令

const char* commandData = R"({"param": "value"})";
appletMgr->CallAppletCommand(
"customCommand",
12345,
"684aa7ed8efdfe29f316a960",
commandData,
strlen(commandData)
);

5. 完整使用示例​

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include "IBrowsingService.h"
#include "IAppletManagerV3.h"
#include "ICoreServiceHandler.h"

// Global state
std::atomic<bool> g_launchCompleted{false};
std::atomic<bool> g_shouldExit{false};
IAppletManagerV3* g_appletMgr = nullptr;

// Launch callback
void OnLaunchComplete(const char* app_id, int result_code, const char* error_desc) {
std::cout << "\n[Launch Callback]" << std::endl;
std::cout << "App ID: " << app_id << std::endl;
std::cout << "Result: " << result_code << std::endl;

if (result_code == WMPF_ERRCODE_SUCCESS) {
std::cout << "Game launched successfully!" << std::endl;
} else {
std::cerr << "Launch failed: " << error_desc << std::endl;
}

g_launchCompleted = true;
}

// JsApi handler
bool OnJsApiCall(
const char* app_id,
const char* api_name,
const char* data,
size_t data_size,
int task_id
) {
std::cout << "\n[JsApi Call]" << std::endl;
std::cout << "API: " << api_name << std::endl;
std::cout << "App ID: " << app_id << std::endl;
std::cout << "Task ID: " << task_id << std::endl;
std::cout << "Data: " << std::string(data, data_size) << std::endl;

// Send response
const char* response = R"({"code": 0, "message": "success"})";
g_appletMgr->SendJsApiOrEventResponse(task_id, response, strlen(response));

return true;
}

// Event handler
bool OnGameEvent(
const char* event_name,
const char* data,
size_t data_size,
int task_id
) {
std::cout << "\n[Game Event]" << std::endl;
std::cout << "Event: " << event_name << std::endl;
std::cout << "Data: " << std::string(data, data_size) << std::endl;

return true;
}

int main() {
// 1. Initialize service (see init.md and browsing-service.md)
// ...
IBrowsingService* service = GetBrowsingService();
service->InitializeBrowsingCore(config, "", nullptr);

// 2. Get IAppletManagerV3
service->QueryInterface("IAppletManagerV3", (void**)&g_appletMgr);

if (!g_appletMgr) {
std::cerr << "Failed to get IAppletManagerV3" << std::endl;
return 1;
}

std::cout << "Got IAppletManagerV3 interface" << std::endl;

// 3. Set handlers
g_appletMgr->SetJsApiHandler(OnJsApiCall);
g_appletMgr->SetAppletEventHandler(OnGameEvent);
std::cout << "Handlers registered" << std::endl;

// 4. Launch game
// appId 和 launchKey 来源于游戏列表 API
// appId: 游戏列表 API 返回的 "id" 字段
// launchKey: 游戏列表 API 返回的 "launchKey" 字段
const char* appId = "691acb162dcfadc65a0fdb77";
const char* launchKey = "691acb162dcfadc65a0fdb77";

char launchConfig[2048];
snprintf(launchConfig, sizeof(launchConfig), R"({
"launchKey": "%s",
"accessToken": "your-access-token",
"userId": "developer",
"debug": true
})", launchKey);

std::cout << "\nLaunching game..." << std::endl;
g_appletMgr->LaunchApplet(
appId,
launchConfig,
strlen(launchConfig),
OnLaunchComplete
);

// 5. Wait for launch to complete
while (!g_launchCompleted && !g_shouldExit) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

if (!g_shouldExit) {
std::cout << "\nGame is running. Press Ctrl+C to exit..." << std::endl;

// Keep running for demo (in real app, use proper event loop)
std::this_thread::sleep_for(std::chrono::seconds(30));

// 6. Close game
std::cout << "\nClosing game..." << std::endl;
g_appletMgr->CloseApplet(appId);
}

// 7. Cleanup
g_appletMgr->Release();
service->UninitializeBrowsingCore();
service->Release();

std::cout << "Done!" << std::endl;
return 0;
}

6. 常见使用模式​

6.1 模式 1: 启动游戏并等待完成​

std::atomic<bool> launchDone{false};

void OnLaunch(const char* app_id, int result_code, const char* error_desc) {
launchDone = true;
}

appletMgr->LaunchApplet(appId, config, strlen(config), OnLaunch);

while (!launchDone) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

6.2 模式 2: 处理 JsApi 并返回结果​

bool OnJsApi(const char* app_id, const char* api_name,
const char* data, size_t data_size, int task_id) {
// Parse request
// Do some work

// Build response
std::string response = BuildResponse();

// Send back
appletMgr->SendJsApiOrEventResponse(
task_id,
response.c_str(),
response.length()
);

return true;
}

6.3 模式 3: 监听游戏事件​

bool OnEvent(const char* event_name, const char* data,
size_t data_size, int task_id) {
if (strcmp(event_name, "game_exited") == 0) {
// Game has exited, perform cleanup
std::cout << "Game exited" << std::endl;
}
return true;
}

7. 注意事项​

  1. 回调函数线程: 回调函数可能在不同线程中执行,注意线程安全
  2. 生命周期管理: 确保在游戏运行期间 IAppletManagerV3 对象保持有效
  3. 响应及时性: JsApi 和事件处理器应该快速返回,避免阻塞
  4. 内存管理: 传入的字符串参数由 SDK 内部管理,不要在回调后继续使用
  5. 错误处理: 始终检查启动回调中的 result_code

8. 相关文档​