海蒂数据库管理工具:在鸿蒙 PC 上原生打造的桌面级数据库客户端

欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/

欢迎在 PC 社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper

开源地址(AtomGit 仓库):https://atomgit.com/OpenHarmonyPCDeveloper/ohos_heidisql


数据库客户端是开发者与运维每天都在用、却总被忽视的基础设施。本文分享「海蒂数据库管理工具」(原 HeidiSQL 鸿蒙版):它在鸿蒙 PC 上用 ArkTS + ArkUI 原生重写了一个桌面级数据库客户端,并把数据库协议层交给交叉编译到 OHOS ARM64 的 C 客户端库。文章侧重技术实现——架构怎么分层、NAPI 桥怎么搭、C 库在 musl 工具链下怎么编,以及 ArkTS 领域层几个关键模块的设计取舍。

请添加图片描述

一、项目定位:原生重写,不是「移植套壳」

上游 HeidiSQL 是 Windows / Delphi 技术栈,在鸿蒙上没有任何直接复用的可能:没有 Delphi 运行时、没有 VCL、可执行文件格式也不一样。所以这里没有走「翻译源码」这条路,而是做了一个清醒的取舍——以上游功能规格为参照,用 ArkTS + ArkUI 全新原生实现界面与领域逻辑,只把真正绕不开的「数据库客户端协议」这层用 C 库解决。上游代码、文案与资源零复制,许可证沿用 GPL-2.0。

有一点需要明确:这不是「把某个 Linux 程序塞进壳里跑」。它跟 HNP 类移植不一样,是一个纯原生 GUI 应用——界面、事件循环、状态管理全部是 ArkUI 声明式范式,数据库连接是 HAP 内的 native 库,不存在独立进程、不存在 HNP、不存在终端命令。所有东西打成一个 HAP,装上就能用。

项目的四个目标:

  1. 平台补位:为鸿蒙 PC 提供一款成熟、开源、免费的图形化数据库管理工具;
  2. 原生体验:全部界面用 ArkUI 声明式范式重写,适配键鼠与高分屏,同时保持触控可用;
  3. 对齐上游核心流程:覆盖「连接管理 → 数据库浏览 → 数据查看 → SQL 查询 → 数据编辑 → 结构编辑 → 数据导出」全流程;
  4. 可持续协作:以规格驱动开发(SDD)沉淀设计与验收标准,让社区贡献有据可依。
层技术
UIArkTS + ArkUI 声明式范式(State Management V1),ArkTS 严格模式
领域逻辑ArkTS:SQL 构建、事务编排、导入导出、目录服务
数据库桥接NAPI(C++):统一 provider 接口 + MySQL / PostgreSQL / SQLite 三个实现
数据库客户端交叉编译至 HarmonyOS ARM64 的 C 库:libmariadb、libpq、sqlite3;TLS 依赖 OpenSSL
构建DevEco Studio + hvigor(API 12);native 层 CMake + OHOS LLVM 工具链(musl)

功能特性(主线,MySQL / MariaDB):

  • 会话管理:新建 / 编辑 / 保存 / 删除 / 复制连接会话,连接前测试连接;密码经系统安全能力加密存储;
  • 数据库树:实例 → 数据库 → 表 / 视图分层导航,右键快捷操作;
  • 数据网格:浏览 / 编辑双模式,列宽拖拽、快速过滤;行内编辑 + 批量事务提交(提交 / 回滚),脏数据守卫;新增行自动列裁剪;无主键表编辑风险告警;BLOB / TEXT 大字段专用编辑器(文本 / 十六进制切换);
  • SQL 编辑器:语法高亮、SQL 执行与结果面板、查询历史;
  • 结构管理:字段编辑、索引与外键 DDL 编辑、DDL 查看、字段类型映射;
  • 对象与运维:数据库 / 表对象编辑器、用户管理、偏好设置;
  • 数据导入导出:SQL / CSV 导出、CSV 导入。

二、架构分层与工程结构

整个系统的分层很干净:ArkTS 管一切看得见的,C 库只管协议,NAPI 做桥。

