A
Air官方
【Air 系列 · 鸿蒙 PC 适配全记录】03 / 56
■ 应用:AirBase(from SQLiteBrowser)(AirBase)
■ 定位:DB Browser for SQLite 移植,SQLite 数据库浏览
■ 上游:DB Browser for SQLite | 路线:Qt6 6.11.1+QPA | 版本:1.2.0
■ 开源: https://gitcode.com/Andy88/Harmony-SQLiteBrowser
■ 市场状态:已上架 AGC 应用页: https://appgallery.huawei.com/app/6917616285376441347
■ 官网(免费下载): https://www.shunidc.cn/
————————————————————
开源鸿蒙 PC 社区: https://harmonypc.csdn.net/
PC 社区项目申请: https://atomgit.com/OpenHarmonyPCDeveloper
适配开源地址:https://gitcode.com/Andy88/Harmony-SQLiteBrowser
环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743
▍一、为什么要适配 DB Browser for SQLite
做鸿蒙应用开发的工程师几乎每天都和数据库打交道:ArkData 落在沙箱里的 .db 文件、调试期导出的库、第三方应用交付的数据包,都需要一个能看表结构、能改数据、能直接跑 SQL 的工具。DB Browser for SQLite 正是桌面端这个位置上最常用的开源软件:浏览数据、数据库结构、编辑杂注、执行 SQL 四个页签覆盖了本地库排查的全部日常,上游为 sqlitebrowser master(3.13.99 nightly,Qt6 Widgets + CMake),MPL-2.0 与 GPL-3.0-or-later 双许可。
选择它作为移植对象还有一个工程层面的原因:它是典型的 Qt6 Widgets 应用,QMenuBar、QDialog、QTabWidget 这类构件与已经全链成熟的 AirCast(OBS 移植)生态完全同构,Qt 6.11.1 预编译栈与 ohos QPA 插件都可以直接复用,移植风险集中在输入与窗口细节而非框架本身。事实证明这个判断基本成立,也留下了几个框架层都没有答案的硬骨头。
当前鸿蒙工程包名为 com.airbase.app,版本 1.0.0,deviceTypes 覆盖 phone、tablet、2in1,声明 ohos.permission.INTERNET 权限,并注册了自定义 UTD 类型 com.airbase.app.sqlite 与 com.airbase.app.sql 的文件打开能力。验证设备为 MatePad 11.5 与 MatePad Mini 悦读版(API 26,2026-09-12 起为主验证机),MateBook Pro 作为 2in1 键鼠对照机。
▍二、先划清边界:不把编译通过当成适配完成
sqlitebrowser 是一个结构规整的桌面程序:main() 起 QApplication,QMainWindow 承载四个页签,QMenuBar 挂全部命令,QFileDialog 管文件进出。这些构件在鸿蒙上的对应物没有一个是现成的,工程对每一层都明确替换策略,并用里程碑记录每层落地的验证状态。
层次 原项目实现(传统桌面方案) 鸿蒙侧当前方案
应用入口 main() 构造 QApplication main 改导出 airbase_main,由宿主线程驱动(P2)
窗口承载 桌面窗口系统上的 QMainWindow XComponent(airbase_surface) → OHNativeWindow → libqohos QPA
菜单命令 QMenuBar 自绘与快捷键分发 ArkTS bindMenu 接管:快照 JSON 轮询 + serial/idx 校验触发
文件打开/保存 QFileDialog 桌面对话框 QPA pick helper ⇄ DocumentViewPicker 系统选择器(TSFN 回传)
数据库引擎 上游捆绑 SQLite AirGis 预编译 libsqlite3.so 复用(sqlcipher=OFF)
视觉主题 桌面默认样式 DarkStyle 默认(qdarkstyle QSS 嵌 qrc)+ COLOR_MODE_DARK 钉死
翻译加载 系统 Qt 翻译目录 .qm 嵌入 qrc,QLibraryInfo → translations → :/translations 三级回退
外部调用 桌面 shell / 文件管理器集成 分享面板出向 + viewData 收向(want 双入口 → staging → pendingOpen)
边界的关键一条在打包形态:上游的 LinguistTools、CPack、桌面 bundle 全部跳过,整个 sqlitebrowser 编为单个 libdbbrowser.so,由 libairbase_core.so 按 dlopen 拓扑载入,ArkTS 层不再有第二套数据库逻辑。
▍三、鸿蒙版的整体架构
工程保持 Air 系双层结构。ArkTS 壳处理 XComponent、顶栏菜单、系统选择器与对话框子窗化;libbasebridge.so 是只链系统库的 NAPI 薄桥;libairbase_core.so 做环境前置、dlopen 拓扑、QPA 接线并驱动 airbase_main。发布前清理后,自动化回归用的 HTTP 通道绑定 INADDR_LOOPBACK,局域网不可达,仅 hdc fport 转发可达。
text
ArkTS 壳(entry/src/main/ets)
├── XComponent(airbase_surface) → OHNativeWindow → QPA(QOhos_SetNativeWindow)
├── 顶栏菜单(bindMenu 系统 Menu,快照轮询 + trigger 回注)
├── 系统文件选择器(DocumentViewPicker ⇄ QPA pick helper,TSFN)
├── 对话框子窗化(SubWindowManager 双模式 + DialogHost)
└── IME 五件套(隐形 TextArea 宿主 + 差分回注协议)
libbasebridge.so(NAPI 薄桥:只链系统库)
└── libairbase_core.so(env 前置 / dlopen 拓扑 / QPA 接线 / airbase_main)
└── dlopen 22 库(RTLD_GLOBAL):Qt6Core→Gui→Widgets→Network→Svg→SvgWidgets
→Xml→Concurrent→PrintSupport→OpenGL→OpenGLWidgets→Core5Compat
→(z 系/ssl/crypto)→libqohos(QPA)→libsqlite3→libdbbrowser
主要目录如下:
text
AirBase/
├── AppScope/app.json5 # 包名、版本
├── PORTING.md # 补丁清单、风险登记册、里程碑与踩坑映射
├── ai_log/ # 逐会话进度实录
├── entry/src/main/
│ ├── ets/
│ │ ├── pages/Index.ets # XComponent 宿主、IME 会话、键转发
│ │ ├── components/DialogHost.ets # Qt 对话框子窗承载
│ │ └── utils/FileManager.ets # 系统选择器中转与回拷
│ ├── cpp/
│ │ ├── airbase_core.cpp # 宿主核心(env/拓扑/接线/HTTP 环回通道)
│ │ ├── napi_init.cpp # NAPI 桥
│ │ └── qt_platform/ohos_qt6/ # ohos QPA(inputcontext/filedialog 等)
│ ├── libs/arm64-v8a/ # Qt6 栈 + libdbbrowser 等 22 个预编译库
│ └── resources/rawfile/arkdata/ # 自定义 UTD 声明
└── native/
├── scripts/build_sqlitebrowser.sh # 交叉构建脚本
└── sources/sqlitebrowser/ # 上游源码树(就地补丁标记)
▍四、核心适配过程
### 1. GUI→库范式与宿主核心
补丁 P1 把上游 CMake 的 add_executable 改为 SHARED 库(产物 libdbbrowser.so),同时跳过 WIN32/MACOSX_BUNDLE/CPack/install;P2 在 src/main.cpp 用 #ifdef __OHOS__ 把 main 改名导出为 airbase_main。entry/src/main/cpp/airbase_core.cpp 承担六件事:最前置 HOME/XDG 环境变量(QSettings 的配置与缓存全部落沙箱,必须在 Qt 缓存之前)、按拓扑序 dlopen 全部依赖、在宿主线程上调 airbase_main(QApplication 构造线程即 Qt 主线程,规避 appfreeze 看门狗)、QPA 接线、日志镜像落盘、环回 HTTP 触发通道。
### 2. 菜单桥接:QMenuBar 的 ArkTS 接管
新增的 src/OHOSMenuBridge.cpp/.h(P3)把 QMenuBar 变成 ArkTS 可消费的数据源:QTimer 以 1 秒周期对菜单树做快照 JSON,QPointer 注册表维护 QAction 身份,trigger 请求带 serial/idx 双重校验。性能上做了代次门控——GetMenuSnapshot(lastSerial) 在代次未变时返回空串,心跳周期内零 JSON 拷贝与解析,解析成功才提交代次,避免解析失败卡死菜单。主窗创建后由 showMainWindow() 接线 airbase_menu_init(P4)。
### 3. 文件进出:系统选择器与分享双向
打开与保存走 QPA 内置的 filedialoghelper:Qt 侧发起 pick,经 TSFN 回调 ArkTS 弹出 DocumentViewPicker,结果回注 Qt。保存通道按 AirCast 范式经 FileManager 中转落盘。分享为双向:出向由 File 菜单的"分享当前数据库"哨兵项触发 ui_request("share", 路径) 拉起 systemShare 面板;收向依赖 module.json5 的 viewData skills 与自定义 UTD,want 双入口先把文件拷入 staging,pendingOpen 以 100ms 自驱冲刷交给 airbase_open_file,真机上 aa start -U file://沙箱库 全链 54ms 返回。
### 4. 汉化链与暗黑主题
界面汉化分三层:core 在 QApplication 构造前 setenv LANG/LC_ALL=zh_CN.UTF-8(QPlugin 层无 locale 环境时 QLocale 会回落 en_US);sqlb_zh_CN.qm 由 host lrelease 预生成后嵌 qrc;Qt 自带翻译因 Qt6 拆分(qt_zh_CN.qm 只是 99 字节依赖清单)单独把 qtbase_zh_CN.qm 以别名嵌入,加载路径加 ":/translations" 第三级回退。暗黑模式在 Settings.cpp 的 __OHOS__ 分支默认 DarkStyle,EntryAbility 侧 setColorMode(COLOR_MODE_DARK) 并在 onConfigurationUpdate 钉死,启动遮罩同步暗色。
### 5. 输入链路重建(M8)
首版壳层的软键盘链路在真机基线测试中完全断链。重建后的 IME 五件套为:2×2vp、透明度 0.01、HitTestMode.None 的隐形 TextArea 宿主;showTextInput() 建立真正的编辑会话(旧的 showSoftKeyboard() 裸拉面板不绑会话,是断链根因之一);20/150/400ms 三段重申;差分回注协议(新增后缀提交、按码点退格、非前缀全删重输、Enter 映射 Qt::Key_Return);imeClearing 回声吞,且只吞空值。键盘侧用 RegisterKeyEventCallbackWithResult 与 GetKeyEventModifierKeyStates 建立修饰键链,Ctrl 位与 QPA metaState 逐位一致,Ctrl+Tab 切页签、Ctrl+A/C/X/V 全部打通。
▍五、适配中遇到的几个难点
### 难点一:整屏纯黑而零报错的启动失败
首次真机启动整屏纯黑,ArkTS 层也无 E 级日志,进程存活。两层原因叠加:libQt6Network.so 的 NEEDED libssl.so/libcrypto.so 未随包部署,dlopen 链在 Qt6Widgets 之后中断;同时 I 级 hilog 被流控吞掉,启动期日志窗口错过现场。修复是 deploy 清单补齐 OpenSSL 两库并去版本号,工程纪律则改为:启动链里程碑(dlopen×22、宿主线程、airbase_main 返回)固定 E 级,姊妹工程复制 deploy 清单时必须核对每个 Qt 模块的完整 NEEDED 闭包。
### 难点二:对话框里输入后无法删除
创建表/索引对话框出现"输入后退格无效",软硬键盘同死。根因是差分回注基准失同步:对话框会话期 Qt 高频重发 showInputPanel,旧逻辑无条件清空代理缓冲,代理为空而 Qt 字段有字,退格在空代理上是零事件。修复三件:showIme 重播种判定(仅 fresh 或种子不一致才重置)、QPA show 请求携带目标 QLineEdit 的文本与光标种子(桥接链三参化)、代理 caretPosition() 同步 Qt 光标。该修复在 MatePad Mini 上以逐字删除、重进字段删除、主窗无回归三个用例双通道验证。
### 难点三:输入落点错落主窗口
对话框字段里打的字出现在主窗 SQL 编辑器。Qt 窗口激活模型下,模态会话期 focusWindow() 常是主窗,而对话框字段才有 Qt 焦点,按窗口解析 focusObject 就会落错控件。工程把 IME 提交目标与键注入目标都改为"可见 Qt::Dialog 窗口的 focusObject 优先",并以带 objectName 的 PRESS 探针确认左 dock 结构树与 SQL 编辑器视口同名(都是 qt_scrollarea_viewport)必须靠 objectName 区分。
### 难点四:预编译栈与上游版本的 API 漂移
上游按 Qt6.2 目标编写,工程栈为 Qt 6.11.1,且 AirGis 栈以 QT_NO_CONTEXTLESS_CONNECT 禁用三参 connect。编译期逐点补丁:connect 挂接收者、QStringView/QDate 漂移见招拆招,Core5Compat 兜底。交叉栈没有 LinguistTools 的 CMake 配置,qt_add_translation 不可用,改为构建脚本用 host lrelease 预生成 .qm 到源码树原位(P6)。
### 难点五:陈旧菜单快照触发错项
自动化测试里点"分享"却触发了"退出"。排查发现建库后"最近的文件"子菜单动态新增条目,QAction 注册表整体移位,而测试用的 idx 来自旧快照。工程约定 HTTP 触发必须现拉菜单快照取当前 idx,禁止硬编码;生产路径中 idx 与 serial 出自同一棵树,代次失配自动重拉,本身不受影响。这个案例同时给了判定纪律:测"触摸是否可达 Qt 主表面"前,必须先确认没有模态弹窗在场吸收点击。
▍六、编译、安装与启动
上游交叉构建与数据部署:
bash
source native/env.sh
bash native/scripts/build_sqlitebrowser.sh # libdbbrowser.so(AUTOMOC 走 QT_HOST_PATH)
bash native/scripts/deploy.sh # Qt 栈 + OpenSSL 归一 + entry/libs 部署
ArkTS 侧标准 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。注意改动了 entry/libs 下的预编译库后必须完整重新构建打包,--skip-build 不会重打旧库。安装与启动:
bash
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.airbase.app
▍七、当前功能边界
里程碑与验收记录支持的已覆盖能力:
- MatePad 11.5 真机冒烟:dlopen 22 库全链、Qt 主窗完整渲染(菜单栏/双层工具栏/四页签/双 dock/状态栏)、faultlog 恒空;
- 全界面汉化(应用菜单与 qtbase 标准按钮两级翻译均生效),暗黑模式为默认主题并钉死系统色模式;
- 建库保存闭环:菜单触发 → 系统保存选择器 → 沙箱落盘 → 菜单判据全翻转;页签触摸切换在 MatePad Mini 定论可达;
- 分享双向(systemShare 面板出向、自定义 UTD + want 收向打开)、触控与鼠标双模输入分流;
- IME 中英文输入、退格、回车、对话框字段提交全链真机实证,剪贴板 Ctrl+A/C/X/V 交互闭环;
- 稳态性能门控(菜单快照代次门控、启动链 E 级日志)与光标样式桥。
尚未覆盖或规划中的能力(PORTING.md 遗留清单):
- MateBook Pro(2in1)键鼠实测:注入配方已入库,待无人时段复跑(S3 点击、S6 光标变形、S14 拖动与自由窗对话框、物理键盘全套);
- en_US 布局下第四页签被右侧 dock 裁断(zh_CN 交付布局不受影响);
- 保存选择器预填文件名残留上次会话名(系统 picker 记忆机制,建议名传参未被新版面板采用);
- 中文拼音组合态逐键手感仅经整串注入验证,交付前建议真手指补一轮。
因此,当前版本更准确的定位是"可日常使用的 SQLite 管理基础版":建库、浏览、改表、跑 SQL、分享与暗黑主题已在平板真机闭环,键鼠域的细节验收仍在补全路上。
▍八、总结
AirBase 的移植过程说明了一件事:当框架栈可以整体复用时,真正决定可用性的是菜单、文件、输入这些"框架认为平台自己会解决"的链路。工程把 QMenuBar 变成快照数据源、把 QFileDialog 换成系统选择器、把软键盘重建为带差分协议的编辑会话,每一条都有真机日志与视觉双通道留痕,这也是它能在一个多月内从空壳推进到日常可用的原因。
后续工作的重心集中在两处:一是 2in1 键鼠域的完整实测,把触控路径上已经验证的结论延伸到鼠标与物理键盘;二是交付前的人工体验项(拼音逐键、保存命名、布局微调)。风险登记册里 R7 一类"触摸可达性"疑问已被 M6 的正面定论关闭,剩余项大多是验证纪律问题而非功能缺口。
■ 应用:AirBase(from SQLiteBrowser)(AirBase)
■ 定位:DB Browser for SQLite 移植,SQLite 数据库浏览
■ 上游:DB Browser for SQLite | 路线:Qt6 6.11.1+QPA | 版本:1.2.0
■ 开源: https://gitcode.com/Andy88/Harmony-SQLiteBrowser
■ 市场状态:已上架 AGC 应用页: https://appgallery.huawei.com/app/6917616285376441347
■ 官网(免费下载): https://www.shunidc.cn/
————————————————————
开源鸿蒙 PC 社区: https://harmonypc.csdn.net/
PC 社区项目申请: https://atomgit.com/OpenHarmonyPCDeveloper
适配开源地址:https://gitcode.com/Andy88/Harmony-SQLiteBrowser
环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743
▍一、为什么要适配 DB Browser for SQLite
做鸿蒙应用开发的工程师几乎每天都和数据库打交道:ArkData 落在沙箱里的 .db 文件、调试期导出的库、第三方应用交付的数据包,都需要一个能看表结构、能改数据、能直接跑 SQL 的工具。DB Browser for SQLite 正是桌面端这个位置上最常用的开源软件:浏览数据、数据库结构、编辑杂注、执行 SQL 四个页签覆盖了本地库排查的全部日常,上游为 sqlitebrowser master(3.13.99 nightly,Qt6 Widgets + CMake),MPL-2.0 与 GPL-3.0-or-later 双许可。
选择它作为移植对象还有一个工程层面的原因:它是典型的 Qt6 Widgets 应用,QMenuBar、QDialog、QTabWidget 这类构件与已经全链成熟的 AirCast(OBS 移植)生态完全同构,Qt 6.11.1 预编译栈与 ohos QPA 插件都可以直接复用,移植风险集中在输入与窗口细节而非框架本身。事实证明这个判断基本成立,也留下了几个框架层都没有答案的硬骨头。
当前鸿蒙工程包名为 com.airbase.app,版本 1.0.0,deviceTypes 覆盖 phone、tablet、2in1,声明 ohos.permission.INTERNET 权限,并注册了自定义 UTD 类型 com.airbase.app.sqlite 与 com.airbase.app.sql 的文件打开能力。验证设备为 MatePad 11.5 与 MatePad Mini 悦读版(API 26,2026-09-12 起为主验证机),MateBook Pro 作为 2in1 键鼠对照机。
▍二、先划清边界:不把编译通过当成适配完成
sqlitebrowser 是一个结构规整的桌面程序:main() 起 QApplication,QMainWindow 承载四个页签,QMenuBar 挂全部命令,QFileDialog 管文件进出。这些构件在鸿蒙上的对应物没有一个是现成的,工程对每一层都明确替换策略,并用里程碑记录每层落地的验证状态。
层次 原项目实现(传统桌面方案) 鸿蒙侧当前方案
应用入口 main() 构造 QApplication main 改导出 airbase_main,由宿主线程驱动(P2)
窗口承载 桌面窗口系统上的 QMainWindow XComponent(airbase_surface) → OHNativeWindow → libqohos QPA
菜单命令 QMenuBar 自绘与快捷键分发 ArkTS bindMenu 接管:快照 JSON 轮询 + serial/idx 校验触发
文件打开/保存 QFileDialog 桌面对话框 QPA pick helper ⇄ DocumentViewPicker 系统选择器(TSFN 回传)
数据库引擎 上游捆绑 SQLite AirGis 预编译 libsqlite3.so 复用(sqlcipher=OFF)
视觉主题 桌面默认样式 DarkStyle 默认(qdarkstyle QSS 嵌 qrc)+ COLOR_MODE_DARK 钉死
翻译加载 系统 Qt 翻译目录 .qm 嵌入 qrc,QLibraryInfo → translations → :/translations 三级回退
外部调用 桌面 shell / 文件管理器集成 分享面板出向 + viewData 收向(want 双入口 → staging → pendingOpen)
边界的关键一条在打包形态:上游的 LinguistTools、CPack、桌面 bundle 全部跳过,整个 sqlitebrowser 编为单个 libdbbrowser.so,由 libairbase_core.so 按 dlopen 拓扑载入,ArkTS 层不再有第二套数据库逻辑。
▍三、鸿蒙版的整体架构
工程保持 Air 系双层结构。ArkTS 壳处理 XComponent、顶栏菜单、系统选择器与对话框子窗化;libbasebridge.so 是只链系统库的 NAPI 薄桥;libairbase_core.so 做环境前置、dlopen 拓扑、QPA 接线并驱动 airbase_main。发布前清理后,自动化回归用的 HTTP 通道绑定 INADDR_LOOPBACK,局域网不可达,仅 hdc fport 转发可达。
text
ArkTS 壳(entry/src/main/ets)
├── XComponent(airbase_surface) → OHNativeWindow → QPA(QOhos_SetNativeWindow)
├── 顶栏菜单(bindMenu 系统 Menu,快照轮询 + trigger 回注)
├── 系统文件选择器(DocumentViewPicker ⇄ QPA pick helper,TSFN)
├── 对话框子窗化(SubWindowManager 双模式 + DialogHost)
└── IME 五件套(隐形 TextArea 宿主 + 差分回注协议)
libbasebridge.so(NAPI 薄桥:只链系统库)
└── libairbase_core.so(env 前置 / dlopen 拓扑 / QPA 接线 / airbase_main)
└── dlopen 22 库(RTLD_GLOBAL):Qt6Core→Gui→Widgets→Network→Svg→SvgWidgets
→Xml→Concurrent→PrintSupport→OpenGL→OpenGLWidgets→Core5Compat
→(z 系/ssl/crypto)→libqohos(QPA)→libsqlite3→libdbbrowser
主要目录如下:
text
AirBase/
├── AppScope/app.json5 # 包名、版本
├── PORTING.md # 补丁清单、风险登记册、里程碑与踩坑映射
├── ai_log/ # 逐会话进度实录
├── entry/src/main/
│ ├── ets/
│ │ ├── pages/Index.ets # XComponent 宿主、IME 会话、键转发
│ │ ├── components/DialogHost.ets # Qt 对话框子窗承载
│ │ └── utils/FileManager.ets # 系统选择器中转与回拷
│ ├── cpp/
│ │ ├── airbase_core.cpp # 宿主核心(env/拓扑/接线/HTTP 环回通道)
│ │ ├── napi_init.cpp # NAPI 桥
│ │ └── qt_platform/ohos_qt6/ # ohos QPA(inputcontext/filedialog 等)
│ ├── libs/arm64-v8a/ # Qt6 栈 + libdbbrowser 等 22 个预编译库
│ └── resources/rawfile/arkdata/ # 自定义 UTD 声明
└── native/
├── scripts/build_sqlitebrowser.sh # 交叉构建脚本
└── sources/sqlitebrowser/ # 上游源码树(就地补丁标记)
▍四、核心适配过程
### 1. GUI→库范式与宿主核心
补丁 P1 把上游 CMake 的 add_executable 改为 SHARED 库(产物 libdbbrowser.so),同时跳过 WIN32/MACOSX_BUNDLE/CPack/install;P2 在 src/main.cpp 用 #ifdef __OHOS__ 把 main 改名导出为 airbase_main。entry/src/main/cpp/airbase_core.cpp 承担六件事:最前置 HOME/XDG 环境变量(QSettings 的配置与缓存全部落沙箱,必须在 Qt 缓存之前)、按拓扑序 dlopen 全部依赖、在宿主线程上调 airbase_main(QApplication 构造线程即 Qt 主线程,规避 appfreeze 看门狗)、QPA 接线、日志镜像落盘、环回 HTTP 触发通道。
### 2. 菜单桥接:QMenuBar 的 ArkTS 接管
新增的 src/OHOSMenuBridge.cpp/.h(P3)把 QMenuBar 变成 ArkTS 可消费的数据源:QTimer 以 1 秒周期对菜单树做快照 JSON,QPointer 注册表维护 QAction 身份,trigger 请求带 serial/idx 双重校验。性能上做了代次门控——GetMenuSnapshot(lastSerial) 在代次未变时返回空串,心跳周期内零 JSON 拷贝与解析,解析成功才提交代次,避免解析失败卡死菜单。主窗创建后由 showMainWindow() 接线 airbase_menu_init(P4)。
### 3. 文件进出:系统选择器与分享双向
打开与保存走 QPA 内置的 filedialoghelper:Qt 侧发起 pick,经 TSFN 回调 ArkTS 弹出 DocumentViewPicker,结果回注 Qt。保存通道按 AirCast 范式经 FileManager 中转落盘。分享为双向:出向由 File 菜单的"分享当前数据库"哨兵项触发 ui_request("share", 路径) 拉起 systemShare 面板;收向依赖 module.json5 的 viewData skills 与自定义 UTD,want 双入口先把文件拷入 staging,pendingOpen 以 100ms 自驱冲刷交给 airbase_open_file,真机上 aa start -U file://沙箱库 全链 54ms 返回。
### 4. 汉化链与暗黑主题
界面汉化分三层:core 在 QApplication 构造前 setenv LANG/LC_ALL=zh_CN.UTF-8(QPlugin 层无 locale 环境时 QLocale 会回落 en_US);sqlb_zh_CN.qm 由 host lrelease 预生成后嵌 qrc;Qt 自带翻译因 Qt6 拆分(qt_zh_CN.qm 只是 99 字节依赖清单)单独把 qtbase_zh_CN.qm 以别名嵌入,加载路径加 ":/translations" 第三级回退。暗黑模式在 Settings.cpp 的 __OHOS__ 分支默认 DarkStyle,EntryAbility 侧 setColorMode(COLOR_MODE_DARK) 并在 onConfigurationUpdate 钉死,启动遮罩同步暗色。
### 5. 输入链路重建(M8)
首版壳层的软键盘链路在真机基线测试中完全断链。重建后的 IME 五件套为:2×2vp、透明度 0.01、HitTestMode.None 的隐形 TextArea 宿主;showTextInput() 建立真正的编辑会话(旧的 showSoftKeyboard() 裸拉面板不绑会话,是断链根因之一);20/150/400ms 三段重申;差分回注协议(新增后缀提交、按码点退格、非前缀全删重输、Enter 映射 Qt::Key_Return);imeClearing 回声吞,且只吞空值。键盘侧用 RegisterKeyEventCallbackWithResult 与 GetKeyEventModifierKeyStates 建立修饰键链,Ctrl 位与 QPA metaState 逐位一致,Ctrl+Tab 切页签、Ctrl+A/C/X/V 全部打通。
▍五、适配中遇到的几个难点
### 难点一:整屏纯黑而零报错的启动失败
首次真机启动整屏纯黑,ArkTS 层也无 E 级日志,进程存活。两层原因叠加:libQt6Network.so 的 NEEDED libssl.so/libcrypto.so 未随包部署,dlopen 链在 Qt6Widgets 之后中断;同时 I 级 hilog 被流控吞掉,启动期日志窗口错过现场。修复是 deploy 清单补齐 OpenSSL 两库并去版本号,工程纪律则改为:启动链里程碑(dlopen×22、宿主线程、airbase_main 返回)固定 E 级,姊妹工程复制 deploy 清单时必须核对每个 Qt 模块的完整 NEEDED 闭包。
### 难点二:对话框里输入后无法删除
创建表/索引对话框出现"输入后退格无效",软硬键盘同死。根因是差分回注基准失同步:对话框会话期 Qt 高频重发 showInputPanel,旧逻辑无条件清空代理缓冲,代理为空而 Qt 字段有字,退格在空代理上是零事件。修复三件:showIme 重播种判定(仅 fresh 或种子不一致才重置)、QPA show 请求携带目标 QLineEdit 的文本与光标种子(桥接链三参化)、代理 caretPosition() 同步 Qt 光标。该修复在 MatePad Mini 上以逐字删除、重进字段删除、主窗无回归三个用例双通道验证。
### 难点三:输入落点错落主窗口
对话框字段里打的字出现在主窗 SQL 编辑器。Qt 窗口激活模型下,模态会话期 focusWindow() 常是主窗,而对话框字段才有 Qt 焦点,按窗口解析 focusObject 就会落错控件。工程把 IME 提交目标与键注入目标都改为"可见 Qt::Dialog 窗口的 focusObject 优先",并以带 objectName 的 PRESS 探针确认左 dock 结构树与 SQL 编辑器视口同名(都是 qt_scrollarea_viewport)必须靠 objectName 区分。
### 难点四:预编译栈与上游版本的 API 漂移
上游按 Qt6.2 目标编写,工程栈为 Qt 6.11.1,且 AirGis 栈以 QT_NO_CONTEXTLESS_CONNECT 禁用三参 connect。编译期逐点补丁:connect 挂接收者、QStringView/QDate 漂移见招拆招,Core5Compat 兜底。交叉栈没有 LinguistTools 的 CMake 配置,qt_add_translation 不可用,改为构建脚本用 host lrelease 预生成 .qm 到源码树原位(P6)。
### 难点五:陈旧菜单快照触发错项
自动化测试里点"分享"却触发了"退出"。排查发现建库后"最近的文件"子菜单动态新增条目,QAction 注册表整体移位,而测试用的 idx 来自旧快照。工程约定 HTTP 触发必须现拉菜单快照取当前 idx,禁止硬编码;生产路径中 idx 与 serial 出自同一棵树,代次失配自动重拉,本身不受影响。这个案例同时给了判定纪律:测"触摸是否可达 Qt 主表面"前,必须先确认没有模态弹窗在场吸收点击。
▍六、编译、安装与启动
上游交叉构建与数据部署:
bash
source native/env.sh
bash native/scripts/build_sqlitebrowser.sh # libdbbrowser.so(AUTOMOC 走 QT_HOST_PATH)
bash native/scripts/deploy.sh # Qt 栈 + OpenSSL 归一 + entry/libs 部署
ArkTS 侧标准 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。注意改动了 entry/libs 下的预编译库后必须完整重新构建打包,--skip-build 不会重打旧库。安装与启动:
bash
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.airbase.app
▍七、当前功能边界
里程碑与验收记录支持的已覆盖能力:
- MatePad 11.5 真机冒烟:dlopen 22 库全链、Qt 主窗完整渲染(菜单栏/双层工具栏/四页签/双 dock/状态栏)、faultlog 恒空;
- 全界面汉化(应用菜单与 qtbase 标准按钮两级翻译均生效),暗黑模式为默认主题并钉死系统色模式;
- 建库保存闭环:菜单触发 → 系统保存选择器 → 沙箱落盘 → 菜单判据全翻转;页签触摸切换在 MatePad Mini 定论可达;
- 分享双向(systemShare 面板出向、自定义 UTD + want 收向打开)、触控与鼠标双模输入分流;
- IME 中英文输入、退格、回车、对话框字段提交全链真机实证,剪贴板 Ctrl+A/C/X/V 交互闭环;
- 稳态性能门控(菜单快照代次门控、启动链 E 级日志)与光标样式桥。
尚未覆盖或规划中的能力(PORTING.md 遗留清单):
- MateBook Pro(2in1)键鼠实测:注入配方已入库,待无人时段复跑(S3 点击、S6 光标变形、S14 拖动与自由窗对话框、物理键盘全套);
- en_US 布局下第四页签被右侧 dock 裁断(zh_CN 交付布局不受影响);
- 保存选择器预填文件名残留上次会话名(系统 picker 记忆机制,建议名传参未被新版面板采用);
- 中文拼音组合态逐键手感仅经整串注入验证,交付前建议真手指补一轮。
因此,当前版本更准确的定位是"可日常使用的 SQLite 管理基础版":建库、浏览、改表、跑 SQL、分享与暗黑主题已在平板真机闭环,键鼠域的细节验收仍在补全路上。
▍八、总结
AirBase 的移植过程说明了一件事:当框架栈可以整体复用时,真正决定可用性的是菜单、文件、输入这些"框架认为平台自己会解决"的链路。工程把 QMenuBar 变成快照数据源、把 QFileDialog 换成系统选择器、把软键盘重建为带差分协议的编辑会话,每一条都有真机日志与视觉双通道留痕,这也是它能在一个多月内从空壳推进到日常可用的原因。
后续工作的重心集中在两处:一是 2in1 键鼠域的完整实测,把触控路径上已经验证的结论延伸到鼠标与物理键盘;二是交付前的人工体验项(拼音逐键、保存命名、布局微调)。风险登记册里 R7 一类"触摸可达性"疑问已被 M6 的正面定论关闭,剩余项大多是验证纪律问题而非功能缺口。
楼主
8 天前