【问题现象】
腾讯会议 SDK 暂未提供 Electron 版的 HarmonyOS 适配。运行在 HarmonyOS 上的 Electron 应用,应当如何集成腾讯会议功能?
【背景知识】


static Napi::Value AddJsCallback(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 1) { // 注册回调函数只有一个参数
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsFunction()) {
Napi::TypeError::New(env, "参数必须是函数").ThrowAsJavaScriptException();
return env.Undefined();
}
Napi::Function regJsCb = info[0].As<Napi::Function>();
WemeetSdkAdapter::CallBack addCb = NapiFunctionToStdFunc(regJsCb, env);
WemeetSdkAdapter::AddCallBack(addCb);
return env.Undefined();
}
static Napi::String GetSDKVersion(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string version = WemeetSdkAdapter::GetSDKVersion();
return Napi::String::New(env, version);
}
/** InitParam:
* std::string sdkId{};
* std::string sdkToken{};
* std::string dataPath{};
* std::string appName{};
* std::string appIcon{};
* std::string preferLanguage{};
*/
static Napi::Value InitWemeetSDK(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
size_t len = info.Length();
if (len != 6) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
for (size_t i = 0; i < len; i++) {
if (!info[i].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
}
InitParam initParam;
initParam.sdkId = info[0].As<Napi::String>().Utf8Value();
initParam.sdkToken = info[1].As<Napi::String>().Utf8Value();
initParam.dataPath = info[2].As<Napi::String>().Utf8Value();
initParam.appName = info[3].As<Napi::String>().Utf8Value();
initParam.appIcon = info[4].As<Napi::String>().Utf8Value();
initParam.preferLanguage = info[5].As<Napi::String>().Utf8Value();
InitWemeetSDKWorker* worker = new InitWemeetSDKWorker(env, initParam);
worker->Queue();
return worker->Promise();
}
static Napi::Value UninitWemeetSDK(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// params:{ force: true }
if (info.Length() != 1) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
std::string param = info[0].As<Napi::String>().Utf8Value();
UninitWemeetSDKWorker* worker = new UninitWemeetSDKWorker(env, param);
worker->Queue();
return worker->Promise();
}
static Napi::Value IsInitialized(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
IsInitializedWorker* worker = new IsInitializedWorker(env);
worker->Queue();
return worker->Promise();
}
static Napi::Value RefreshSDKToken(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 1) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsString()) {
Napi::TypeError::New(env, "参数必须是函数").ThrowAsJavaScriptException();
return env.Undefined();
}
std::string param = info[0].As<Napi::String>().Utf8Value();
int code = WemeetSdkAdapter::RefreshSDKToken(param);
return Napi::Number::New(env, code);
}
static Napi::Value IsAuthorized(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
IsAuthorizedWorker* worker = new IsAuthorizedWorker(env);
worker->Queue();
return worker->Promise();
}
static Napi::Value Login(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// params: ssoUrl
if (info.Length() != 1) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
std::string param = info[0].As<Napi::String>().Utf8Value();
LoginWorker* worker = new LoginWorker(env, param);
worker->Queue();
return worker->Promise();
}
static Napi::Value Logout(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
LogoutWorker* worker = new LogoutWorker(env);
worker->Queue();
return worker->Promise();
}
/** JoinParam:
* std::string meetingCode{};
* std::string userDisplayName{};
* std::string password{};
* std::string inviteUrl{};
* bool micOn{false};
* bool cameraOn{false};
* bool speakerOn{false};
* bool faceBeautyOn{false};
* std::string meetingWindowTitle{};
*/
static Napi::Value JoinMeeting(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 9) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
for (size_t i = 0; i < 4; i++) {
if (!info[i].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
}
for (size_t i = 4; i < 8; i++) {
if (!info[i].IsBoolean()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
}
if (!info[8].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
JoinParam joinParam;
joinParam.meetingCode = info[0].As<Napi::String>().Utf8Value();
joinParam.userDisplayName = info[1].As<Napi::String>().Utf8Value();
joinParam.password = info[2].As<Napi::String>().Utf8Value();
joinParam.inviteUrl = info[3].As<Napi::String>().Utf8Value();
joinParam.micOn = info[4].As<Napi::Boolean>().Value();
joinParam.cameraOn = info[5].As<Napi::Boolean>().Value();
joinParam.speakerOn = info[6].As<Napi::Boolean>().Value();
joinParam.faceBeautyOn = info[7].As<Napi::Boolean>().Value();
joinParam.meetingWindowTitle = info[8].As<Napi::String>().Utf8Value();
JoinMeetingWorker* worker = new JoinMeetingWorker(env, joinParam);
worker->Queue();
return worker->Promise();
}
/** int leave_meeting_type:
* 0、所有设备离开会议;
* 1、结束会议(结束会议,仅当前账户是会议主持人时,该参数才有效。当非主持人时,调用结束会议等同于所有设备离开会议);
* 2、仅当前设备离开会议 (当非多端入会场景时,调用仅当前设备离开会议等同于离开会议
*/
static Napi::Value LeaveMeeting(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 1) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
int type = info[0].As<Napi::Number>().Int32Value();
LeaveMeetingWorker* worker = new LeaveMeetingWorker(env, type);
worker->Queue();
return worker->Promise();
}
static Napi::String CollectLogFiles(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
size_t len = info.Length();
if (len != 2) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
for (size_t i = 0; i < len; i++) {
if (!info[i].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
}
std::string beginTime = info[0].As<Napi::String>().Utf8Value();
std::string endTime = info[1].As<Napi::String>().Utf8Value();
std::string filePaths = WemeetSdkAdapter::CollectLogFiles(beginTime, endTime);
return Napi::String::New(env, filePaths);
}
static Napi::Value EnableRingInvitationView(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 1) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsBoolean()) {
Napi::TypeError::New(env, "参数必须是函数").ThrowAsJavaScriptException();
return env.Undefined();
}
bool enable = info[0].As<Napi::Boolean>().Value();
WemeetSdkAdapter::EnableRingInvitationView(enable);
return env.Undefined();
}
static Napi::Value SetNeedShareCallback(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 2) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsBoolean() || !info[1].IsBoolean()) {
Napi::TypeError::New(env, "参数必须是函数").ThrowAsJavaScriptException();
return env.Undefined();
}
bool enable = info[0].As<Napi::Boolean>().Value();
bool show = info[1].As<Napi::Boolean>().Value();
WemeetSdkAdapter::EnableInviteCallback(enable, show);
return env.Undefined();
}
// 响应邀请的处理(入会、挂断)
static Napi::Value HandleRingInvitation(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 2) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsBoolean() || !info[1].IsString()) {
Napi::TypeError::New(env, "参数必须是函数").ThrowAsJavaScriptException();
return env.Undefined();
}
bool accept = info[0].As<Napi::Boolean>().Value();
std::string inviteId = info[1].As<Napi::String>().Utf8Value();
WemeetSdkAdapter::HandleRingInvitation(accept, inviteId);
return env.Undefined();
}
// 设置是否使用添加成员的回调, HarmonyOS暂不支持
static Napi::Value EnableInviteUsersCallback(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() != 2) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsBoolean() || !info[1].IsBoolean()) {
Napi::TypeError::New(env, "参数必须是函数").ThrowAsJavaScriptException();
return env.Undefined();
}
bool enable = info[0].As<Napi::Boolean>().Value();
bool show = info[1].As<Napi::Boolean>().Value();
WemeetSdkAdapter::EnableInviteUsersCallback(enable, show);
return env.Undefined();
}
/** 异步执行
* 添加人员操作,接入方可以邀请人加入预定会议、或邀请人员加入会议, HarmonyOS暂不支持
* string json_param格式:
{
"users": ["user1_id","user2_id","user3_id","user4_id"],
"user_type":2
}
*/
static Napi::Value AddUsersWithParam(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// params: json_param
if (info.Length() != 1) {
Napi::TypeError::New(env, "参数数目错误").ThrowAsJavaScriptException();
return env.Undefined();
}
if (!info[0].IsString()) {
Napi::TypeError::New(env, "参数类型错误").ThrowAsJavaScriptException();
return env.Undefined();
}
std::string param = info[0].As<Napi::String>().Utf8Value();
AddUsersWithParamWorker* worker = new AddUsersWithParamWorker(env, param);
worker->Queue();
return worker->Promise();
}
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "AddJsCallback"),
Napi::Function::New(env, AddJsCallback));
exports.Set(Napi::String::New(env, "TestCallFunc"),
Napi::Function::New(env, TestCallFunc));
exports.Set(Napi::String::New(env, "GetSDKVersion"),
Napi::Function::New(env, GetSDKVersion));
exports.Set(Napi::String::New(env, "InitWemeetSDK"),
Napi::Function::New(env, InitWemeetSDK));
exports.Set(Napi::String::New(env, "UninitWemeetSDK"),
Napi::Function::New(env, UninitWemeetSDK));
exports.Set(Napi::String::New(env, "IsInitialized"),
Napi::Function::New(env, IsInitialized));
exports.Set(Napi::String::New(env, "RefreshSDKToken"),
Napi::Function::New(env, RefreshSDKToken));
exports.Set(Napi::String::New(env, "Login"),
Napi::Function::New(env, Login));
exports.Set(Napi::String::New(env, "IsAuthorized"),
Napi::Function::New(env, IsAuthorized));
exports.Set(Napi::String::New(env, "Logout"),
Napi::Function::New(env, Logout));
exports.Set(Napi::String::New(env, "JoinMeeting"),
Napi::Function::New(env, JoinMeeting));
exports.Set(Napi::String::New(env, "LeaveMeeting"),
Napi::Function::New(env, LeaveMeeting));
exports.Set(Napi::String::New(env, "CollectLogFiles"),
Napi::Function::New(env, CollectLogFiles));
exports.Set(Napi::String::New(env, "EnableRingInvitationView"),
Napi::Function::New(env, EnableRingInvitationView));
exports.Set(Napi::String::New(env, "SetNeedShareCallback"),
Napi::Function::New(env, SetNeedShareCallback));
exports.Set(Napi::String::New(env, "HandleRingInvitation"),
Napi::Function::New(env, HandleRingInvitation));
exports.Set(Napi::String::New(env, "EnableInviteUsersCallback"),
Napi::Function::New(env, EnableInviteUsersCallback));
exports.Set(Napi::String::New(env, "AddUsersWithParam"),
Napi::Function::New(env, AddUsersWithParam));
return exports;
}
NODE_API_MODULE(wemeet_sdk, Init);#include "wemeetSdkAdapter.h"
#include <functional>
#include "aki/jsbind.h"
void WemeetSdkAdapter::AddCallBack(CallBack& addCb)
{
if (auto jsFunc = aki::JSBind::GetJSFunction("addCallBack")) {
jsFunc->Invoke<void>(addCb);
}
}
std::string WemeetSdkAdapter::GetSDKVersion()
{
if (auto getSdkVerFunc = aki::JSBind::GetJSFunction("getSDKVersion")) {
auto version = getSdkVerFunc->Invoke<std::string>();
return version;
}
return "";
}
// SDK初始化 - 异步接口
int WemeetSdkAdapter::InitWemeetSDK(InitParam initParam)
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("initWemeetSDK")) {
jsFunc->Invoke<void>(initParam, callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// SDK反初始化 - 异步接口
int WemeetSdkAdapter::UninitWemeetSDK(std::string param)
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("uninitWemeetSDK")) {
jsFunc->Invoke<void>(param, callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// SDK是否初始化 - 异步接口
int WemeetSdkAdapter::IsInitialized()
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("isInitialized")) {
jsFunc->Invoke<void>(callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// 刷新SDK token信息 - 同步接口
int WemeetSdkAdapter::RefreshSDKToken(std::string param)
{
if (auto refreshSDKTokenFunc = aki::JSBind::GetJSFunction("refreshSDKToken")) {
auto code = refreshSDKTokenFunc->Invoke<int>(param);
return code;
}
return -1;
}
// 异步登录
int WemeetSdkAdapter::Login(std::string param)
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("login")) {
jsFunc->Invoke<void>(param, callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// 异步退出
int WemeetSdkAdapter::Logout()
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("logout")) {
jsFunc->Invoke<void>(callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// 异步获取是否已登录(已授权)
int WemeetSdkAdapter::IsAuthorized()
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("isAuthorized")) {
jsFunc->Invoke<void>(callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// 异步加入会议
int WemeetSdkAdapter::JoinMeeting(JoinParam joinParam)
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("joinMeeting")) {
jsFunc->Invoke<void>(joinParam, callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// 异步离开会议
int WemeetSdkAdapter::LeaveMeeting(int type)
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("leaveMeeting")) {
jsFunc->Invoke<void>(type, callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}
// 同步获取会议日志文件路径的列表
std::string WemeetSdkAdapter::CollectLogFiles(std::string beginTime, std::string endTime)
{
if (auto jsFunc = aki::JSBind::GetJSFunction("collectLogFiles")) {
auto filePath = jsFunc->Invoke<std::string>(beginTime, endTime);
return filePath;
}
return "";
}
// 同步设置是否显示SDK的响铃邀请界面
void WemeetSdkAdapter::EnableRingInvitationView(bool enable)
{
if (auto jsFunc = aki::JSBind::GetJSFunction("enableRingInvitationView")) {
jsFunc->Invoke<void>(enable);
}
}
// 同步设置是否使用邀请回调,如果使用,点击会议中界面下方工具栏上的邀请按钮,会触发`InMeetingCallback.onInviteMeeting`回调,并回调会议信息
void WemeetSdkAdapter::EnableInviteCallback(bool enable, bool show)
{
if (auto jsFunc = aki::JSBind::GetJSFunction("enableInviteCallback")) {
jsFunc->Invoke<void>(enable, show);
}
}
// 同步处理响铃邀请
void WemeetSdkAdapter::HandleRingInvitation(bool accept, std::string inviteId)
{
if (auto jsFunc = aki::JSBind::GetJSFunction("handleRingInvitation")) {
jsFunc->Invoke<void>(accept, inviteId);
}
}
// 同步设置是否使用添加成员的回调
void WemeetSdkAdapter::EnableInviteUsersCallback(bool enable, bool show)
{
if (auto jsFunc = aki::JSBind::GetJSFunction("enableInviteUsersCallback")) {
jsFunc->Invoke<void>(enable, show);
}
}
// 异步添加人员操作,接入方可以邀请人加入预定会议
int WemeetSdkAdapter::AddUsersWithParam(std::string param)
{
std::promise<int> promise;
std::function<void(int)> callback =
[&promise](int code) {
promise.set_value(code);
};
if (auto jsFunc = aki::JSBind::GetJSFunction("addUsersWithParam")) {
jsFunc->Invoke<void>(param, callback);
} else {
int errcode(0);
promise.set_value(errcode);
}
auto future = promise.get_future();
return future.get();
}InitWemeetSDK接口参数使用了InitParam结构体,JoinMeeting接口参数使用了JoinParam结构体,需要声明InitParam和JoinMeeting结构体并使用aki绑定类/结构体并绑定类成员属性。代码片段如下:
JSBIND_CLASS(InitParam) {
JSBIND_PROPERTY(sdkId);
JSBIND_PROPERTY(sdkToken);
JSBIND_PROPERTY(dataPath);
JSBIND_PROPERTY(appName);
JSBIND_PROPERTY(appIcon);
JSBIND_PROPERTY(preferLanguage);
}
JSBIND_CLASS(JoinParam) {
JSBIND_PROPERTY(meetingCode);
JSBIND_PROPERTY(userDisplayName);
JSBIND_PROPERTY(password);
JSBIND_PROPERTY(inviteUrl);
JSBIND_PROPERTY(micOn);
JSBIND_PROPERTY(cameraOn);
JSBIND_PROPERTY(speakerOn);
JSBIND_PROPERTY(faceBeautyOn);
JSBIND_PROPERTY(meetingWindowTitle);
}static bind() {
hilog.info(0x0000, TAG, `-----------JSBind start--------------`);
if (WeMeetSdkJsBindingEts.currentContext === undefined) {
WeMeetSdkJsBindingEts.currentContext = wemeet_sdk_adapter.getNativeContext();
}
// 绑定相关函数
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("addCallBack", WeMeetSdkJsBindingEts.addCallBack);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("getSDKVersion", WeMeetSdkJsBindingEts.getSDKVersion);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("initWemeetSDK", WeMeetSdkJsBindingEts.initWemeetSDK);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("uninitWemeetSDK", WeMeetSdkJsBindingEts.uninitWemeetSDK);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("isInitialized", WeMeetSdkJsBindingEts.isInitialized);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("refreshSDKToken", WeMeetSdkJsBindingEts.refreshSDKToken);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("login", WeMeetSdkJsBindingEts.login);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("logout", WeMeetSdkJsBindingEts.logout);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("isAuthorized", WeMeetSdkJsBindingEts.isAuthorized);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("joinMeeting", WeMeetSdkJsBindingEts.joinMeeting);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("leaveMeeting", WeMeetSdkJsBindingEts.leaveMeeting);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("collectLogFiles", WeMeetSdkJsBindingEts.collectLogFiles);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("enableRingInvitationView", WeMeetSdkJsBindingEts.enableRingInvitationView);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("enableInviteCallback", WeMeetSdkJsBindingEts.enableInviteCallback);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("handleRingInvitation", WeMeetSdkJsBindingEts.handleRingInvitation);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("enableInviteUsersCallback", WeMeetSdkJsBindingEts.enableInviteUsersCallback);
WeMeetSdkJsBindingEts.currentContext.JSBind.bindFunction("addUsersWithParam", WeMeetSdkJsBindingEts.addUsersWithParam);
}addCallBack接口实现中需要保存onCallback参数,在其他接口如initWemeetSDK完成后通过onCallback通知调用方:
// addCallBack 添加注册函数
static addCallBack(onCallback: JsonCallback): void {
hilog.info(0x0000, TAG, `-----------addCallBack start--------------`);
TMMeetingSDK.g_callBack = onCallback;
} onCallback中回调参数为json字符串,格式如下 :

通过如下方法封装回调参数并回调到Electron Js侧:
// msg should be normal string, param should be json string
static processCallbackMsg(
func: string,
service: string,
code: number,
json: boolean,
msg: string,
param: string
): void {
// 1. 创建基础JSON对象
const jsonObj: CallbackMsg = {
func: func,
service: service
};
// 2. 处理code和msg(仅当code非0或msg非空时添加)
if (code !== 0 || msg !== '') {
jsonObj.code = code.toString(); // 转为字符串
// 判断msg是否为JSON格式,决定是否带引号
if (TMMeetingSDK.judgeMsgJson(msg)) {
// 如果是JSON字符串,先解析为对象再赋值(避免JSON.stringify二次转义)
jsonObj.msg = JSON.parse(msg) as object;
} else {
jsonObj.msg = msg;
}
}
// 3. 处理param(非空时添加)
if (param !== '') {
// param直接作为JSON值(不添加引号)
jsonObj.param = JSON.parse(param) as object;
}
// 4. 转换为JSON字符串
const jsonStr = JSON.stringify(jsonObj);
TMMeetingSDK.triggerCallback(jsonStr);
}以initWemeetSDK接口回调为例(其他接口代码可在),按如下方式回调初始话结果到js侧:
// SDK初始化
static initialize(initParam: InitParamIn): void {
let uiContext: common.UIAbilityContext | undefined = TMMeetingSDK.getUIContext();
TMSDK.initialize(uiContext, initParam, new MyCallback());
}
onSDKInitializeResult(code: number, msg: string): object| void {
hilog.info(0x0000, TAG, `SDKInitialize result code: ${code}, msg : ${msg}`);
TMMeetingSDK.processCallbackMsg("OnSDKInitializeResult", "CommonService", code, false, msg, "");
}Navigation改造:
腾讯会议HarmonyOS SDK接入指导路由使用说明推荐使用Navigation实现路由跳转。当前HarmonyOS生态提供的Electron构建包模板工程中暂未支持Navigation跳转,需要对模板工程进行改造。在electron/src/main/ets 下新建EntryPage.ets页面:
import { Index } from "./Index";
import { NodeHandleWindow } from "./NodeHandleWindow";
let storage = LocalStorage.getShared();
@Entry(storage)
@Component
export struct EntryPage {
@State isSupportNodeHandleFeature:boolean = false;
aboutToAppear(): void {
let isTMWindow:boolean = AppStorage.get('isTMWindow') as boolean
if (isTMWindow) {
AppStorage.setOrCreate('PathStack', this.pathStack);
AppStorage.setOrCreate('isTMWindow',false);
}
this.isSupportNodeHandleFeature = AppStorage.get('isSupportNodeHandleFeature') as boolean;
}
private pathStack: NavPathStack = new NavPathStack()
build() {
Navigation(this.pathStack) {
if(this.isSupportNodeHandleFeature) {
NodeHandleWindow()
} else {
Index()
}
}
.width('100%')
.height('100%')
.hideToolBar(true)
.hideTitleBar(true)
.mode(NavigationMode.Stack)
}
}在electron\src\main\resources\base\profile\main_pages.json中添加
"pages/EntryPage",修改web_engine\src\main\ets\ability\WebBaseAbility.ets中protected getContentPath(): string { ... }整体替换成
protected getContentPath(): string {
AppStorage.setOrCreate('isSupportNodeHandleFeature', this.nativeContext.IsSupportNodeHandleFeature());
return 'pages/EntryPage';
}const addon = require('wemeet_sdk.node');
addon.AddJsCallback((msg)=>{
const obj = JSON.parse(msg);
console.log(Tag, "收到回调:", msg);
//初始化
if(obj.func === 'OnSDKInitializeResult') {
console.log(Tag,"OnSDKInitializeResult,code:",obj.code,"msg:",obj.msg);
return;
}
});
const addon = require('wemeet_sdk.node');
addon.AddJsCallback((msg)=>{
const obj = JSON.parse(msg);
console.log(Tag, "收到回调:", msg);
//初始化
if(obj.func === 'OnSDKInitializeResult') {
console.log(Tag,"OnSDKInitializeResult,code:",obj.code,"msg:",obj.msg);
return;
}
});
addon.InitWemeetSDK("sdkId","sdkToken", "logPath", "测试应用", "iconPath", 'zh-cn')x关键问题
1.问题现象:集成中遇到CPPCrash,Signal:SIGSEGV(SEGV_MAPERR)@0x0000000000000590 probably caused by NULL pointer dereference

问题原因:libelectron.so依赖的libc++_shared.so和腾讯会议libwemeet_platform.so依赖的libc++_shared.so是不同LLVM版本工具编译的,存在冲突。
解决方案: 构建libelectron.so时采用静态链接libc++_static.a的方式,解耦libelectron.so对libc++_shared.so的动态依赖,可使用electron 34.8.4及以上版本,libelectron.so是采用静态链接libc++_static.a的。在编译libwemeet_sdk_adapter.so时修改为静态链接libc++_static.a,在/adapter/CMakeLists.txt中增加如下配置:
# 静态链接libc++_static.a
target_link_options(${TARGETFILENAME} PRIVATE -nostdlib++)
target_link_options(${TARGETFILENAME} PRIVATE ${OHOS_SDK_PATH}/openharmony/native/llvm/lib/aarch64-unknown-linux-ohos/libc++_static.a)代码附件
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。