┌──────────────────────────────────────────────┐
│  pages/        ArkUI 页面(会话管理/工作台…)  │
├──────────────────────────────────────────────┤
│  viewmodel/    SQL 构建、事务编排、导入导出    │
│  catalog/      数据库树目录服务               │
│  editor/       SQL 编辑器与语法高亮           │
│  model/        会话、连接参数、安全存储        │
├──────────────────────────────────────────────┤
│  dbclient/     连接注册表(ArkTS 侧)         │
├──────────────────────────────────────────────┤
│  cpp/          NAPI 桥接:db_provider 统一接口 │
│                ├ mysql_provider(libmariadb) │
│                ├ postgres_provider(libpq)   │
│                └ sqlite_provider(sqlite3)   │
├──────────────────────────────────────────────┤
│  native/       交叉编译 ARM64 .so(musl 兼容)│
└──────────────────────────────────────────────┘

对应的工程目录:

ohos_HeidiSQL/                          # 工程根目录(DevEco Studio 打开这个)
├── build-profile.json5                 # 工程级构建配置(SDK 版本 / 签名配置)
├── AppScope/                           # 应用级配置(bundleName / 图标 / 显示名)
├── entry/                              # 主模块(整个应用就是一个 HAP)
│   └── src/main/
│       ├── module.json5                # 设备类型(含 2in1)、INTERNET 权限、Ability 声明
│       ├── cpp/                        # NAPI 桥接层(C++,编成 libdbclient.so)
│       │   ├── db_provider.h / .cpp    # 数据库 provider 统一接口(连接/查询/转义…)
│       │   ├── mysql_provider.cpp      # MySQL / MariaDB 实现(真实驱动 libmariadb)
│       │   ├── sqlite_provider.cpp     # SQLite 实现(桩,待恢复完整实现)
│       │   ├── postgres_provider.cpp   # PostgreSQL 实现(桩,待恢复完整实现)
│       │   └── napi_init.cpp           # NAPI 模块注册(ArkTS ↔ C++ 全部入口)
│       └── ets/
│           ├── entryability/           # EntryAbility(PC 窗口尺寸适配就在这)
│           ├── pages/                  # 20 个 ArkUI 页面(工作台/数据网格/SQL 编辑器…)
│           ├── viewmodel/              # SQL 构建、行编辑缓冲、导入导出等领域逻辑
│           ├── catalog/                # 数据库树目录服务
│           ├── editor/                 # SQL 语法高亮与关键字表
│           ├── model/                  # 会话模型 / HUKS 加密存储 / 偏好设置
│           └── dbclient/               # 连接注册表(ArkTS 侧持有 native 连接句柄)
└── native/                             # C 库交叉编译配套(跟 HAP 构建解耦)
    ├── build/
    │   ├── env.sh                      # OHOS 工具链环境变量(clang / sysroot / lld)
    │   └── build_libs.sh               # 一键交叉编译 6 个 C 库的主脚本
    ├── compat/
    │   └── musl_compat.h               # glibc 扩展符号在 musl 下的兼容桩
    └── prebuilt/arm64-v8a/             # 交叉编译产物(.so + 头文件)

这条路线最大的好处是双向隔离:数据库客户端库以预编译 .so 随 HAP 分发,运行时靠 -Wl,-rpath,$ORIGIN 就近加载;领域逻辑全部在 ArkTS 层,换数据库只动 provider 一层,UI 一行不改;反过来 ArkTS 侧的演进也不触碰 C 库。

连接链路从前台一路贯通到 native 层:

EntryAbility(主窗口 1280×800)
    └── MainWindowPage
          ├── SessionManagerPage        # 会话管理
          │     └── SecureSecretStore    # HUKS 密码加密
          └── WorkbenchPage             # 工作台
                └── DbConnection / ConnRegistry     # ArkTS 连接注册表
                      └── NAPI: libdbclient.so
                            └── DbProvider 统一接口
                                  ├── mysql_provider    → libmariadb
                                  ├── sqlite_provider   → sqlite3(待集成)
                                  └── postgres_provider → libpq(待集成)

三、跨语言桥接:NAPI 怎么把 C 库变成 ArkTS 可用的对象

3.1 统一 Provider 接口

C++ 侧的核心抽象是 DbProvider 纯虚接口,把三种数据库统一成同一套方法:

