A
Air官方
【Air 系列 · 鸿蒙 PC 适配全记录】14 / 56
■ 应用:轻引擎(from Godot)(AirForge)
■ 定位:开源游戏引擎编辑器(Godot)
■ 上游:Godot Engine | 路线:引擎直连 EGL | 版本:1.0.0
■ 市场状态:开发中,即将上架
■ 官网(免费下载): https://www.shunidc.cn/
————————————————————
开源鸿蒙 PC 社区: https://harmonypc.csdn.net/
PC 社区项目申请: https://atomgit.com/OpenHarmonyPCDeveloper
适配开源地址:(AtomGit 仓库建立后回填)
环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743
▍一、为什么要适配轻引擎
Godot Engine 是当前最主流的开源游戏引擎之一,以 MIT 协议发布,编辑器与游戏运行时一体,2D 与 3D 全覆盖。游戏引擎是桌面软件里对图形、输入、音频、进程模型要求最全面的一类:它既是生产力工具(编辑器本身是一个复杂的 GUI 应用),又是运行时环境(游戏实例需要独立的渲染与音频通路)。把 Godot 带到鸿蒙,意味着图形栈、多进程 Ability 模型与输入系统同时接受一套完整的检验,其产出的平台层也能反过来服务所有基于 Godot 的游戏移植。
轻引擎(工程名 AirForge)的目标是把 Godot Engine 4.7.2-stable 完整移植到鸿蒙:编辑器、项目管理器与游戏运行时。应用版本 1.0.0,包名 com.airforge.app,deviceTypes 覆盖 tablet、2in1 与 phone。路线选择是"引擎直连"——不用容器、不做转译,参照 AirModel/Blender 的 GHOST-OHOS 先例与上游 Android 平台层,为 Godot 新建一个 platform/ohos 平台层,让引擎以 EGL 加 GLES3 直接面对鸿蒙的窗口表面。渲染后端选 gl_compatibility 并关闭 Vulkan,音频走 OHAudio,源码以浅克隆保存在 native/sources/godot。
需要如实定位的是:这是一个处于早期阶段但已打通关键链路的工程。PORTING.md 的验收标准对照表(S1 至 S14)尚全部未打勾,主力验证设备为 Mate 60 Pro(2720×1260 横屏),MatePad Mini 为回归机。截至 2026-09-25 的会话记录,项目管理器到编辑器的打开链已在真机完成闭环,全功能交付仍在逐项推进。
▍二、先划清边界:不把编译通过当成适配完成
Godot 桌面版运行在 X11/Wayland 或 Windows 的 DisplayServer 之上,Android 版则有成熟的 Java Activity 加 JNI 平台层。鸿蒙侧两者都不能直接复用:ArkUI 的 XComponent 表面需要引擎自己的 EGL 初始化,Android 的 GestureDetector 与双 Activity 约定需要等价的鸿蒙实现。工程把边界划在"平台层是否完整"上——SCons 能编出 so 只说明代码生成链路可用,引擎能不能创建窗口、收到输入、隔离进程,才是平台层是否成立的验收点。
层次 原项目实现(Godot 桌面/Android 版) 鸿蒙侧当前方案
应用入口 桌面单进程;Android 双 Activity EntryAbility(编辑器/项目管理器)+ GameAbility(:game 进程)双 Ability
窗口表面 X11/Wayland/Android Surface DisplayServer_OHOS + XComponent(SURFACE),EGLManager 子类化
渲染后端 Vulkan/Forward+、GLES3 gl_compatibility(EGL + GLES3),Vulkan 编译关闭
输入管线 Android GestureDetector 经 JNI 打标 OH_NativeXComponent 回调 → OHOSInputHandler → Input 缓冲
双击检测 Java GestureDetector 完成 ohos_input_handler.cpp 自建(350ms 窗口 + 100px slop)
音频 各平台音频驱动 OHAudio AudioDriver 拉流回调(libohaudio.so)
文件对话框 各平台原生对话框 FEATURE_NATIVE_DIALOG_FILE 声明,走上游内建路径接系统 Picker
进程模型 桌面单进程多窗口 项目管理器与游戏实例进程隔离,restartApp 全进程重启兜底
这条边界的当前含义是:已经上屏的是项目管理器与编辑器的窗口、输入与打开链骨架,引擎的完整编辑功能、游戏运行时验收与性能口径仍在 S1 至 S14 的逐项对照中推进,工程不把未打勾项表述为已交付。
▍三、鸿蒙版的整体架构
ArkTS 壳只有四个 ets 文件、约 1200 行,职责被刻意压缩到最薄:EntryAbility 承载编辑器与项目管理器,GameAbility 以 process=":game" 在独立进程运行游戏实例,Index.ets 铺满一个 SURFACE 型 XComponent 并提供选择器、剪贴板、分享、IME 与软键盘桥。薄 NAPI 桥只链系统库,运行期 dlopen libgodot_ohos.so 并 dlsym OHOS_Godot_* 符号进入引擎。
text
ArkTS 壳(entry/src/main/ets)
EntryAbility(编辑器/项目管理器) GameAbility(process=":game",进程隔离)
│ XComponent(SURFACE, id=airforge_canvas) 铺满
▼ 薄 NAPI 桥 libentry.so(dlopen + dlsym OHOS_Godot_*)
libgodot_ohos.so(SCons 交叉编译全量引擎,entry/libs/arm64-v8a 打包通道)
platform/ohos/:OS_OHOS : OS_Unix;DisplayServer_OHOS(EGLManager 子类)
引擎线程:Main::setup → 等 surface → setup2 → start
→ 循环 { process_events; Main::iteration; swap }
native_vsync 帧泵;输入 = XComponent 回调(UI线程) → OHOSInputHandler → Input 缓冲
音频 = AudioDriver_OHAudio 拉流回调
主要目录如下:
text
AirForge/
├── AppScope/app.json5 # 包名 com.airforge.app、版本 1.0.0
├── PORTING.md # 移植手册:架构/依赖/补丁/风险/验收对照
├── env.sh # 设备与路径环境变量(含回归机配置)
├── ai_log/ # 按日期分文件的移植会话日志
├── scripts/
│ ├── build_engine.sh # SCons 交叉编译引擎并拷入打包通道
│ └── deploy.sh # 构建部署脚本
├── native/
│ ├── patches/ohos-platform/ # 平台层补丁与上游整合补丁
│ └── sources/godot/ # Godot 4.7.2 源码(浅克隆)
└── entry/src/main/
├── cpp/napi_init.cpp # 薄 NAPI 桥与 TSFN 通道
└── ets/
├── entryability/EntryAbility.ets # 编辑器/项目管理器宿主
├── gameability/GameAbility.ets # 游戏实例宿主(:game 进程)
└── pages/Index.ets # XComponent 宿主与引擎控制
▍四、核心适配过程
### 1. platform/ohos 平台层从零新建
这是 P 系列补丁的主体:detect.py 与 SCsub 把 ohos 注册为 SCons 平台,os_ohos 实现 OS_OHOS : OS_Unix,display_server_ohos 以 drivers/egl/egl_manager.cpp 子类的方式接入 EGL 初始化与交换链,ohos_input_handler 承接 XComponent 的 UI 线程触摸回调并写入引擎 Input 缓冲,audio_driver_ohos 以拉流回调对接 OHAudio,godot_ohos 作为引擎入口把 Main::setup 的启动序列拆成"等 surface 再 setup2"两段。整套平台层以 OHOS_ENABLED 守卫或独立新文件形式存在,不污染上游通用路径。
### 2. SCons 交叉编译与体积收敛
构建命令是 scons platform=ohos target=editor arch=arm64 production=yes optimize=size debug_symbols=no vulkan=no opengl3=yes,musl 与 glibc 的线程差异(sysinfo、execinfo/backtrace、pthread_cancel)以 P2 补丁在构建期逐个暴露并收口。体积控制沿用 AirModel 的收敛定式:production 加 optimize=size 加 version-script 符号白名单,libgodot_ohos.so 从 137.9MB 收到 109MB。依赖矩阵极短:只直链 libEGL、libGLESv3、libohaudio、libhilog_ndk 四个 NDK 系统库,加随 HAP 分发的 libc++_shared.so,其余 zlib/png 等全用 Godot thirdparty 内置,无任何宿主可执行工具依赖。
### 3. 双 Ability 进程模型
编辑器内"运行项目"对应上游 Android 的双 Activity 设计:OS_OHOS::create_instance 经 NAPI 桥 TSFN 通知 ArkTS 层 startAbility(GameAbility),游戏在 :game 独立进程运行,GameAbility 退出即进程自毁、全局态零残留。这条链上踩出了两个手册级教训:GameAbility 的 exported 必须为 true,否则应用内 startAbility 的可见性校验失败时 AMS 不报错、静默改拉 EntryAbility;而"同进程引擎二启"不可行——Main::cleanup 清理进程级注册表后静态 once-guard 未复位,二启在 ProjectSettings 阶段即 SIGSEGV。手机形态的进程字段一度记录为被静默忽略,后续实测确认 :game 进程真实生效(跑满 272 秒),代码注释中保留了这一翻案证据;ApplicationContext.restartApp 全进程重启(pending_open.json 传参)保留为形态兼容兜底。
### 4. 输入与系统能力接线
输入链是 XComponent 回调进 OHOSInputHandler,再写引擎 Input 缓冲,触控与鼠标按源分流并防双发。双击语义是重点修复项:引擎核心只透传 is_double_tap 标志,检测责任在平台层——Android 侧由 GestureDetector 完成,OHOS 平台层此前的实现从未检测,导致项目管理器行双击打开与编辑器所有双击语义全部失效;修法是在 ACTION_DOWN 自建 350ms 窗口加 100px slop 判定并支持三连击重新配对。手写笔按 force 转 pressure、tiltX/Y 转 tilt 注入,捏合走轴事件转 MagnifyGesture,光标经 dlopen libohinput 调 OH_Input_SetPointerStyle 并以 2 秒心跳重申。文件对话框走的是上游内建路径:声明 FEATURE_NATIVE_DIALOG_FILE 后,引擎 FileDialog 自动落到 DisplayServer::file_dialog_show,桥接系统 DocumentViewPicker,此环节零补丁达成。汉化将上游 zh_Hans.po 编进二进制并预设 editor_language=zh_CN。
### 5. 引擎线程与帧泵
重型初始化全部在引擎线程完成,ArkTS 主线程零阻塞,配合双看门狗纪律规避启动 appfreeze(风险 R7)。帧泵用 native_vsync 帧回调驱动引擎循环,避免低功耗模式下忙转;swap interval 取 1(FIFO)防满速 present(风险 R3,Maleoon GPU 的 GLES3 兼容性先以三角形级验证过 EGL 通路)。入口侧还处理了 libentry.so 双实例问题:XComponent 的 libraryname 加载与 ETS import 会各 dlopen 一份,static 状态全部双份,最终以 PID 级 marker 文件加 AppStorage 双保险阻止退出后的"项目管理器幽灵回归"。
▍五、适配中遇到的几个难点
### 难点1:exported 缺失导致的静默回退
GameAbility 的 exported 配置为 false 时,应用内 startAbility 的可见性校验失败,AMS 不报任何错误,静默 spawn 默认的 EntryAbility——每次"打开工程"实际是新开一个项目管理器。shell 侧 aa start -a GameAbility 报 10103001 visibility 错误才定位到根因。教训已写入移植手册:多 Ability 架构的应用内启动同样受 exported 约束,失败形态是静默回退而非报错。
### 难点2:双击检测的平台层缺位
项目管理器双击行打不开工程、编辑器双击语义全灭,但信号链探针显示 wiring 完好。逐层核查后确认:引擎触摸到鼠标的合成只透传 is_double_tap() 布尔值,双击时间窗与位移阈值的判定责任完全在平台层,Android 由 Java GestureDetector 打标,OHOS 平台层从未实现。在 ohos_input_handler.cpp 按 350ms 窗口加 100px slop 自建判定后,注入双击稳定触发打开信号。
### 难点3:半成品二进制制造的三块"假铁证"
一轮排查中"信号不到处理器"的三条证据链,最终全部翻案:所依赖的 so 是上会话中途取消的 scons 半成品,部分 .o 新部分旧;所谓"打开按钮矩形"实为重命名按钮(OCR 加像素定案);"信号零触发"是旧二进制与点错按钮的叠加假象。另一个叠加问题是构建脚本用错产物名——scons 产物带全后缀 libgodot_ohos.ohos.editor.arm64.so,脚本按短名拷贝必然失败且 exit code 被 | tail 吃掉,此前部署的一直是旧 so。结论进入方法学:部署验证用的 so 必须来自完整收敛的构建,产物时间戳要晚于最后一次源码修改。
### 难点4:跨语言边界的两个静默陷阱
ArkTS 数组跨 NAPI 边界后不是 JS Array(napi_typeof 返回 object、napi_is_array 为 false),set_engine_args 静默丢参——项目管理器模式下参数恰好为空数组,缺陷从未暴露,直到编辑器模式需要传 --path。修法是 d.ts 改为 JSON 字符串、napi 侧做逐 token 解析。另一个是状态隔离:UIAbility 里 AppStorage 的 setOrCreate 与 @Entry 页面的 AppStorage 是隔离实例,ability 写入后页面读到的仍是空。两个问题都不报错,只能靠埋点往返验证发现,最终分别以 JSON 通道与 pending_open.json 文件通道解决。
### 难点5:退出与重启的流转设计
项目管理器与编辑器互相拉起、退出回归的流转经过四代演进:直接 startAbility 回 PM 会留下双实例;同进程二启崩溃;restartApp 全进程重启(API 12+,需获焦)配合 pending_open.json 与 want 参数镜像,构成干净进程链。配套的防重入设计包括 ENGINE_EXITED 分支的 restartingApp 防竞争标志,以及退出时先 startAbility 回 EntryAbility 再 terminateSelf 的顺序约束。
▍六、编译、安装与启动
构建分引擎与 HAP 两段,先在仓库根目录 source 环境脚本,再交叉编译引擎并把产物拷入打包通道:
bash
source env.sh
cd $GODOT_SRC && scons platform=ohos target=editor arch=arm64 production=yes \
optimize=size debug_symbols=no vulkan=no opengl3=yes -j$(sysctl -n hw.ncpu)
cp $GODOT_BIN/libgodot_ohos.ohos.editor.arm64.so $GODOT_LIBS_CHANNEL/
随后打包 HAP(PORTING 记录用 devecocli build,等价的 hvigor 命令如下):
bash
export JAVA_HOME=/Applications/DevEco-Studio.app/Contents/jbr/Contents/Home
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
hvigorw --mode module -p module=entry assembleHap --no-daemon
产物位于 entry/build/default/outputs/default/entry-default-signed.hap。安装与启动(更换引擎 so 后必须 force-stop 换进程验证,避免旧进程残留):
bash
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa force-stop com.airforge.app
hdc shell aa start -a EntryAbility -b com.airforge.app
▍七、当前功能边界
按 PORTING.md 与 2026-09-25 会话日志的记录,当前阶段已在 Mate 60 Pro 真机实证的能力:
- 项目管理器上屏与工程列表,行双击打开工程(350ms 双击窗口);
- 打开链完整闭环:PM 双击行 → 启动 GameAbility(:game 独立进程)或 restartApp 通道 → 编辑器以 --path demo --editor 全屏上屏(2720×1260 沉浸式,底部死黑已修)→ BACK 干净退出 → PM 回归无幽灵实例;
- 引擎直连渲染:gl_compatibility(EGL + GLES3)在实机 GPU 上完成从三角形级验证到编辑器全屏渲染;
- OHOS 平台层:OS_OHOS、DisplayServer_OHOS、OHOSInputHandler、AudioDriver_OHAudio 与引擎入口;
- 文件对话框经上游内建 FEATURE_NATIVE_DIALOG_FILE 路径接系统 Picker;
- 汉化资源(zh_Hans 编进二进制)与菜单、输入、光标等系统能力的实现落点已就位。
尚未完成或明确登记为遗留的能力:S1 至 S14 验收标准尚未逐项打勾,编辑、运行、剪贴板双向、分享与碰一碰、暗黑主题、新建项目模板、性能口径均属待验收;Mate60Pro 上 PM 侧栏打开按钮的有效区与系统手势保留区完全重叠(右缘死区),当前以行双击加 Ctrl+E 作为主打开路径,真机手指可达性待验证,彻底方案为 XComponent 右缘避让(影响全局坐标,暂缓);PM 首次双击前需先选中行的交互约束;MatePad Mini 回归未跑;编辑器模式此轮记录过一处 ArkUI 渲染层的 SIGSEGV 待观察。
因此,当前版本更准确的定位是"Godot 鸿蒙移植的基础骨架加已验证的关键链路":平台层与进程模型已经成立,项目管理器到编辑器的真实闭环可以在真机复现,交付级的功能完备度仍以验收对照表的逐项打勾为准。
▍八、总结
轻引擎的移植选择了四条路线里工程量最大的一条:不套壳、不转译,为 Godot 新建 platform/ohos 平台层,让引擎以 EGL 加 GLES3 直接面对鸿蒙表面。这一选择的回报是架构上的对齐——双 Ability 对应上游双 Activity,restartApp 通道对应进程生命周期,未来基于 Godot 的游戏移植可以直接继承这套平台层。会话日志里沉淀的静默回退、半成品二进制、跨语言边界静默丢参等教训,也都超出了单一工程的适用范围。
后续工作的重心由验收对照表决定:把 S1 至 S14 逐项实证打勾,先补齐编辑器触控与手写笔输入的回归,再处理右缘死区的避让方案与 MatePad Mini 回归,最后落性能口径。每一步继续坚持会话日志的口径:结论必须同时有代码链路证据与真机行为证据。
■ 应用:轻引擎(from Godot)(AirForge)
■ 定位:开源游戏引擎编辑器(Godot)
■ 上游:Godot Engine | 路线:引擎直连 EGL | 版本:1.0.0
■ 市场状态:开发中,即将上架
■ 官网(免费下载): https://www.shunidc.cn/
————————————————————
开源鸿蒙 PC 社区: https://harmonypc.csdn.net/
PC 社区项目申请: https://atomgit.com/OpenHarmonyPCDeveloper
适配开源地址:(AtomGit 仓库建立后回填)
环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743
▍一、为什么要适配轻引擎
Godot Engine 是当前最主流的开源游戏引擎之一,以 MIT 协议发布,编辑器与游戏运行时一体,2D 与 3D 全覆盖。游戏引擎是桌面软件里对图形、输入、音频、进程模型要求最全面的一类:它既是生产力工具(编辑器本身是一个复杂的 GUI 应用),又是运行时环境(游戏实例需要独立的渲染与音频通路)。把 Godot 带到鸿蒙,意味着图形栈、多进程 Ability 模型与输入系统同时接受一套完整的检验,其产出的平台层也能反过来服务所有基于 Godot 的游戏移植。
轻引擎(工程名 AirForge)的目标是把 Godot Engine 4.7.2-stable 完整移植到鸿蒙:编辑器、项目管理器与游戏运行时。应用版本 1.0.0,包名 com.airforge.app,deviceTypes 覆盖 tablet、2in1 与 phone。路线选择是"引擎直连"——不用容器、不做转译,参照 AirModel/Blender 的 GHOST-OHOS 先例与上游 Android 平台层,为 Godot 新建一个 platform/ohos 平台层,让引擎以 EGL 加 GLES3 直接面对鸿蒙的窗口表面。渲染后端选 gl_compatibility 并关闭 Vulkan,音频走 OHAudio,源码以浅克隆保存在 native/sources/godot。
需要如实定位的是:这是一个处于早期阶段但已打通关键链路的工程。PORTING.md 的验收标准对照表(S1 至 S14)尚全部未打勾,主力验证设备为 Mate 60 Pro(2720×1260 横屏),MatePad Mini 为回归机。截至 2026-09-25 的会话记录,项目管理器到编辑器的打开链已在真机完成闭环,全功能交付仍在逐项推进。
▍二、先划清边界:不把编译通过当成适配完成
Godot 桌面版运行在 X11/Wayland 或 Windows 的 DisplayServer 之上,Android 版则有成熟的 Java Activity 加 JNI 平台层。鸿蒙侧两者都不能直接复用:ArkUI 的 XComponent 表面需要引擎自己的 EGL 初始化,Android 的 GestureDetector 与双 Activity 约定需要等价的鸿蒙实现。工程把边界划在"平台层是否完整"上——SCons 能编出 so 只说明代码生成链路可用,引擎能不能创建窗口、收到输入、隔离进程,才是平台层是否成立的验收点。
层次 原项目实现(Godot 桌面/Android 版) 鸿蒙侧当前方案
应用入口 桌面单进程;Android 双 Activity EntryAbility(编辑器/项目管理器)+ GameAbility(:game 进程)双 Ability
窗口表面 X11/Wayland/Android Surface DisplayServer_OHOS + XComponent(SURFACE),EGLManager 子类化
渲染后端 Vulkan/Forward+、GLES3 gl_compatibility(EGL + GLES3),Vulkan 编译关闭
输入管线 Android GestureDetector 经 JNI 打标 OH_NativeXComponent 回调 → OHOSInputHandler → Input 缓冲
双击检测 Java GestureDetector 完成 ohos_input_handler.cpp 自建(350ms 窗口 + 100px slop)
音频 各平台音频驱动 OHAudio AudioDriver 拉流回调(libohaudio.so)
文件对话框 各平台原生对话框 FEATURE_NATIVE_DIALOG_FILE 声明,走上游内建路径接系统 Picker
进程模型 桌面单进程多窗口 项目管理器与游戏实例进程隔离,restartApp 全进程重启兜底
这条边界的当前含义是:已经上屏的是项目管理器与编辑器的窗口、输入与打开链骨架,引擎的完整编辑功能、游戏运行时验收与性能口径仍在 S1 至 S14 的逐项对照中推进,工程不把未打勾项表述为已交付。
▍三、鸿蒙版的整体架构
ArkTS 壳只有四个 ets 文件、约 1200 行,职责被刻意压缩到最薄:EntryAbility 承载编辑器与项目管理器,GameAbility 以 process=":game" 在独立进程运行游戏实例,Index.ets 铺满一个 SURFACE 型 XComponent 并提供选择器、剪贴板、分享、IME 与软键盘桥。薄 NAPI 桥只链系统库,运行期 dlopen libgodot_ohos.so 并 dlsym OHOS_Godot_* 符号进入引擎。
text
ArkTS 壳(entry/src/main/ets)
EntryAbility(编辑器/项目管理器) GameAbility(process=":game",进程隔离)
│ XComponent(SURFACE, id=airforge_canvas) 铺满
▼ 薄 NAPI 桥 libentry.so(dlopen + dlsym OHOS_Godot_*)
libgodot_ohos.so(SCons 交叉编译全量引擎,entry/libs/arm64-v8a 打包通道)
platform/ohos/:OS_OHOS : OS_Unix;DisplayServer_OHOS(EGLManager 子类)
引擎线程:Main::setup → 等 surface → setup2 → start
→ 循环 { process_events; Main::iteration; swap }
native_vsync 帧泵;输入 = XComponent 回调(UI线程) → OHOSInputHandler → Input 缓冲
音频 = AudioDriver_OHAudio 拉流回调
主要目录如下:
text
AirForge/
├── AppScope/app.json5 # 包名 com.airforge.app、版本 1.0.0
├── PORTING.md # 移植手册:架构/依赖/补丁/风险/验收对照
├── env.sh # 设备与路径环境变量(含回归机配置)
├── ai_log/ # 按日期分文件的移植会话日志
├── scripts/
│ ├── build_engine.sh # SCons 交叉编译引擎并拷入打包通道
│ └── deploy.sh # 构建部署脚本
├── native/
│ ├── patches/ohos-platform/ # 平台层补丁与上游整合补丁
│ └── sources/godot/ # Godot 4.7.2 源码(浅克隆)
└── entry/src/main/
├── cpp/napi_init.cpp # 薄 NAPI 桥与 TSFN 通道
└── ets/
├── entryability/EntryAbility.ets # 编辑器/项目管理器宿主
├── gameability/GameAbility.ets # 游戏实例宿主(:game 进程)
└── pages/Index.ets # XComponent 宿主与引擎控制
▍四、核心适配过程
### 1. platform/ohos 平台层从零新建
这是 P 系列补丁的主体:detect.py 与 SCsub 把 ohos 注册为 SCons 平台,os_ohos 实现 OS_OHOS : OS_Unix,display_server_ohos 以 drivers/egl/egl_manager.cpp 子类的方式接入 EGL 初始化与交换链,ohos_input_handler 承接 XComponent 的 UI 线程触摸回调并写入引擎 Input 缓冲,audio_driver_ohos 以拉流回调对接 OHAudio,godot_ohos 作为引擎入口把 Main::setup 的启动序列拆成"等 surface 再 setup2"两段。整套平台层以 OHOS_ENABLED 守卫或独立新文件形式存在,不污染上游通用路径。
### 2. SCons 交叉编译与体积收敛
构建命令是 scons platform=ohos target=editor arch=arm64 production=yes optimize=size debug_symbols=no vulkan=no opengl3=yes,musl 与 glibc 的线程差异(sysinfo、execinfo/backtrace、pthread_cancel)以 P2 补丁在构建期逐个暴露并收口。体积控制沿用 AirModel 的收敛定式:production 加 optimize=size 加 version-script 符号白名单,libgodot_ohos.so 从 137.9MB 收到 109MB。依赖矩阵极短:只直链 libEGL、libGLESv3、libohaudio、libhilog_ndk 四个 NDK 系统库,加随 HAP 分发的 libc++_shared.so,其余 zlib/png 等全用 Godot thirdparty 内置,无任何宿主可执行工具依赖。
### 3. 双 Ability 进程模型
编辑器内"运行项目"对应上游 Android 的双 Activity 设计:OS_OHOS::create_instance 经 NAPI 桥 TSFN 通知 ArkTS 层 startAbility(GameAbility),游戏在 :game 独立进程运行,GameAbility 退出即进程自毁、全局态零残留。这条链上踩出了两个手册级教训:GameAbility 的 exported 必须为 true,否则应用内 startAbility 的可见性校验失败时 AMS 不报错、静默改拉 EntryAbility;而"同进程引擎二启"不可行——Main::cleanup 清理进程级注册表后静态 once-guard 未复位,二启在 ProjectSettings 阶段即 SIGSEGV。手机形态的进程字段一度记录为被静默忽略,后续实测确认 :game 进程真实生效(跑满 272 秒),代码注释中保留了这一翻案证据;ApplicationContext.restartApp 全进程重启(pending_open.json 传参)保留为形态兼容兜底。
### 4. 输入与系统能力接线
输入链是 XComponent 回调进 OHOSInputHandler,再写引擎 Input 缓冲,触控与鼠标按源分流并防双发。双击语义是重点修复项:引擎核心只透传 is_double_tap 标志,检测责任在平台层——Android 侧由 GestureDetector 完成,OHOS 平台层此前的实现从未检测,导致项目管理器行双击打开与编辑器所有双击语义全部失效;修法是在 ACTION_DOWN 自建 350ms 窗口加 100px slop 判定并支持三连击重新配对。手写笔按 force 转 pressure、tiltX/Y 转 tilt 注入,捏合走轴事件转 MagnifyGesture,光标经 dlopen libohinput 调 OH_Input_SetPointerStyle 并以 2 秒心跳重申。文件对话框走的是上游内建路径:声明 FEATURE_NATIVE_DIALOG_FILE 后,引擎 FileDialog 自动落到 DisplayServer::file_dialog_show,桥接系统 DocumentViewPicker,此环节零补丁达成。汉化将上游 zh_Hans.po 编进二进制并预设 editor_language=zh_CN。
### 5. 引擎线程与帧泵
重型初始化全部在引擎线程完成,ArkTS 主线程零阻塞,配合双看门狗纪律规避启动 appfreeze(风险 R7)。帧泵用 native_vsync 帧回调驱动引擎循环,避免低功耗模式下忙转;swap interval 取 1(FIFO)防满速 present(风险 R3,Maleoon GPU 的 GLES3 兼容性先以三角形级验证过 EGL 通路)。入口侧还处理了 libentry.so 双实例问题:XComponent 的 libraryname 加载与 ETS import 会各 dlopen 一份,static 状态全部双份,最终以 PID 级 marker 文件加 AppStorage 双保险阻止退出后的"项目管理器幽灵回归"。
▍五、适配中遇到的几个难点
### 难点1:exported 缺失导致的静默回退
GameAbility 的 exported 配置为 false 时,应用内 startAbility 的可见性校验失败,AMS 不报任何错误,静默 spawn 默认的 EntryAbility——每次"打开工程"实际是新开一个项目管理器。shell 侧 aa start -a GameAbility 报 10103001 visibility 错误才定位到根因。教训已写入移植手册:多 Ability 架构的应用内启动同样受 exported 约束,失败形态是静默回退而非报错。
### 难点2:双击检测的平台层缺位
项目管理器双击行打不开工程、编辑器双击语义全灭,但信号链探针显示 wiring 完好。逐层核查后确认:引擎触摸到鼠标的合成只透传 is_double_tap() 布尔值,双击时间窗与位移阈值的判定责任完全在平台层,Android 由 Java GestureDetector 打标,OHOS 平台层从未实现。在 ohos_input_handler.cpp 按 350ms 窗口加 100px slop 自建判定后,注入双击稳定触发打开信号。
### 难点3:半成品二进制制造的三块"假铁证"
一轮排查中"信号不到处理器"的三条证据链,最终全部翻案:所依赖的 so 是上会话中途取消的 scons 半成品,部分 .o 新部分旧;所谓"打开按钮矩形"实为重命名按钮(OCR 加像素定案);"信号零触发"是旧二进制与点错按钮的叠加假象。另一个叠加问题是构建脚本用错产物名——scons 产物带全后缀 libgodot_ohos.ohos.editor.arm64.so,脚本按短名拷贝必然失败且 exit code 被 | tail 吃掉,此前部署的一直是旧 so。结论进入方法学:部署验证用的 so 必须来自完整收敛的构建,产物时间戳要晚于最后一次源码修改。
### 难点4:跨语言边界的两个静默陷阱
ArkTS 数组跨 NAPI 边界后不是 JS Array(napi_typeof 返回 object、napi_is_array 为 false),set_engine_args 静默丢参——项目管理器模式下参数恰好为空数组,缺陷从未暴露,直到编辑器模式需要传 --path。修法是 d.ts 改为 JSON 字符串、napi 侧做逐 token 解析。另一个是状态隔离:UIAbility 里 AppStorage 的 setOrCreate 与 @Entry 页面的 AppStorage 是隔离实例,ability 写入后页面读到的仍是空。两个问题都不报错,只能靠埋点往返验证发现,最终分别以 JSON 通道与 pending_open.json 文件通道解决。
### 难点5:退出与重启的流转设计
项目管理器与编辑器互相拉起、退出回归的流转经过四代演进:直接 startAbility 回 PM 会留下双实例;同进程二启崩溃;restartApp 全进程重启(API 12+,需获焦)配合 pending_open.json 与 want 参数镜像,构成干净进程链。配套的防重入设计包括 ENGINE_EXITED 分支的 restartingApp 防竞争标志,以及退出时先 startAbility 回 EntryAbility 再 terminateSelf 的顺序约束。
▍六、编译、安装与启动
构建分引擎与 HAP 两段,先在仓库根目录 source 环境脚本,再交叉编译引擎并把产物拷入打包通道:
bash
source env.sh
cd $GODOT_SRC && scons platform=ohos target=editor arch=arm64 production=yes \
optimize=size debug_symbols=no vulkan=no opengl3=yes -j$(sysctl -n hw.ncpu)
cp $GODOT_BIN/libgodot_ohos.ohos.editor.arm64.so $GODOT_LIBS_CHANNEL/
随后打包 HAP(PORTING 记录用 devecocli build,等价的 hvigor 命令如下):
bash
export JAVA_HOME=/Applications/DevEco-Studio.app/Contents/jbr/Contents/Home
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
hvigorw --mode module -p module=entry assembleHap --no-daemon
产物位于 entry/build/default/outputs/default/entry-default-signed.hap。安装与启动(更换引擎 so 后必须 force-stop 换进程验证,避免旧进程残留):
bash
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa force-stop com.airforge.app
hdc shell aa start -a EntryAbility -b com.airforge.app
▍七、当前功能边界
按 PORTING.md 与 2026-09-25 会话日志的记录,当前阶段已在 Mate 60 Pro 真机实证的能力:
- 项目管理器上屏与工程列表,行双击打开工程(350ms 双击窗口);
- 打开链完整闭环:PM 双击行 → 启动 GameAbility(:game 独立进程)或 restartApp 通道 → 编辑器以 --path demo --editor 全屏上屏(2720×1260 沉浸式,底部死黑已修)→ BACK 干净退出 → PM 回归无幽灵实例;
- 引擎直连渲染:gl_compatibility(EGL + GLES3)在实机 GPU 上完成从三角形级验证到编辑器全屏渲染;
- OHOS 平台层:OS_OHOS、DisplayServer_OHOS、OHOSInputHandler、AudioDriver_OHAudio 与引擎入口;
- 文件对话框经上游内建 FEATURE_NATIVE_DIALOG_FILE 路径接系统 Picker;
- 汉化资源(zh_Hans 编进二进制)与菜单、输入、光标等系统能力的实现落点已就位。
尚未完成或明确登记为遗留的能力:S1 至 S14 验收标准尚未逐项打勾,编辑、运行、剪贴板双向、分享与碰一碰、暗黑主题、新建项目模板、性能口径均属待验收;Mate60Pro 上 PM 侧栏打开按钮的有效区与系统手势保留区完全重叠(右缘死区),当前以行双击加 Ctrl+E 作为主打开路径,真机手指可达性待验证,彻底方案为 XComponent 右缘避让(影响全局坐标,暂缓);PM 首次双击前需先选中行的交互约束;MatePad Mini 回归未跑;编辑器模式此轮记录过一处 ArkUI 渲染层的 SIGSEGV 待观察。
因此,当前版本更准确的定位是"Godot 鸿蒙移植的基础骨架加已验证的关键链路":平台层与进程模型已经成立,项目管理器到编辑器的真实闭环可以在真机复现,交付级的功能完备度仍以验收对照表的逐项打勾为准。
▍八、总结
轻引擎的移植选择了四条路线里工程量最大的一条:不套壳、不转译,为 Godot 新建 platform/ohos 平台层,让引擎以 EGL 加 GLES3 直接面对鸿蒙表面。这一选择的回报是架构上的对齐——双 Ability 对应上游双 Activity,restartApp 通道对应进程生命周期,未来基于 Godot 的游戏移植可以直接继承这套平台层。会话日志里沉淀的静默回退、半成品二进制、跨语言边界静默丢参等教训,也都超出了单一工程的适用范围。
后续工作的重心由验收对照表决定:把 S1 至 S14 逐项实证打勾,先补齐编辑器触控与手写笔输入的回归,再处理右缘死区的避让方案与 MatePad Mini 回归,最后落性能口径。每一步继续坚持会话日志的口径:结论必须同时有代码链路证据与真机行为证据。
楼主
8 天前