C++ SDK 快速集成
WebGLHost C++ SDK 提供了标准的 C++ 接口,用于在 Windows 和 macOS 桌面应用中集成和管理 WebGL 游戏小程序。
1. 获取凭据
集成 SDK 需要先在 小游戏宿主控制台 中创建应用,获得每个应用专属的 APP KEY, APP SECRET 及 Service Token 后。
启动 SDK 时,需要通过 APP KEY,APP SECRET 初始化。接入方也可联系 Unity 以创建 App Service Token / App Key / App Secret。
如下是测试用 App Service Token / App Key / App Secret 示例
- App Service Token
- App Key:
AKIDt1vMSYVFf1twI53iDecobx6QsTK0 - App Secret:
ufzN1iD8PsnMW0ViDCMhpJFBiLR1E1Xf
Service Token 的主要作用是调用以下 API 获取游戏列表,并可从中获取 Game ID 和 Launch Key 以启动游戏。
1.1 关键 ID 说明
在集成 SDK 时,需要理解以下几个关键标识符:
| 标识符 | 说明 | 来源 |
|---|---|---|
| Game ID (Applet ID) | 游戏的唯一标识符,用于 LaunchApplet 和 CloseApplet 的第一个参数 | 游戏列表 API 返回的 id 字段 |
| Launch Key | 游戏启动 Key,用于 launchConfig 中的 launchKey 字段 | 游戏列表 API 返回的 launchKey 字段 |
| Host App ID | 宿主应用的唯一标识符,用于获取游戏列表 | 在控制台创建应用时获得 |
| Access Token | 用户访问令牌,用于身份验证 | 由宿主应用的用户系统提供 |
游戏列表 API 返回示例:
[
{
"id": "691acb162dcfadc65a0fdb77", // Game ID - 用于 LaunchApplet 第一个参数
"appId": "691ac9ef2dcfadc65a0fb4a6", // Host App ID
"name": "示例游戏",
"launchKey": "691acb162dcfadc65a0fdb77", // Launch Key - 用于 launchConfig
"gameType": "webgl",
"briefIntro": "这是一个示例游戏"
}
]
实际生产环境中,Service Token 应该在服务端使用,从服务端调用上面的 API 。Demo 项目中,Service Token 是在客户端使用,这个仅仅是一个实例,不建议在生产环境中这样使用。
2. 获取 SDK
2.1 下载 SDK
从 PC SDK 下载页面 下载最新的 C++ SDK 包。
2.2 获取 Demo 项目
完整的 C++ SDK Demo 项目可从 GitHub 获取:
GitHub 仓库: https://github.com/UnityMiniHost/PCDemo
# 克隆 Demo 项目
git clone https://github.com/UnityMiniHost/PCDemo.git
cd PCDemo
SDK Demo 项目包含以下内容:
PCDemo_cpp/
├── include/ # SDK 头文件
│ ├── IBrowsingService.h # 主服务接口
│ ├── IAppletManagerV3.h # 游戏管理接口
│ ├── ICoreServiceHandler.h # 事件处理接口
│ └── WIUnknown.h # 基础接口
├── native_sdk/ # 预打包的 SDK 和运行时
│ ├── windows/ # Windows 平台
│ │ ├── host.zip # SDK DLL (webglhost_export.dll)
│ │ ├── runtime.z01 # 运行时分卷压缩包 (part 1)
│ │ ├── runtime.z02 # 运行时分卷压缩包 (part 2)
│ │ ├── runtime.z03 # 运行时分卷压缩包 (part 3)
│ │ └── version.json # 版本信息
│ └── mac/ # macOS 平台
│ ├── runtime-x64.tar.gz.01 # x64 运行时分卷压缩包 (part 1)
│ ├── runtime-x64.tar.gz.02 # x64 运行时分卷压缩包 (part 2)
│ ├── runtime-x64.tar.gz.03 # x64 运行时分卷压缩包 (part 3)
│ ├── runtime-arm64.tar.gz.01 # ARM64 运行时分卷压缩包 (part 1)
│ ├── runtime-arm64.tar.gz.02 # ARM64 运行时分卷压缩包 (part 2)
│ ├── runtime-arm64.tar.gz.03 # ARM64 运行时分卷压缩包 (part 3)
│ └── version.json # 版本信息
├── demo.cpp # 示例代码
├── CMakeLists.txt # CMake 构建配置
├── scripts/ # 构建和运行脚本
│ ├── build.bat # Windows 构建脚本
│ ├── build.sh # macOS 构建脚本
│ ├── build-and-run.bat # Windows 一键构建运行
│ ├── build-and-run.sh # macOS 一键构建运行
│ ├── clean.bat # Windows 清理脚本
│ ├── clean.sh # macOS 清理脚本
│ ├── pack.bat # Windows 打包脚本
│ ├── pack.sh # macOS 打包脚本
│ ├── run.bat # Windows 运行脚本
│ ├── run.sh # macOS 运行脚本
│ └── USAGE.md # 脚本使用说明
├── docs/ # 文档
│ ├── Quick-Start-Guide.md # 快速开始指南
│ └── API-Integration-Guide.md # API 集成指南
└── README.md # 项目说明
**注意**:
- SDK 和运行时文件已预先打包在 `native_sdk/` 目录中
- 使用分卷压缩以适应 Git 仓库大小限制
- 构建脚本会自动解压这些文件到正确的位置
- Windows: `webglhost_export.dll` 和 `webglhost-runtime.exe`
- macOS: `libwebglhost_export.dylib` 和 `webglhost-runtime.app`
3. 快速开始
3.1 添加头文件
将 include/ 目录添加到项目的包含路径:
#include "IBrowsingService.h"
#include "IAppletManagerV3.h"
#include "ICoreServiceHandler.h"
3.2 配置项目
CMake 配置:
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加头文件路径
include_directories(${CMAKE_SOURCE_DIR}/include)
# 链接库 (Windows)
if(WIN32)
target_link_libraries(your_app ws2_32)
endif()
Visual Studio 项目配置 (Windows):
- 项目属性 → C/C++ → 常规 → 附加包含目录: 添加
include路径 - 项目属性 → 链接器 → 输入 → 附加依赖项: 添加
ws2_32.lib - 项目属性 → C/C++ → 语言 → C++ 语言标准: ISO C++17 标准
Xcode 项目配置 (macOS):
- Build Settings → Header Search Paths: 添加
include路径 - Build Settings → C++ Language Dialect: C++17
- 不需要额外链接库(系统框架自动链接)
3.3 加载 SDK
Windows:
#include <windows.h>
#include "IBrowsingService.h"
// Load DLL
HMODULE hDll = LoadLibraryA("host\\webglhost_export.dll");
if (!hDll) {
std::cerr << "Failed to load DLL" << std::endl;
return 1;
}
// Get factory function
typedef IBrowsingService* (*GetBrowsingServiceFunc)();
GetBrowsingServiceFunc GetBrowsingService =
(GetBrowsingServiceFunc)GetProcAddress(hDll, "GetBrowsingService");
if (!GetBrowsingService) {
std::cerr << "Failed to get GetBrowsingService function" << std::endl;
FreeLibrary(hDll);
return 1;
}
// Get service instance
IBrowsingService* service = GetBrowsingService();
macOS:
#include <dlfcn.h>
#include "IBrowsingService.h"
// Load dylib
void* hDll = dlopen("host/libwebglhost_export.dylib", RTLD_LAZY);
if (!hDll) {
std::cerr << "Failed to load dylib: " << dlerror() << std::endl;
return 1;
}
// Get factory function
typedef IBrowsingService* (*GetBrowsingServiceFunc)();
GetBrowsingServiceFunc GetBrowsingService =
(GetBrowsingServiceFunc)dlsym(hDll, "GetBrowsingService");
if (!GetBrowsingService) {
std::cerr << "Failed to get GetBrowsingService function: " << dlerror() << std::endl;
dlclose(hDll);
return 1;
}
// Get service instance
IBrowsingService* service = GetBrowsingService();
3.4 初始化 SDK
// Configuration
const char* SDK_KEY = "your-sdk-key";
const char* SDK_SECRET = "your-sdk-secret";
// Build config JSON
char config[1024];
snprintf(config, sizeof(config), R"({
"sdkKey": "%s",
"sdkSecret": "%s",
"debug": true
})", SDK_KEY, SDK_SECRET);
// Initialize (runtime_path: empty for auto-detection)
int result = service->InitializeBrowsingCore(config, "", nullptr);
if (result == WMPF_ERRCODE_SUCCESS) {
std::cout << "SDK initialized successfully!" << std::endl;
} else {
std::cerr << "SDK initialization failed: " << result << std::endl;
return 1;
}
3.5 获取游戏管理器
// Query IAppletManagerV3 interface
IAppletManagerV3* appletMgr = nullptr;
result = service->QueryInterface("IAppletManagerV3", (void**)&appletMgr);
if (result != WMPF_ERRCODE_SUCCESS || !appletMgr) {
std::cerr << "Failed to get IAppletManagerV3" << std::endl;
return 1;
}
std::cout << "Got IAppletManagerV3 interface" << std::endl;
3.6 启动游戏
// 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;
}
}
// Game configuration
// APPLET_ID: 来源于游戏列表 API 返回的 "id" 字段
// LAUNCH_KEY: 来源于游戏列表 API 返回的 "launchKey" 字段
const char* APPLET_ID = "691acb162dcfadc65a0fdb77"; // 从游戏列表获取
const char* LAUNCH_KEY = "691acb162dcfadc65a0fdb77"; // 从游戏列表获取
const char* ACCESS_TOKEN = "your-access-token";
// Build launch config
// launchKey 必须使用从游戏列表 API 获取
char launchConfig[2048];
snprintf(launchConfig, sizeof(launchConfig), R"({
"launchKey": "%s",
"accessToken": "%s",
"userId": "developer",
"debug": true,
"mute": false
})", LAUNCH_KEY, ACCESS_TOKEN);
// Launch the game
// 第一个参数 APPLET_ID 是游戏列表 API 返回的 "id" 字段
appletMgr->LaunchApplet(
APPLET_ID,
launchConfig,
strlen(launchConfig),
OnLaunchComplete
);
std::cout << "Game launch request sent..." << std::endl;
3.7 清理资源
// Wait for game to finish (in real app, use event loop)
std::this_thread::sleep_for(std::chrono::seconds(60));
// Close game
appletMgr->CloseApplet(APPLET_ID);
// Cleanup
appletMgr->Release();
service->UninitializeBrowsingCore();
service->Release();
// Unload library
#ifdef _WIN32
FreeLibrary(hDll);
#else
dlclose(hDll);
#endif
std::cout << "Cleanup complete" << std::endl;
4. 完整最小示例
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include "IBrowsingService.h"
#include "IAppletManagerV3.h"
// SDK Configuration
const char* SDK_KEY = "AKIDcv9N9wkDXKZ7gDoB2avKlu0N8tnS";
const char* SDK_SECRET = "sp9ZsGlNLmTSX9o0sa29C5FwmxemUV8A";
const char* ACCESS_TOKEN = "w2uAAaGN0WOdmNiNLcKQML4JT3O-5ng2hx2Mur_1dvY01ef";
// Game Configuration - 这些值应该从游戏列表 API 获取
// APPLET_ID: 游戏列表 API 返回的 "id" 字段
// LAUNCH_KEY: 游戏列表 API 返回的 "launchKey" 字段
const char* APPLET_ID = "691acb162dcfadc65a0fdb77";
const char* LAUNCH_KEY = "691acb162dcfadc65a0fdb77";
// Global state
std::atomic<bool> g_launchCompleted{false};
std::atomic<int> g_launchResultCode{-1};
// Launch callback
void OnLaunchComplete(const char* app_id, int result_code, const char* error_desc) {
g_launchResultCode = result_code;
g_launchCompleted = true;
if (result_code == WMPF_ERRCODE_SUCCESS) {
std::cout << "Game launched: " << app_id << std::endl;
} else {
std::cerr << "Launch failed: " << (error_desc ? error_desc : "Unknown error") << std::endl;
}
}
int main() {
// 1. Load library
#ifdef _WIN32
HMODULE hDll = LoadLibraryA("host\\webglhost_export.dll");
if (!hDll) {
std::cerr << "Failed to load DLL" << std::endl;
return 1;
}
typedef IBrowsingService* (*GetBrowsingServiceFunc)();
GetBrowsingServiceFunc GetBrowsingService =
(GetBrowsingServiceFunc)GetProcAddress(hDll, "GetBrowsingService");
#else
void* hDll = dlopen("host/libwebglhost_export.dylib", RTLD_LAZY);
if (!hDll) {
std::cerr << "Failed to load dylib: " << dlerror() << std::endl;
return 1;
}
typedef IBrowsingService* (*GetBrowsingServiceFunc)();
GetBrowsingServiceFunc GetBrowsingService =
(GetBrowsingServiceFunc)dlsym(hDll, "GetBrowsingService");
#endif
if (!GetBrowsingService) {
std::cerr << "Failed to get GetBrowsingService" << std::endl;
return 1;
}
// 2. Get service instance
IBrowsingService* service = GetBrowsingService();
if (!service) {
std::cerr << "Failed to get service instance" << std::endl;
return 1;
}
// 3. Initialize SDK
char config[1024];
snprintf(config, sizeof(config), R"({
"sdkKey": "%s",
"sdkSecret": "%s",
"debug": true
})", SDK_KEY, SDK_SECRET);
std::cout << "Initializing SDK..." << std::endl;
int result = service->InitializeBrowsingCore(config, "", nullptr);
if (result != WMPF_ERRCODE_SUCCESS) {
std::cerr << "Init failed: " << result << std::endl;
return 1;
}
std::cout << "SDK initialized" << std::endl;
// 4. Get applet manager
IAppletManagerV3* appletMgr = nullptr;
result = service->QueryInterface("IAppletManagerV3", (void**)&appletMgr);
if (result != WMPF_ERRCODE_SUCCESS || !appletMgr) {
std::cerr << "Failed to get IAppletManagerV3" << std::endl;
return 1;
}
std::cout << "Got IAppletManagerV3" << std::endl;
// 5. Launch game
// launchKey 来源于游戏列表 API 返回的 "launchKey" 字段
char launchConfig[2048];
snprintf(launchConfig, sizeof(launchConfig), R"({
"launchKey": "%s",
"accessToken": "%s",
"userId": "developer",
"debug": true
})", LAUNCH_KEY, ACCESS_TOKEN);
std::cout << "Launching game..." << std::endl;
// APPLET_ID 来源于游戏列表 API 返回的 "id" 字段
appletMgr->LaunchApplet(APPLET_ID, launchConfig, strlen(launchConfig), OnLaunchComplete);
// 6. Wait for launch
while (!g_launchCompleted) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
if (g_launchResultCode != WMPF_ERRCODE_SUCCESS) {
std::cerr << "Game launch failed, exiting..." << std::endl;
appletMgr->Release();
service->UninitializeBrowsingCore();
service->Release();
return 1;
}
// 7. Keep running
std::cout << "\nGame is running. Press Ctrl+C to exit..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(60));
// 8. Cleanup
std::cout << "\nClosing game..." << std::endl;
appletMgr->CloseApplet(APPLET_ID);
appletMgr->Release();
service->UninitializeBrowsingCore();
service->Release();
#ifdef _WIN32
FreeLibrary(hDll);
#else
dlclose(hDll);
#endif
std::cout << "Done!" << std::endl;
return 0;
}
5. 编译和运行
Demo 项目提供了便捷的脚本来自动解压 SDK、构建和运行示例程序。
5.1 Windows
一键构建并运行:
cd scripts
build-and-run.bat
分步操作:
cd scripts
REM 1. 构建项目(自动解压 SDK 和运行时)
build.bat
REM 2. 运行示例
run.bat
REM 3. 清理构建产物
clean.bat
使用 CMake 手动构建:
# 首先需要手动解压 native_sdk/windows/ 下的文件
mkdir build
cd build
cmake .. -G "Visual Studio 16 2019" -A x64
cmake --build . --config Release
.\Release\demo.exe
5.2 macOS
一键构建并运行:
cd scripts
chmod +x *.sh
./build-and-run.sh
分步操作:
cd scripts
chmod +x *.sh
# 1. 构建项目(自动解压 SDK 和运行时)
./build.sh
# 2. 运行示例
./run.sh
# 3. 清理构建产物
./clean.sh
使用 CMake 手动构建:
# 首先需要手动解压 native_sdk/mac/ 下的文件
mkdir build
cd build
cmake ..
make
./demo
构建脚本说明:
- 构建脚本会自动检测系统架构(x64 或 ARM64)
- 自动合并和解压分卷压缩包
- 将 SDK 和运行时文件放置到正确的位置
- 详细说明请参考
scripts/USAGE.md
6. 系统要求
6.1 Windows
- 操作系统: Windows 10/11 (64位)
- 开发工具: Visual Studio 2019 或更高版本
- C++ 标准: C++17 或更高
- 依赖库: ws2_32.lib (Windows Sockets)
6.2 macOS
- 操作系统: macOS 10.15+ (Catalina 或更高版本)
- 开发工具: Xcode Command Line Tools
- C++ 标准: C++17 或更高
- 依赖库: 系统框架(自动链接)
7. 常见问题
7.1 DLL/dylib 加载失败
Windows:
- 确保
webglhost_export.dll在可执行文件同目录或系统路径中 - 检查 Visual C++ Redistributable 是否已安装
macOS:
- 使用绝对路径或相对路径加载 dylib
- 检查库签名和权限
7.2 初始化失败
- 验证 SDK Key 和 Secret
- 确保运行时文件
runtime/webglhost-runtime.exe(Windows)或runtime/webglhost-runtime.app(macOS)存在 - 检查网络连接
7.3 游戏启动失败
- 查看错误描述信息