class DbProvider {
public:
  virtual bool Connect(const std::map<std::string, std::string>& params, std::string& err) = 0;
  virtual void Disconnect() = 0;
  virtual bool Ping(std::string& err) = 0;
  virtual std::string GetServerVersion() = 0;
  virtual std::string GetServerInfo() = 0;
  virtual std::string EscapeString(const std::string& s) = 0;
  virtual ResultSet Query(const std::string& sql) = 0;
  virtual bool IsConnected() = 0;
};

工厂按 kind 分发(mysql / mariadb / postgres / postgresql / sqlite / sqlite3),ArkTS 侧完全不关心底层是哪种库:

std::shared_ptr<DbProvider> CreateProvider(const std::string& kind) {
  if (kind == "sqlite" || kind == "sqlite3")        return CreateSqliteProvider();
  if (kind == "mysql"  || kind == "mariadb")        return CreateMysqlProvider();
  if (kind == "postgres" || kind == "postgresql")   return CreatePostgresProvider();
  return nullptr;
}

3.2 句柄路由:跨语言生命周期怎么管

NAPI 层用全局连接表 + 自增整型句柄把对象生命周期管起来。C++ 侧每个连接持有一个 std::shared_ptr<DbProvider>,只把一个 int32_t 句柄返回给 ArkTS,后续所有调用通过句柄路由,全局表用互斥锁保护:

std::mutex g_mutex;
std::map<int32_t, std::shared_ptr<heidi::DbProvider>> g_conns;
std::atomic<int32_t> g_nextHandle{1};

一个细节:RemoveProvider 会把 shared_ptr 先移出表、在锁外析构,避免 Provider 析构时回调上层再抢同一把锁造成死锁。

ArkTS 侧再用 DbConnection 把它包成面向对象的形式,上层业务不感知任何 NAPI 细节:

const conn = new DbConnection('mysql');
conn.connect({ host: '10.0.2.2', port: '3306', user: 'root', password: '***', database: 'test' });
const rs = conn.query('SELECT id, a FROM test.test;');
conn.close();

ConnRegistry 则在页面之间按 id 分发连接(registerConn / getConn / unregisterConn)。

3.3 ResultSet 归一化

ResultSet 的结构设计是这套桥接能"一次写、三库通用"的关键:所有列值统一以字符串承载,且额外带一份与行同形状的 NULL 标记数组:

struct ResultSet {
  std::vector<Column>                       columns;
  std::vector<std::vector<std::string>>     rows;
  std::vector<std::vector<bool>>            nulls;   // true 表示 NULL
  int64_t      affectedRows = 0;
  int64_t      insertId     = 0;
  bool         ok           = true;
  std::string  error;
  std::string  sqlState;
  int32_t      errorCode    = 0;
};

好处是把类型转换问题后置到 ArkTS 侧按列类型自行解析,native 层不必为每个库维护不同的返回值结构;NAPI 出口时再把 nulls 为真的位置转成 JS 的 null。列元信息(dbTypeName / type / nullable / isPrimaryKey / maxLength)也一并带出,直接支撑上层的编辑与结构管理。

模块注册就是一张方法表,九个入口:

static napi_value Init(napi_env env, napi_value exports) {
  napi_property_descriptor desc[] = {
    {"create", nullptr, M_Create, ...}, {"connect", ...}, {"disconnect", ...},
    {"destroy", ...}, {"ping", ...}, {"getServerVersion", ...},
    {"getServerInfo", ...}, {"escapeString", ...}, {"query", ...},
  };
  napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
  return exports;
}

四、协议层:6 个 C 库在 musl 工具链下的交叉编译

界面可以重写,数据库协议不必重造轮子。libmariadb / libpq / sqlite3 都是成熟 C 库,只要能交叉编译到 OHOS ARM64,协议层就交给它们。

4.1 工具链封装(native/build/env.sh)

所有构建脚本只从这一个文件取环境:SDK 自带 LLVM/Clang、--sysroot 指向 musl sysroot、链接器 ld.lld。其中两个变量必须并存,这是最容易踩的坑:

# autoconf 系工程的 --host 只认标准三元组
export TARGET_HOST="aarch64-linux-gnu"
# clang 的 --target 用 ohos 三元组
export TARGET_TRIPLE="aarch64-linux-ohos"

