@iwae 救命
鸿蒙和cocos,目前是在不同的线程里,要互相调用的话,需要进行线程通信。目前是没有进行封装,实现的方式还是比较原始些,复杂些,后续我们会考虑优化封装。
首先鸿蒙的ts接口是跑在ARK上的,我们先定义为UI线程或者主线程,cocos是运行在worker上的,我们定义为cocos线程。
ark 调用 cocos的接口:
首先是从UI线程发消息通知COCOS线程:
works/cocos_worker.ts是在cocos线程里。
workPort.postMessage 这个地方就是代表着发送消息到cocos线程
例如在CocosVideoPlayer.ts里的
this.workPort?.postMessage("onVideoEvent", {
videoTag: this.videoInfo.viewTag as number,
videoEvent: EventType.PLAYING as EventType
} as param);
})
cocos线程需要监听,是在cocos_worker.ts里监听,类似:
case "onVideoEvent":
nativeVideo.onVideoEvent(JSON.stringify(msg.param));
break;
到了这个过程,其实就已经完成了从鸿蒙UI线程到COCOS线程,同一个线程的js引擎是一样的,全局的变量也是一样的,这个时候就可以有很多方案可以选择了。
比如:可以在游戏里,定义一个全局的变量,例如window.oh.test, 然后在cocos_worker.ts里进行调用。
目前这里的大部分实现的方式是引擎内部的,实际上是很麻烦的,走的流程是:
cocos_worker.ts ->c++ -> 游戏里
这里是通过NAPI来实现的,下面也大概说下流程:
c++里面注册一个函数给cocos_worker里进行调用
// 导出一个接口给cocos_worker.ts调用
exports["onVideoEvent"] = Napi::Function::New(env, napiOnVideoEvent);
调用cocos引擎的jsb.onVideoEvent,这里相当于是在C++里转到cocos的ts里:
se::Value onVideoEventVal;
ok = ohVal.toObject()->getProperty("onVideoEvent", &onVideoEventVal);
if (!ok || !onVideoEventVal.isObject() || !onVideoEventVal.toObject()->isFunction()) {
CC_LOG_ERROR("onVideoEvent not found");
return;
}
// Convert args to se::ValueArray
se::ValueArray seArgs;
seArgs.reserve(1);
seArgs.emplace_back(se::Value(info[0].As<Napi::String>().Utf8Value()));
ok = onVideoEventVal.toObject()->call(seArgs, ohVal.toObject());
if (!ok) {
CC_LOG_ERROR("Call oh.onEventEvent failed!");
}
引擎的ts处理:
window.oh.onVideoEvent = (args) => {
const data = JSON.parse(args);
videoPlayers.forEach((player) => {
if (player.index === data.videoTag) {
player.dispatchEvent(data.videoEvent, data.args);
}
});
};
cocos 调用 ark 的接口其实也是一样的,就是cocos线程上,postMessage给UI线程(ARK线程),这个地方是有封装接口的,所以在游戏里,可以直接使用window.oh.postMessage
例如videoplayer的实现:
pause () {
window.oh.postMessage('pauseVideo', this._videoIndex);
}
setVisible (visible) {
window.oh.postMessage('setVideoVisible', { tag: this._videoIndex, visible });
}
resume () {
window.oh.postMessage('resumeVideo', this._videoIndex);
}
ui线程的接收消息的地方是在index.ets里面:
case "startVideo": {
let index = this.videoIndexMap.get(msg.param as number) as number;
if(this.videoArray[index].duration){
this.videoArray[index].controller.start();
}else{
this.videoArray[index].isPreparedStart = true;
}
break;
}
case "pauseVideo": {
let index = this.videoIndexMap.get(msg.param as number) as number;
this.videoArray[index].controller.pause();
break;
}
case "stopVideo": {
let index = this.videoIndexMap.get(msg.param as number) as number;
this.videoArray[index].controller.stop();
break;
}
到了这里,其实就可以使用ark的接口了。
还有一种方式,可以调用ts的接口,就是在sys-ability-polyfill.ts里,定义全局接口,然后在游戏里直接调用。但是部分接口应该是有问题的,因为有些接口不一定是线程安全的,就相当于在一个线程里,调用另一个线程的环境。
在后面发布的2.4.14和3.8.5里,可以使用类似jsb.reflection.callStaticMethod的方法,可以在cocos里直接调用ark引擎的方法。可以参考实现
好像有点理解了,因为之前在观察鸿蒙的原生层是否有实现类似安卓原生层的“Cocos2dxJavascriptJavaBridge.evalString”这种去调用cocos层里的ts函数的接口,这里鸿蒙调cocos好像要在NapiHelper.cpp写接口,并且c++层也要有对应的实现才行
嗯,后续的版本会有类似的接口
本次OH报名队伍超过410只,后续大家可以继续讨论和优化,期待决赛相见!
咨询下鸿蒙报名方 可以扫码入群
有点奇怪:
手机系统版本号: OpenHarmony 4.1.7.605
目前我收到的华为手机无论怎么怎么切换 USB 连电脑,并没任何提示,我看开发者模式是默认有的
于是使用这个 IDE 准备模拟器调试下,没想到并没任何报错, 但是就是没运行起来,大家没有遇到过这种情况的吗?官方交流群好少人说话:
不支持模拟器,设备打开usb调试如果不行 换个数据线
DevEco Studio要下载5.0.0版本的,官网最新是5.0.1,识别不了收到的手机。
感谢,降级确实可以看到手机设备,不过 USB 连手机后电脑还是显示不了
嗯,默认是开了 USB 调试,数据线和手机都换了,线是ok的
可以下载这个版本试试:
下载中心 | 华为开发者联盟-HarmonyOS开发者官网,共建鸿蒙生态
另外,这个真机调试,每次这里运行到这一步,设备就会自动重启,安装不上,看不到什么效果,调试确实有点麻烦,不知道各位大佬都是怎么调试的呢?
这个是开发版还是手机?
请大家本周务必上传仓库
是手机,升级了最新的系统的手机,另外也尝试恢复出厂设置了,不怎么行
2.4.14 版本OpenHarmony 不支持脚本加密和MD5 Cache吗,构建面板中没有此选项,有大佬给建议可以如何加密混编吗



