高级用法
获取 SDK 和 Demo
- SDK 下载: PC SDK 下载页面
- Demo 项目: GitHub - UnityMiniHost/PCDemo
1. 自定义 JsApi 处理
1.1 实现 JsApi 处理器
SDK 允许您实现自定义的 JsApi 处理器来响应游戏中的 API 调用。
基本实现模式:
// Global applet manager reference for use in handler
static IAppletManagerV3* g_appletManager = nullptr;
// Main JsApi handler - dispatches to specific handlers
bool OnJsApiHandler(const char* app_id, const char* api_name,
const char* data, size_t data_size, int task_id) {
std::cout << "[JsApiHandler] API called: " << api_name << std::endl;
std::cout << " App ID: " << app_id << std::endl;
std::cout << " Task ID: " << task_id << std::endl;
std::cout << " Data Size: " << data_size << std::endl;
std::string dataStr = (data && data_size > 0) ? std::string(data, data_size) : "";
// Dispatch to specific handler based on api_name
if (api_name) {
if (strcmp(api_name, "TJLoginHost") == 0) {
return HandleTJLoginHost(app_id, dataStr, task_id);
}
if (strcmp(api_name, "loadRewardAd") == 0) {
return HandleLoadRewardAd(app_id, dataStr, task_id);
}
if (strcmp(api_name, "showRewardAd") == 0) {
return HandleShowRewardAd(app_id, dataStr, task_id);
}
}
// API not handled - send not_handled response
std::string notHandledResponse = R"({"success":false,"errorCode":"NOT_HANDLED","error":"API not handled"})";
if (g_appletManager) {
g_appletManager->SendJsApiOrEventResponse(task_id, notHandledResponse.c_str(), notHandledResponse.length());
}
return false;
}
// Register the handler
appletManager->SetJsApiHandler(OnJsApiHandler);
g_appletManager = appletManager; // Store global reference
1.2 实现认证处理器
示例:Unity Connect 认证
// Perform HTTP authentication
std::string PerformUnityConnectAuth(const std::string& accessToken) {
std::string encodedToken = UrlEncode(accessToken);
std::string url = "https://example.com/minihost?token=" + encodedToken;
// Use platform-specific HTTP library (WinHTTP on Windows, libcurl on macOS)
std::string responseBody = HttpGet(url);
// Extract LSToken from response
std::string lsToken = ExtractJsonStringValue(responseBody, "LSToken");
if (lsToken.empty()) {
throw std::runtime_error("LSToken not found in auth response");
}
return lsToken;
}
// TJLoginHost handler
bool HandleTJLoginHost(const char* app_id, const std::string& dataStr, int task_id) {
try {
std::string accessToken = ExtractJsonStringValue(dataStr, "accessToken");
if (accessToken.empty()) {
std::string errorResponse = R"({"success":false,"errorCode":"MISSING_TOKEN","error":"accessToken is required"})";
g_appletManager->SendJsApiOrEventResponse(task_id, errorResponse.c_str(), errorResponse.length());
return false;
}
std::string lsToken = PerformUnityConnectAuth(accessToken);
std::ostringstream responseOss;
responseOss << R"({"success":true,"result":{"code":")" << lsToken << R"("}})";
std::string successResponse = responseOss.str();
g_appletManager->SendJsApiOrEventResponse(task_id, successResponse.c_str(), successResponse.length());
return true;
} catch (const std::exception& e) {
std::ostringstream errorOss;
errorOss << R"({"success":false,"errorCode":"API_ERROR","error":")" << e.what() << R"("})";
std::string errorResponse = errorOss.str();
g_appletManager->SendJsApiOrEventResponse(task_id, errorResponse.c_str(), errorResponse.length());
return false;
}
}
HTTP 请求实现
HTTP 请求的具体实现(Windows 使用 WinHTTP,macOS 使用 libcurl)请参考 Demo 项目 中的 demo_http.cpp 文件。
2. 事件监听和处理
2.1 实现事件处理器
// Event handler - called when game sends an event
bool OnEventHandler(const char* event_name, const char* data, size_t data_size, int task_id) {
std::cout << "[EventHandler] Event received: " << event_name << std::endl;
std::cout << " Task ID: " << task_id << std::endl;
std::cout << " Data Size: " << data_size << std::endl;
if (data && data_size > 0) {
std::cout << " Data: " << std::string(data, data_size) << std::endl;
}
// Handle specific events
if (event_name && strcmp(event_name, "game_exited") == 0) {
std::cout << "[EventHandler] Game exited" << std::endl;
// Handle game exit
return true;
}
return true; // Indicate event was handled
}
// Register event handler
appletManager->SetAppletEventHandler(OnEventHandler);
3. 核心服务事件处理
3.1 实现 ICoreServiceHandler
class DemoCoreServiceHandler : public ICoreServiceHandler {
public:
// COM interface methods (for stack objects, no ref counting needed)
virtual INT QueryInterface(const char* type, void** ppvObject) override {
return -1; // Not implemented
}
virtual ULONG AddRef(void) override {
return 1; // No-op for stack objects
}
virtual ULONG Release(void) override {
return 1; // No-op for stack objects
}
// Service lifecycle events
virtual void OnContextInitialized() override {
std::cout << "[CoreServiceHandler] Context initialized" << std::endl;
}
virtual void OnServiceDisconnected() override {
std::cout << "[CoreServiceHandler] Service disconnected" << std::endl;
// Handle service disconnection
}
virtual bool OnCommonEventHappened(const char* event_name, int32_t callback_id,
const char* data, const unsigned int data_size) override {
std::cout << "[CoreServiceHandler] Event: " << event_name << std::endl;
// Check for server process exit event
if (event_name && strcmp(event_name, "cservice_event_report_process") == 0) {
if (data && strstr(data, "\"event\":2")) {
std::cout << "[CoreServiceHandler] Server process exiting" << std::endl;
// Handle server exit
}
}
return true;
}
};
// Usage
DemoCoreServiceHandler handler;
service->InitializeBrowsingCore(config, runtimePath, &handler);
字符串处理工具
JSON 解析和字符串转义的辅助函数请参考 Demo 项目 中的 demo_utils.cpp 文件。
4. 异步操作和状态管理
4.1 使用回调管理状态
// Global state for launch result
static volatile bool g_launchCompleted = false;
static volatile int g_launchResultCode = -1;
static volatile bool g_shouldExit = false;
// Launch callback
void OnLaunchComplete(const char* appId, int resultCode, const char* errorDesc) {
std::cout << "[LaunchCallback] Launch finished!" << std::endl;
std::cout << " App ID: " << appId << std::endl;
std::cout << " Result Code: " << resultCode << std::endl;
if (errorDesc && strlen(errorDesc) > 0) {
std::cout << " Error: " << errorDesc << std::endl;
}
g_launchCompleted = true;
g_launchResultCode = resultCode;
if (resultCode != 0) {
g_shouldExit = true;
}
}
// Wait for launch with timeout
int launchWaitTime = 0;
const int launchTimeout = 30000; // 30 seconds
const int checkInterval = 500; // Check every 500ms
while (!g_launchCompleted && launchWaitTime < launchTimeout) {
std::this_thread::sleep_for(std::chrono::milliseconds(checkInterval));
launchWaitTime += checkInterval;
if (g_shouldExit) {
std::cerr << "Launch failed, exiting..." << std::endl;
break;
}
}
if (!g_launchCompleted) {
std::cerr << "Launch timeout after " << launchTimeout / 1000 << " seconds" << std::endl;
}
5. 完整示例
完整的 C++ SDK 示例项目可从 GitHub 获取:
GitHub 仓库: UnityMiniHost/PCDemo
git clone https://github.com/UnityMiniHost/PCDemo.git
cd PCDemo
项目包含:
demo.cpp- 完整实现示例(1100+ 行)include/- SDK 头文件scripts/- 构建和运行脚本native_sdk/- 预打包的 SDK 和运行时
关键实现要点:
- 平台相关的 HTTP 请求实现(WinHTTP / libcurl)
- 自定义 JsApi 处理器(TJLoginHost, loadRewardAd, showRewardAd)
- 事件处理和状态管理
- 跨平台库加载和资源清理
快速运行:
# Windows
scripts\build-and-run.bat
# macOS
./scripts/build-and-run.sh