export TARGET_FLAGS="--target=$TARGET_TRIPLE --sysroot=$SYSROOT -D__linux__ -D__MUSL__ -fPIC"
export LDFLAGS="--target=$TARGET_TRIPLE --sysroot=$SYSROOT -fuse-ld=$LLVM_BIN/ld.lld"

两个自定义宏很关键:-D__linux__(musl 上部分头文件靠它才暴露 API)、-D__MUSL__(自己的桩与补丁全靠这个宏切换分支)。

4.2 版本锁定的 6 个库

脚本按「先依赖后主库」的顺序编译,版本全部写死,保证可复现:

顺序库版本说明
1SQLite3.46.0纯 C amalgamation,一条 clang 命令编成 .so(开 FTS5 / JSON1 / RTREE)
2libiconv1.17libpq 的字符集依赖,手工 lld 链接(libcharset + libiconv 两个 .so)
3libintlgettext 0.22.5只编 gettext-runtime 子集,libpq 依赖
4OpenSSL3.3.1libmariadb / libpq 的 TLS 依赖
5libpqPostgreSQL 15.7只编 src/interfaces/libpq,不编 server 端
6libmariadb3.3.3MySQL / MariaDB 客户端,认证插件全部静态链接

脚本本身是幂等的:源码包已存在则跳过下载、已解压则跳过解压、产物已存在则跳过编译,全流程可重复执行。

cd native/build
./build_libs.sh all            # 按依赖顺序编译全部库
./build_libs.sh libmariadb     # 也可单独编某一个
OHOS_SDK_PATH=/path/to/sdk ./build_libs.sh all   # 指定 SDK 路径

4.3 musl 兼容桩(native/compat/musl_compat.h)

libmariadb / libpq / OpenSSL 这类库默认按 glibc 假设编译,交叉链接时会报一串 undefined symbol。逐个改库源码既脏又不可持续——每个库每个版本都要重新打补丁。最终解法是一个兼容桩头,通过 -include 强制注入到所有编译单元,对 glibc 专有符号提供空桩或等价实现:

符号处理
backtrace / backtrace_symbolsmusl 无 <execinfo.h>,libmariadb 崩溃诊断路径会引用,提供空桩
malloc_usable_sizeglibc 扩展,用于内存统计,返回 0
program_invocation_name / program_invocation_short_nameglibc 全局变量,声明为外部符号
__libc_current_sigrtmin / sigrtmaxPostgreSQL 代码路径引用,返回常量
secure_getenvmusl 无,转发到 getenv
PTHREAD_MUTEX_ADAPTIVE_NP / ROBUST_NP缺失宏,补 0

库源码零改动,升级库版本时不需要重新维护补丁集。

4.4 单库的特殊处理

OpenSSL 3.3.1:不走 autoconf,用自己的 Configure——平台选 linux-aarch64,shared no-tests no-asm 减少坑面;安装阶段要 unset CROSS_COMPILE,否则 make install 会拿交叉前缀去找本机不存在的工具。

libmariadb 3.3.3(坑最多的一个),三处处理:

  • CMAKE_SYSTEM_NAME=Linux 必须显式指定,否则 CMake 在 macOS 上把它检测成 Darwin,交叉编译直接翻车;
  • 交叉环境下 FIND_PACKAGE(OpenSSL) 内部的 TRY_RUN 无法执行,OPENSSL_FOUND 拿不到值、TLS 支持会被静默裁掉——脚本用 sed 往它的 CMakeLists 注入一段 OHOS_CROSS_COMPILE_HACK,跳过探测、直接注入头文件与库路径;
  • 认证插件全部静态链接(CLIENT_PLUGIN_caching_sha2_password=STATIC 等)。这是真机上最容易撞上的坑:MySQL 8+ 默认认证就是 caching_sha2_password,插件若靠动态加载,运行时在应用沙箱里找不到插件文件,连接直接报错;GSSAPI 等单机用不到的直接 OFF。

libpq 15.7:--without-readline --without-zlib 砍掉不必要依赖、--with-openssl 接 TLS,只编客户端接口层;链接时需要 -Wl,-rpath-link,$PREFIX/lib 才能找到刚编出来的 libssl / libiconv。

4.5 组包与就近加载

