一、无影开放SDK集成与使用
1、要求
客户端要求
WYSDK API是无影云电脑应用程序的Windows安装包的一部分。在客户端设备上安装适用于Windows的无影云电脑应用程序。确保WYSDK.dll(适用于64位机器)存在于无影云电脑应用程序的Windows安装文件夹中。
服务器端要求
WYSDK要求在客户端和服务器之间完成登录、选择云电脑和获取Ticket。无影服务端开放平台对接请参考API概览。
2、使用SDK的步骤
验证WYSDK二进制文件是否安装在客户端上(WYSDK.dll)。
从安装路径加载WYSDK.DLL。在这里,客户端可以使用无影云电脑应用程序注册表项来获取WYSDK二进制文件的安装路径。
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{D19D277C-E465-4F61-A725-231B7DB9255D}_is1是安装的注册表路径。
使用LoadLibrary加载WYSDK.DLL。
使用GetProcAddress获取API并相应使用,但要使用API,需要初始化SDK。
3、获取WYSDK.DLL路径
通过注册获取到无影云电脑的安装目录
std::string getDicOfSDK() {
HKEY hkey = nullptr;
std::string sub_key = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{D19D277C-E465-4F61-A725-231B7DB9255D}_is1";
LSTATUS res = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub_key.c_str(), 0, KEY_READ, &hkey);
if (res != ERROR_SUCCESS) {
printf("RegOpenKeyExA status:%d failed: %d\n", res, GetLastError());
return "";
}
std::string valueName = std::string("InstallLocation");
DWORD dwType = REG_SZ;
DWORD dwSize = 0;
LSTATUS ret = RegQueryValueExA(hkey, valueName.c_str(), NULL, &dwType, nullptr, &dwSize);
if (ret != ERROR_SUCCESS || dwSize <= 0) {
printf("RegQueryValueExA status:%d size:%d valueName:%s failed: %d\n", ret, dwSize, valueName.c_str(), GetLastError());
RegCloseKey(hkey);
return "";
}
std::vector<BYTE> value_data(dwSize);
ret = RegQueryValueExA(hkey, valueName.c_str(), NULL, &dwType, value_data.data(), &dwSize);
if (ret != ERROR_SUCCESS) {
printf("RegQueryValueExA status:%d valueName:%s failed: %d\n", ret, valueName.c_str(), GetLastError());
RegCloseKey(hkey);
return "";
}
RegCloseKey(hkey);
std::string path(value_data.begin(), value_data.end());
if (path.back() == '\0') {
path.pop_back();
}
path.append(std::string("bin"));
printf("RegQueryValueExA11 valueName:%s res: %s\n", valueName.c_str(), path.c_str());
return path;
}
4、Demo
示例代码:WYSDKDemo.zip
#include <iostream>
#include <windows.h>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
struct WYResponse {
int code;
const char* content;
const char* requestKey;
const char* requestParams;
};
typedef WYResponse(*WYSyncRequest)(const char* key, const char* params);
typedef void (*WYAsyncRequest)(const char* key, const char* params, void (*callback)(WYResponse));
typedef void (*WYFreeResponse)(WYResponse& response);
WYSyncRequest SyncRequest;
WYAsyncRequest AsyncRequest;
WYFreeResponse FreeResponse;
std::string getConnectParams(const std::string& desktopId, const std::string& desktopName, const std::string& ticket) {
std::string operationInfo = std::string("\"operation\":\"openDesktop\"");
std::string bizParams = std::string("\"bizParam\":{\"ticket\":\"") + ticket + std::string("\",\"desktopId\":\"") + desktopId + std::string("\",\"desktopName\":\"") + desktopName + std::string("\"}");
std::string extInfo = std::string("\"extInfo\":{\"language\":\"zh\",\"fullscreen\":false,\"hideFloatingBall\":false,\"cloudDpi\":150}");
std::string connectParams = "";
connectParams.append(std::string("{"));
connectParams.append(operationInfo);
connectParams.append(std::string(","));
connectParams.append(bizParams);
connectParams.append(std::string(","));
connectParams.append(extInfo);
connectParams.append(std::string("}"));
return connectParams;
}
std::string getCloudAppConnectParams(const std::string& desktopId, const std::string& desktopName, const std::string& ticket) {
std::string operationInfo = std::string("\"operation\":\"openApp\"");
std::string bizParams = std::string("\"bizParam\":{\"ticket\":\"") + ticket + std::string("\",\"appInstanceGroupId\":\"") + desktopId + std::string("\",\"appName\":\"") + desktopName + std::string("\",") + std::string("\"osType\":\"Windows\"}");
std::string connectParams = "";
connectParams.append(std::string("{"));
connectParams.append(operationInfo);
connectParams.append(std::string(","));
connectParams.append(bizParams);
connectParams.append(std::string("}"));
return connectParams;
}
void connectDesktop(bool isCloudApp, const std::string& desktopId, const std::string& desktopName, const std::string& ticket) {
std::string listenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
listenerParams.append(desktopId);
listenerParams.append("\"}");
AsyncRequest("WYRegisterListener", listenerParams.c_str(), [](WYResponse value) {
printf("Listener callback value %s\n", value.content);
});
std::string connectParams = isCloudApp ? getCloudAppConnectParams(desktopId, desktopName, ticket) : getConnectParams(desktopId, desktopName, ticket);
WYResponse createConnectValue = SyncRequest("WYCreateConnect", connectParams.c_str());
FreeResponse(createConnectValue);
}
void disconnectDesktop(const std::string& desktopId) {
std::string disparams = std::string("{\"connectId\":\"");
disparams.append(desktopId);
disparams.append("\"}");
WYResponse disConnectValue = SyncRequest("WYDisconnect", disparams.c_str());
FreeResponse(disConnectValue);
std::string unListenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
unListenerParams.append(desktopId);
unListenerParams.append("\"}");
WYResponse unStatusValue = SyncRequest("WYUnregisterListener", unListenerParams.c_str());
FreeResponse(unStatusValue);
}
void toEnumerateConnectInfo() {
WYResponse infoListValue = SyncRequest("enumConnections", NULL);
printf("WYEnumerateConnectInfo info %s\n", infoListValue.content);
FreeResponse(infoListValue);
}
void toGetUUID() {
WYResponse uuidValue = SyncRequest("uuid", NULL);
printf("uuid is %s\n", uuidValue.content);
FreeResponse(uuidValue);
}
int runSDK(const std::string& directory) {
//初始化SDK
std::string config = std::string("{\"partnerInfo\":{\"partner\":\"wuyingPartnerTest\",\"partnerApp\":\"WuyingPartnerTestApp\"}, \"launcherPath\":\"");
config.append(directory);
config.append(std::string("\\stream_launcher.exe"));
config.append(std::string("\"}"));
WYResponse initValue = SyncRequest("WYInitialize", config.c_str());
FreeResponse(initValue);
//监听SDK日志输出回调
AsyncRequest("WYRegisterListener", "{\"tag\": \"onOutputLog\"}", [](WYResponse value) {
printf("%s\n", value.content);
});
//监听SDK错误回调
AsyncRequest("WYRegisterListener", "{\"tag\": \"onErrorCode\"}", [](WYResponse value) {
int code = value.code;
if (code == 200 || code == 201 || code == 202) {
//建议: 最好去重启进程, 如果不想重启进程,可以去重新加载WYSDK.dll,但进程里会存留一些垃圾静态实例
}
printf("Listener callback tag %s value %d\n", value.requestParams, code);
});
//运行SDK
WYResponse runValue = SyncRequest("WYRun", NULL);
int runCode = runValue.code;
FreeResponse(runValue);
printf("sdk run %s\n", runCode == 0 ? "ok" : "fail");
if (runCode == 0) {
toGetUUID();
// 唤出问题反馈
//WYResponse feedbackValue = WYSyncRequest("feedback", NULL);
//FreeResponse(feedbackValue);
// 唤出版本升级
//WYResponse upgradeValue = WYSyncRequest("upgrade", NULL);
//FreeResponse(upgradeValue);
std::string desktopId = std::string("ecd-iolwxthr1vcpoefhp");
std::string desktopName = std::string("wenzhang-20220927");
std::string desktopTicket = std::string("*****");
std::string appInstanceGroupId = std::string("ca-6p9vj2m79tlwcsl8z");
std::string appName = std::string("Chrome");
std::string appTicket = std::string("****");
for (int i = 0; i < 1; i++) {
//连接云电脑/云应用
connectDesktop(false, desktopId, desktopName, desktopTicket);
//connectDesktop(true, appInstanceGroupId, appName, appTicket);
std::this_thread::sleep_for(std::chrono::seconds(5));
toEnumerateConnectInfo();
//断开云电脑/云应用
disconnectDesktop(desktopId);
//std::this_thread::sleep_for(std::chrono::seconds(2));
//disconnectDesktop(appInstanceGroupId);
}
}
//取消监听SDK错误回调
WYResponse unErrorValue = SyncRequest("WYUnregisterListener", "{\"tag\": \"onErrorCode\"}");
FreeResponse(unErrorValue);
//取消监听SDK日志输出回调
WYResponse unLogValue = SyncRequest("WYUnregisterListener", "{\"tag\": \"onOutputLog\"}");
FreeResponse(unLogValue);
//销毁SDK
WYResponse unInitValue = SyncRequest("WYUninitialize", NULL);
FreeResponse(unInitValue);
printf("\n\n\n\n\n");
return 0;
}
int main() {
printf("begin to load SDK dll \n");
std::string directory = "D:\\Code\\20230731\\output\\windows_amd64_release\\target\\bin";// getDicOfSDK();
std::wstring wideDirectory(directory.begin(), directory.end());
LPCWSTR widePath = wideDirectory.c_str();
SetDllDirectory(widePath);
//加载动态库,动态库的生命周期需要跟着进程生命周期走
HMODULE hModule = LoadLibrary(L"WYSDK.dll");
if (hModule == NULL) {
std::cout << "Failed to load DLL" << GetLastError() << std::endl;
return 1;
}
printf("load SDK dll success \n");
printf("begin to load function \n");
// 获取函数指针
SyncRequest = (WYSyncRequest)GetProcAddress(hModule, "WYSyncRequest");
AsyncRequest = (WYAsyncRequest)GetProcAddress(hModule, "WYAsyncRequest");
FreeResponse = (WYFreeResponse)GetProcAddress(hModule, "WYFreeResponse");
if (!SyncRequest || !AsyncRequest || !FreeResponse) {
printf("load function fail \n");
return 1;
}
printf("load function success \n");
for (int i = 0; i < 1; i++)
{
runSDK(directory);
}
//不建议 卸载动态链接库
//FreeLibrary(hModule);
//printf("finished to free SDK dll\n");
return 0;
}
二、支持功能列表
功能 | 说明 |
打开云电脑 | 支持 |
断开云电脑 | 支持 |
打开云应用 | 支持 |
断开云应用 | 支持 |
设置语言(中文/英文) | 支持 连接云电脑配置 |
设置缩放比 | 支持 连接云电脑配置 |
隐藏悬浮球 | 支持 连接云电脑配置 |
是否全屏 | 支持 连接云电脑配置 |
获取设备uuid | 支持 |
获取SDK版本号 | 支持 |
获取所有云电脑信息 | 支持 |
监听SDK错误回调 | 支持 |
监听云电脑/云应用连接状态 | 支持 |
唤出问题反馈界面 | 支持 |
唤出版本升级界面 | 支持 |
三、WYSDK的API
1、API简介
WYSyncRequest
同步执行请求
WYResponse WYSyncRequest(constchar* key, constchar* params);
参数:
key: 请求唯一标识
params:请求参数
返回值:
请求结构,结构如下
struct WYResponse {
int code;
const char* content;
const char* requestKey;
const char* requestParams;
};
code为0,表示请求成功,content为请求到的数据,requestKey和requestParams为请求入参的key和params。
注意:返回值在使用完成的时候,调用WYFreeResponse去释放WYResponse内存。
WYAsyncRequest
void WYAsyncRequest(constchar* key, constchar* params, void (*callback)(WYResponse));
异步执行请求,(备注:异步请求接口支持所有同步执行的key)
参数:
key: 请求唯一标识
params:请求参数
callback:异常执行的回调
WYFreeResponse
void WYFreeResponse(WYResponse& response);
释放请求到的reponse对象
2、API使用
初始化SDK
std::string directory = getDicOfSDK();
std::string config = std::string("{\"partnerInfo\":{\"partner\":\"***\",\"partnerApp\":\"***\"}, \"launcherPath\":\"");
config.append(directory);
config.append(std::string("\\stream_launcher.exe"));
config.append(std::string("\"}"));
WYResponse value = SyncRequest("WYInitialize", config.c_str());
FreeResponse(value);
调用WYSyncRequest接口,参数为"WYInitialize"和配置信息。
配置信息,格式为JSON,其中必现包含partnerInfo和launcherPath相关信息
partnerInfo:调用无影服务的合作方的信息
○ partner:合作方公司名称
○ partnerApp:合作方应用的名称
launcherPath:为stream_launcher.exe的绝对路径
返回值:value.code 0-成功 其他值-失败
释放SDK
WYResponse value = SyncRequest("WYUninitialize", NULL);
FreeResponse(value);
调用WYSyncRequest接口,参数为"WYUninitialize"。
返回值:value.code 0-成功 其他值-失败
运行SDK
WYResponse value = SyncRequest("WYRun", NULL);
FreeResponse(value);
调用WYSyncRequest接口,参数为"WYRun"。
返回值:value.code 0-成功 其他值-失败
监听日志输出Listener
AsyncRequest("WYRegisterListener", "{\"tag\": \"onOutputLog\"}", [](WYResponse value) {
printf("%s\n", value.content);
});
调用WYAsyncRequest接口,参数为"WYRegisterListener"、Listener参数(JSON结构)和执行回调。
Listener参数:tag唯一标识,状态回调唯一标识为:onOutputLog。
监听错误回调Listener
AsyncRequest("WYRegisterListener", "{\"tag\": \"onErrorCode\"}", [](WYResponse value) {
int code = value.code;
if (code == 200 || code == 201 || code == 202) {
//建议: 最好去重启进程, 如果不想重启进程,可以去重新加载WYSDK.dll,但进程里会存留一些垃圾静态实例
}
printf("Listener callback tag %s value %d\n", value.requestParams, code);
});
调用WYAsyncRequest接口,参数为"WYRegisterListener"、Listener参数(JSON结构)和执行回调。
Listener参数:tag唯一标识,状态回调唯一标识为:"onErrorCode"。
监听云电脑/云应用状态回调Listener
std::string listenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
listenerParams.append(desktopId);
listenerParams.append("\"}");
AsyncRequest("WYRegisterListener", listenerParams.c_str(), [](WYResponse value) {
printf("Listener callback value %s\n", value.content);
});
调用WYAsyncRequest接口,参数为"WYRegisterListener"、Listener参数(JSON结构)和执行回调。
Listener参数:tag唯一标识,状态回调唯一标识为:onStatusChange,connectId云电脑/云应用的ID
取消监听Listener
std::string unListenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
unListenerParams.append(desktopId);
unListenerParams.append("\"}");
WYResponse unStatusValue = SyncRequest("WYUnregisterListener", unListenerParams.c_str());
FreeResponse(unStatusValue);
调用WYAsyncRequest接口,参数为"WYUnregisterListener"、unlistener参数(JSON结构)。unlistener参数与listener对应。
创建连接云电脑/云应用
std::string connectParams = “{***}”;
WYResponse createConnectValue = SyncRequest("WYCreateConnect", connectParams.c_str());
FreeResponse(createConnectValue);
调用WYSyncRequest接口,参数为"WYCreateConnect"和连接参数。
连接参数:是一个JSON结构,格式如下
名称 | 类型 | 必填 | 描述 | 示例 |
operation | String | 是 | 操作名称 | openDesktop-打开云电脑 openApp-打开云应用 |
| object | 是 | 透传从无影服务端获取到的连接信息 | |
-- ticket | String | 是 | ticket为调用无影开放平台GetConnectionTicket - 获取连接凭证接口返回的ticket信息 | |
-- desktopId | String | 是 | 云电脑Id | ecd-7nvbz4ccjly95xxxx |
-- desktopName | String | 是 | 云电脑名称 | xx的云电脑 |
-- osType | String | 是 | 系统类型 | windows |
| object | 是 | 调用无影服务的合作方的信息 | |
-- partner | String | 是 | 合作方公司名称 | xxx公司 |
-- partnerApp | String | 是 | 合作方应用的名称 | xxx应用 |
| object | 否 | 扩展字段,外部配置参数 | |
-- language | String | 否 | 设置一次后所有打开的窗口UI都会显示设置的语言(未设置时默认为中文) | “zh” --- 中文 “en” --- 英文 |
-- cloudDpi | int | 否 | 云电脑启动时的默认dpi缩放比例
| 100 |
-- fullscreen | bool | 否 | 是否在全屏窗口状态打开云资源
| true |
-- isVpc | bool | 否 | 是否走vpc网络
| false |
-- hideFloatingBall | bool | 否 | 是否隐藏云资源窗口内的悬浮球
| false |
| object | 否 | 网络代理配置 | |
-- type | String | 否 | 代理类型 目前支持系统代理、socket代理、HTTP代理3种方式 | system - 系统代理 socket - socket代理 HTTP - HTTP代理 |
-- host | String | 否 | 代理的host | 127.x.x.x |
-- port | int | 否 | 代理端口号 | 50550 |
-- account | String | 否 | 代理账号 | |
-- password | String | 否 | 代理密码 |
示例
JSON格式
{
"operation": "openDesktop",
"bizParam": {
"ticket": "xxxxxxxxxxxxxxxxxxxxxxx",
"desktopId": "ecd-7nvbz4ccjly95xxxx",
"desktopName": "xx的云电脑",
"osType": "windows"
},
"partnerInfo": {
"partner": "wuyingPartnerTest",
"partnerApp": "WuyingPartnerTestApp"
},
"extInfo": {
"language": "zh",
"cloudDpi": 150,
"fullscreen": true,
"isVpc": true,
"hideFloatingBall": true,
"proxy": {
"type": "system",
"host": "xxxxxx",
"port": 1111,
"account": "xxxx",
"password": "xxx"
}
}
断开连接云电脑/云应用
WYResponse disConnectValue = SyncRequest("WYDisconnect", "{\"connectId\":\"***\"}");
FreeResponse(disConnectValue);
调用WYSyncRequest接口,参数为"WYDisconnect"和断连参数。
断连参数:是一个JSON结构,包含connectId
connectId: 使用云电脑Id或云应用id
遍历获取所有的云电脑/云应用信息
WYResponse value = SyncRequest("enumConnections", NULL);
printf("WYEnumerateConnectInfo info %s\n", value.content);
FreeResponse(value);
调用WYSyncRequest接口,参数为“enumConnections”。
获取结果value.content是一个JSON结构,
{
"connection" : "***",
"connectionPid" : 27324, //云电脑的进程
"partner" : "***",
"partnerApp" : "***",
"processId" : 8696,
"status" : "start" //状态值包含start和exit
}
获取设备的UUID
WYResponse value = SyncRequest("uuid", NULL);
printf("uuid is %s\n", value.content);
FreeResponse(value);
调用WYSyncRequest接口,参数为“uuid”。
获取SDK版本号
WYResponse value = SyncRequest("sdkVersion", NULL);
printf("version is %s\n", value.content);
FreeResponse(value);
调用WYSyncRequest接口,参数为"sdkVersion"。
唤出问题反馈面板
WYResponse value = WYSyncRequest("feedback", NULL);
FreeResponse(value);
调用WYSyncRequest接口,参数为"feedback"。
唤出版本升级面板
WYResponse value = WYSyncRequest("upgrade", NULL);
FreeResponse(value);
调用WYSyncRequest接口,参数为"upgrade"。
四、错误码列表
错误码 | 说明 |
1 | SDK初始化失败 |
2 | SDK配置没有无影服务的合作方的信息 |
100 | 打开Launcher失败 |
101 | Launcher初始化失败 |
200 | 获取通信service失败(需要杀进程/卸载SDK,重新加载) |
201 | 通信service中断(需要杀进程/卸载SDK,重新加载) |
202 | 创建通信service失败(需要杀进程/卸载SDK,重新加载) |
300 | 连接云电脑/云应用参数无效 |
301 | 连接云电脑/云应用失败 |