NAPI 模块的 CMake 指向 native/prebuilt/arm64-v8a/,链接 sqlite3 / mariadb / ssl / crypto 加 SDK 的 ace_napi.z / hilog_ndk.z,并用 POST_BUILD 把运行期依赖的 .so(含 mariadb 插件目录)自动拷进 libdbclient.so 同目录:

target_link_options(dbclient PRIVATE "-Wl,-rpath,\$ORIGIN")
add_custom_command(TARGET dbclient POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_directory
          "${PREBUILT_DIR}/lib" "$<TARGET_FILE_DIR:dbclient>"
  ...)

运行时靠 $ORIGIN 就近加载——HAP 自包含,设备上不需要任何预装库。

4.6 MySQL 8 认证失败的可读错误

真机连库失败时,最好别把 mysql_error 原样抛给用户。MysqlProvider::Connect 会识别错误特征并给出可操作的提示:

if (originalErr.find("caching_sha2_password") != std::string::npos ||
    originalErr.find("Authentication plugin")  != std::string::npos) {
  err = "MySQL 8.0+ 使用 caching_sha2_password 认证失败。请确认:"
        "1) libmariadb.so 已静态链接该插件(重新运行 build_libs.sh libmariadb);"
        "2) OpenSSL 已正确链接。也可在服务器端执行:"
        "ALTER USER '用户名'@'主机' IDENTIFIED WITH mysql_native_password BY '密码';";
}

五、ArkTS 领域层的几个关键设计

5.1 SQL 编辑器:自研词法高亮

编辑器没有依赖现成高亮库,而是写了一个词法扫描器 SqlHighlighter.ets:把 SQL 切成 token 序列,识别空白、单行 / 多行注释、字符串字面量、反引号 / 双引号标识符、数字(含十六进制与科学计数法)、关键字、数据类型、函数名(通过后跟 ( 判定)与标点,再按 token 类型生成带颜色的 HTML 交给 RichText 渲染。关键字字典按 SQL 标准 + 各库扩展关键字的子集维护,明暗双主题各有一套色板。

配套的 SqlExecutor 负责按 ; 拆多语句并逐条执行:拆分时会尊重字符串 / 注释 / 引号内的分号(词法级拆分,不做完整 SQL 解析),执行时统计每条语句的耗时、影响行数与错误,支持「首条失败即中止后续」;失败时带回 sqlState 与 errorCode,便于定位。

const { results, summary } = executor.execute(sql, /* abortOnError */ true);
// summary: { totalStatements, successCount, failedCount, totalElapsedMs, aborted }

5.2 数据网格:一条数据从服务端到屏幕

数据网格是数据库工具的体验核心,它的数据流由 DataGridLoader 管理,不是「SELECT * 一把梭」。一次刷新分三步:

  1. 探针查询拿列结构:首次进入用 LIMIT 0, 1 探一次,拿到列名、类型、是否主键、最大长度;
  2. 分页取数据:按 pageSize(默认 100)构造 SELECT ... LIMIT n OFFSET m;
  3. 单独统计总数:另发一条 SELECT COUNT(*) 得到总行数,驱动分页控件。

同时接入了排序、过滤与长文本截断,SQL 全部在 ArkTS 侧拼接:

SELECT <列清单> FROM `db`.`table` WHERE <过滤条件> ORDER BY `col` DESC LIMIT 100 OFFSET 0

两个值得注意的细节:

  • 长文本截断:对 TEXT / JSON / Enum / Set 等文本类列,若 maxLength 超过阈值(1000)或未知,用 LEFT(col, 1000)(SQLite 用 SUBSTR)只取前 1000 字节,避免把超大字段整个拉回内存拖垮网格;
  • 过滤操作符:eq / ne / like / notlike / gt / lt / gte / lte / isnull / isnotnull / raw,数值列走数字比较、文本列走转义后的引号比较,还支持直接写原生 WHERE 子句。

5.3 行编辑缓冲区:桌面级编辑的「脏数据」模型

数据网格支持行内编辑 + 批量事务提交 / 回滚,核心是 RowEditBuffer。它把用户在网格上的改动先暂存,点「提交」前不写库,点「回滚」丢弃全部待提交编辑:

export interface PendingEdit {
  rowKey: string;                 // 行的唯一 key
  op: 'update' | 'insert' | 'delete';
  original: (string | null)[];    // 原始值(UPDATE/DELETE 用)
  current: (string | null)[];     // 编辑后的值
  changedColumns: Set<string>;    // 被改过的列
}

几个关键决策:

  • rowKey 生成:优先用主键列值拼接;无主键时退化为全部列值拼接——这也是「无主键表只能受限编辑」的由来;
  • 值语义约定清晰:空串 '' 原样写缓冲,NULL 只能通过显式的「设为 NULL」入口写入;数值列的空串在生成 SQL 时兜底按 NULL 处理;
  • INSERT 列裁剪:从未被触碰的列不出现在插入列清单里,自增列 / 有默认值的列交由数据库端生成,避免 INSERT 时误写 0 或空串污染自增主键;
  • 提交顺序固定:INSERT → UPDATE → DELETE,并用单个事务包起来(BEGIN → 逐条 → 失败 ROLLBACK → COMMIT),任一语句失败即整体回滚并把失败语句序号带回。

applyEditBuffer 里还有个小而实用的设计:对 update / delete 影响 0 行的语句,不当作失败,而是收集进 zeroRowWarnings 提示「目标行可能已被其他用户修改或删除」——本质上是一个轻量的并发冲突信号。

请添加图片描述

5.4 SQL 生成与三方方言适配

编辑缓冲最终由 SqlBuilder 变成 SQL 字符串,核心是按列类型格式化值 + 按方言引用标识符:

private formatValue(v: string | null, col: Column): string {
  if (v === null) return 'NULL';
  if (v === '' && (col.type === Integer || col.type === Real)) return 'NULL';
  if (col.type === Integer || col.type === Real) {
    if (/^-?\d+(\.\d+)?$/.test(v)) return v;   // 合法数字不加引号
  }
  return "'" + this.conn.escapeString(v) + "'";
}

标识符引用按方言区分:MySQL / MariaDB 用反引号 `ident`,PostgreSQL / SQLite 用双引号 "ident"。这种差异在 AlterTableBuilder(结构管理的 DDL 生成)里体现得更明显:

能力MySQL / MariaDBPostgreSQLSQLite
MODIFY 列一条 MODIFY COLUMN 整列重写拆成多条 ALTER COLUMN TYPE / SET NOT NULL / SET DEFAULT / RENAME不支持,提示重建表
自增AUTO_INCREMENT用 SERIAL 类型表达依赖 INTEGER PRIMARY KEY
DROP 列直接 DROP COLUMN直接 DROP COLUMN3.35+ 才支持,老版本受限

方言差异集中在 SQL 构建层、UI 完全不感知——这也是后面接入 PostgreSQL / SQLite 时改动能收敛在 viewmodel 层的原因。

请添加图片描述

5.5 密码安全存储(HUKS)

SecureSecretStore 基于 @ohos.security.huks 实现,替代 Windows 上的 DPAPI 思路:

  • 密钥由 HUKS 生成并持久化存储,密钥永不出 HUKS,加解密都在 HUKS 内部完成;
  • 算法 AES-256-GCM,12 字节随机 IV + 16 字节认证标签;
  • 密文按 Base64(IV + ciphertext + tag) 拼接存储,每条密文独立;
  • 解密失败(密钥变更或数据被篡改)直接抛异常,不静默返回脏数据。

5.6 PC 交互适配

「让它像桌面应用、而不是大号手机应用」是重点投入的部分:

  • module.json5 的 deviceTypes 显式声明 2in1,随通用设备一起安装;
  • EntryAbility.onWindowStageCreate 里主窗口拉起即设为 1280×800,符合桌面工作区习惯;
  • 键鼠交互对齐桌面习惯:数据库树与表格的右键上下文菜单(ContextMenuHelper)、数据网格列宽拖拽(ColResizeHandle)、多级树形导航;
  • 全程 ArkTS 严格模式(禁 any、禁对象字面量类型推断、禁动态属性访问),倒逼出 pages / viewmodel / model / dbclient / catalog 的清晰分层。

六、环境要求与构建步骤

项目要求备注
IDE / SDKDevEco Studio(含 HarmonyOS SDK)提供 OHOS LLVM/Clang、musl sysroot、hvigor、CMake
compatibleSdkVersion5.0.0(12)见 build-profile.json5
targetSdkVersion6.1.1(24)实际编译目标版本
交叉编译工具cmake、make、curl、tar、xz、unzipcmake 优先用 SDK 自带
目标设备2in1(鸿蒙 PC)及通用设备deviceTypes = ["default", "2in1"]
权限ohos.permission.INTERNET连接远程数据库必需,已在 module.json5 带用途说明声明

整个流程是「交叉编译 C 库 → 构建签名 HAP → 装到鸿蒙 PC」:

# 1. 交叉编译数据库客户端 C 库
cd native/build && ./build_libs.sh all

# 2. 构建签名 HAP(DevEco 里 Signing Configs 点 Fix 生成调试签名后 Run,或命令行)
hvigorw assembleHap

# 3. 安装并启动
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap

产物落在 native/prebuilt/arm64-v8a/(.so + 头文件),native 依赖库全部随 HAP 打包,单文件即可分发安装。


七、当前能力状态(T0 / T1 / T2)

状态只有三种含义:已完成(代码在仓库里,按上文可复现构建)、桩 / 未集成(接口就位、依赖脚本备好,属排期问题)、暂不计划(对齐上游 Roadmap 的主动取舍)。

T0 基础能力(能不能编、能不能装、能不能起)—— 全部完成:交叉编译工具链封装完毕;SQLite / OpenSSL / libmariadb 交叉编译产物就绪;libpq / libiconv / libintl 脚本就绪;NAPI 统一桥接层与 HAP 构建通过;2in1 设备适配完成。

T1 主要能力(MySQL / MariaDB 主线)—— 已完成:会话管理、真实连接(native_password + caching_sha2_password 认证、可选 TLS)、数据库树导航、数据浏览与编辑、SQL 查询、结构管理、导入导出、对象与运维,全链路就位。

T2 待办与取舍:SQLite 与 PostgreSQL 两个后端为桩实现——libsqlite3.so 已交叉编译并链接进 libdbclient.so,libpq 构建脚本就绪,属于「恢复实现」的工作量,不存在架构性堵点;SSH 隧道与 MSSQL / Interbase / Firebird 暂不计划。

需要如实说明的边界:数据编辑的批量提交依赖目标表具备主键或唯一键,无主键表提供的是带风险告警的受限编辑。


八、开源与合规

  • 本项目遵循 GPL-2.0,与上游 HeidiSQL 一致;
  • 第三方组件及其许可证:
组件用途许可证
libmariadbMySQL / MariaDB 客户端LGPL-2.1(动态链接)
libpqPostgreSQL 客户端PostgreSQL License
SQLiteSQLite 客户端Public Domain
OpenSSLTLSApache-2.0
libiconv / libintllibpq 依赖LGPL
  • 关系声明:HeidiSQL 名称与上游项目版权归原权利人所有;本移植项目仅为功能规格层面的参照实现,未复制上游源码与资源。
  • 开发流程采用规格驱动(SDD):以 spec/<feature>/ 组织 spec.md(需求与验收标准)→ plan.md(技术方案)→ tasks.md(任务清单),让社区贡献有据可依。

九、总结

海蒂数据库管理工具把「原生重写」这条路走通了:界面与领域逻辑用 ArkTS / ArkUI 原生实现,协议层交叉编译成熟的 C 客户端库,NAPI 做桥,最终打成单一 HAP,装上即用——不存在独立进程或终端命令,是真正的原生桌面 GUI 应用。

回头看有三点经验值得同类项目借鉴:

  • 能复用的协议层绝不重写:libmariadb 这类 C 库在 musl 工具链下的坑(三元组、TRY_RUN、认证插件)虽多,但全部可以收敛进一个幂等脚本和一个兼容桩头,一次解决、次次复用;
  • 原生重写的成本大头在交互密度而非页面数量:数据网格一个组件的工作量接近全局三分之一,但这正是「桌面工具」与「手机套壳」的分水岭;
  • 适配状态要按用户路径如实标注:能启动不等于能连接,界面出现不等于功能闭环——T0 / T1 / T2 的划分就是为了把「已验证的」与「待完成的」说清楚。

开源鸿蒙 PC 需要的正是这类日常基础设施软件。项目代码已托管在 AtomGit,无论是 SQLite / PostgreSQL 后端集成、数据网格性能打磨,还是新场景的适配反馈,都欢迎参与共建。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