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

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

适配开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_sonarqube

一、为什么要适配 SonarQube

SonarQube 是开发团队常用的持续代码质量平台。它将静态分析规则、质量门、问题跟踪、覆盖率与重复率等指标收敛到统一的工程流程中。对鸿蒙 PC 而言,适配这类工具的价值不只是“能打开一个页面”,而是让开发者能在本地项目目录发起真实扫描,并在同一台设备上完成服务连接、结果摘要查看和完整报告跳转。

SonarQube 也是一个很有代表性的适配对象。上游服务端由 Web Server、Compute Engine、Elasticsearch 和数据库等多个长时间运行部件组成,而 Scanner 又需要 Java 运行时、项目读取权限和稳定的网络链路。这与 HarmonyOS 应用沙箱、HAP 页面生命周期以及 HNP 原生包分发方式存在明显差异。因此,本次适配的核心不是强行把所有服务塞进一个应用进程,而是重新划分客户端与服务端的责任边界。

最终方案将 SonarQube 定位为“远端服务 + 鸿蒙 PC 本地客户端 + SonarScanner HNP”:服务端继续承载规则、索引、数据库与历史报告;鸿蒙端负责连接配置、本地扫描入口、质量结果查询和完整报告跳转。这条路线保留了 SonarQube 原有分析能力,也避免了应用打开时同时冷启动多个 JVM 和本地索引服务。

二、先明确产品边界:鸿蒙端不再托管完整服务端

原始 SonarQube 发行版假定它运行在稳定的服务器环境中,可以长时间占用端口、内存和磁盘,并由运维系统管理进程。鸿蒙 PC 客户端的典型使用方式不同:页面需要即时打开,关闭窗口不应改变远端平台的服务状态,扫描器则应当在真正的代码目录中运行。

本次将链路拆成四个层次:

层次主要职责鸿蒙侧实现
界面层管理服务地址、项目 Key 和当前会话 TokenArkTS 页面,仅持久化地址与项目 Key
API 层检测服务状态,读取质量门和未解决问题数@kit.NetworkKit 请求 SonarQube Web API
扫描层在本地项目目录读取源码并提交分析HNP 中的 SonarScanner CLI 与 AArch64 musl Java 21
报告层展示问题定位、度量、历史和规则详情调用系统浏览器打开远端项目仪表盘

页面不会启动 Elasticsearch、Compute Engine 或本地数据库。即使远端服务暂时不可达,客户端仍能立即进入配置页面;服务恢复后再重新检测或刷新结果即可。

三、适配后的工程结构

仓库保留 SonarQube 上游源码,与 HarmonyOS 相关的交付内容集中放在 ohos/ 目录:

ohos_sonarqube/
├── server/                                  # SonarQube 上游服务端源码
├── ohos/
│   ├── hap/
│   │   ├── AppScope/                       # 应用图标与全局资源
│   │   ├── entry/src/main/ets/
│   │   │   ├── entryability/EntryAbility.ets
│   │   │   └── pages/Index.ets              # 连接、扫描命令与结果查询页
│   │   ├── hnp/arm64-v8a/sonar-scanner.hnp # Scanner 与独立 Java 运行时
│   │   └── hnp-inject-plugin.ts           # 在签名前注入 HNP
│   └── scripts/
│       ├── sonar-scan                      # HiShell 公共命令入口
│       └── build-ohos-scanner-hnp.sh       # 组装并打包 Scanner HNP
├── OHOS_ADAPTATION_PLAN.md                # 适配边界与验收标准
└── README.OpenHarmony_CN.md                # 鸿蒙端构建与使用说明

实际数据流是一条明确的单向链路:SonarScanner 在鸿蒙 PC 读取本地项目,将分析任务提交给远端 SonarQube;远端完成规则计算和持久化后,客户端只读取必要的摘要数据。这样既避免在 HAP 中复制一套复杂报告页面,也不会将服务端的数据库和索引文件带入应用沙箱。

四、从连接配置到完整报告的真机验证

以下五张图均来自已连接的 HarmonyOS PC 2in1 真机,设备型号为 HAD-W32,系统版本为 HarmonyOS 6.1.0.117(SP78C00E100R13P3),截图分辨率为 3120×2080。测试使用 SonarQube 公开服务与公开项目数据,页面状态和 API 结果都是当时由真机实时请求返回的内容。

1. 客户端首页将三个核心环节放在同一个窗口

应用首页从左到右展示 SonarQube 地址、当前会话 Token、项目 Key 与可直接执行的扫描命令,底部则保留质量结果区域。地址和项目 Key 会持久化,Token 只保留在当前会话,不写入项目文件。

在这里插入图片描述

这种布局对实际开发流程更直接:用户不需要在多个设置页来回切换,也不需要手工拼接 sonar.projectKey 参数。页面根据当前输入生成命令,真正的源码读取仍由项目目录中的 Scanner 完成。

2. 通过标准 Web API 确认远端服务真实可用

点击“测试连接”后,客户端请求 /api/system/status。真机返回服务状态 UP,页面右上角切换为绿色的“服务器已连接”,同时显示远端 SonarQube 版本 2026.5.0.127716

在这里插入图片描述

这一步不是单纯的网页跳转。请求由 ArkTS 客户端直接发起,覆盖 HTTPS 访问、JSON 解析、状态判定和页面状态更新整条链路。对私有部署,同一请求会通过 Authorization: Bearer 头携带当前会话中的 Token。

3. HNP 中的 SonarScanner 可在 HiShell 真实执行

在真机 HiShell 中设置服务地址和测试用 Token 变量后,执行 sonar-scan -h,终端由 HNP 中的 SonarScanner CLI 返回帮助信息。

在这里插入图片描述

截图中的 usage: sonar-scanner [options] 不是页面预置文字,而是内置 Java 21 实际启动 Scanner 主类后的输出。它同时验证了 HNP 公共命令、软链接解析、AArch64 musl Java、libffi 依赖和 JVM 参数能够在目标设备上协同工作。

4. 客户端实时读取质量门与未解决问题数

“刷新结果”会分别请求项目质量门状态和未解决问题总数。测试时公开项目 sonarqube 的质量门为 OK,未解决问题数为 3222,页面状态显示“质量结果已更新”。

在这里插入图片描述

问题数会随远端项目的后续分析变化,截图保留的是此次真机验证时刻的实时结果。客户端只提取高频摘要,没有将一个可能包含数千条记录的问题列表全部塞进首页。

5. 从客户端直接进入远端完整报告

点击“打开完整报告”后,应用使用系统 viewData Ability 打开项目仪表盘。真机浏览器成功加载 SonarQube Overview,可以继续查看质量门、覆盖率、重复率、问题明细和分析历史。

在这里插入图片描述

这里的跳转保留了 SonarQube 原生页面的完整交互能力,同时让鸿蒙客户端继续保持轻量。首页适合快速判断项目状态,浏览器则承担问题定位、度量对比和治理操作,两者职责清晰。

五、适配过程中的几个关键难点

难点一:适配目标不是“原样搬运服务端”

SonarQube 服务端是长时间驻留的多进程 Java 系统,它不仅需要 Web Server 和 Compute Engine,还依赖 Elasticsearch、数据库、可写数据目录和足够的内存预留。把这套组件全部捆绑到普通 HAP,应用启动时间、后台生命周期和数据可靠性都会变得难以预期。

项目曾对本地服务端链路进行过风险验证,最终根据产品使用方式收敛为客户端方案。服务端放在适合运维的远端环境,鸿蒙 PC 保留本地 Scanner 和高频查询能力。这不是功能简单删减,而是把必须常驻的基础设施与必须贴近开发者的本地扫描正确分层。

难点二:Scanner 需要可以在 OHOS musl AArch64 上独立运行的 Java

SonarScanner CLI 本身是 Java 程序,但不能假设设备已经安装了与之兼容的桌面 JDK。项目选用 Scanner 8.0.1.6346 的 Any/JVM 分发包,并在 HNP 中附带 AArch64 musl Java 21。对 Zero VM 环境,打包脚本同时收集 libffi.so.8,启动脚本则补齐 LD_LIBRARY_PATH

运行参数也经过针对性约束:默认堆为 -Xms32m -Xmx384m,使用 -Xint,关闭压缩对象指针与压缩类指针。否则 Zero VM 可能在尚未分析代码前就为压缩类空间保留过大虚拟内存,导致真机启动失败。

难点三:避免 Scanner 再下载一份不兼容的 JRE

新版 Scanner 支持自动供应 JRE,但远端下载的常规 Linux JRE 未必与 OHOS musl 环境兼容。鸿蒙启动器显式设置 -Dsonar.scanner.skipJreProvisioning=true,强制 Scanner 使用 HNP 中已验证的 Java。这一处看似只是单个开关,实际上决定了首次扫描是否会在运行时悄然替换已适配的 JVM。

难点四:HNP 必须在正确的构建阶段进入 HAP

module.json5 中声明 hnpPackages 并不代表已有 HNP 会自动出现在最终签名包内。当前 Hvigor 打包链路不会自动向 app_packing_tool 传递 --hnp-path,如果只执行常规 assembleHap,容易得到一个页面可打开、但公共 sonar-scan 命令不存在的不完整安装包。

工程中的 hnp-inject-plugin.ts 把注入任务安排在 PackageHap 之后、SignHap 之前,用 HNP 路径重新组装未签名 HAP,再交还 Hvigor 完成整体签名。顺序不能颠倒:签名后再修改包体会破坏完整性校验。

难点五:公共命令是软链接,HNP 安装目录又不能写死

HNP 安装后,sonar-scan 是由系统注册的公共命令软链接,包体真实路径由安装服务管理。启动脚本先通过 readlink 解析自身位置,再以真实路径为基准定位 scanner/runtime/jdk/。因此命令可以从任意项目目录执行,不需要用户了解 HNP 解包路径。

难点六:Token 与项目配置的持久化策略不能一刀切

服务地址和项目 Key 适合持久化,因为它们是常用工程上下文;Token 则不应该被直接写进项目配置文件或长期显示在页面中。客户端使用 PersistentStorage 保存地址与项目 Key,Token 仅作为当前页面状态;Scanner 通过 SONAR_TOKEN 环境变量接收凭据。这种做法没有替代企业密钥管理,但避免了最常见的 Token 误入库问题。

六、构建、安装与使用

本项目的鸿蒙端由 ArkTS HAP 和 Java/Native HNP 组成,不是 Qt 或 Electron 工程。构建需要 DevEco Studio、HarmonyOS SDK、AArch64 musl Java 21,如果 Java 使用 Zero VM,还需要对应架构的 libffi.so.8

首先生成 Scanner HNP:

OHOS_JDK_DIR=/path/to/aarch64-musl-jdk21 \
OHOS_LIBFFI_PATH=/path/to/aarch64-musl/libffi.so.8 \
OHOS_SDK_PATH=/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony \
HNP_PATCH_VERSION=2 \
./ohos/scripts/build-ohos-scanner-hnp.sh

脚本默认使用 SonarScanner CLI 8.0.1.6346 Any/JVM 分发包,移除 JDK 中不影响运行的演示、文档、开发头文件和 jmods,然后通过 hnpcli 打包。产物位于:

ohos/hap/hnp/arm64-v8a/sonar-scanner.hnp

再构建携带 HNP 的签名 HAP:

cd ohos/hap
OHOS_SDK_PATH=/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony \
DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk \
/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw \
assembleHap --mode module -p product=default

最终安装包位于:

ohos/hap/entry/build/default/outputs/default/entry-default-signed.hap

连接 HarmonyOS PC 真机后安装并启动:

hdc list targets
hdc install -r ohos/hap/entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.example.sonarqube -m entry

在客户端填写服务地址、项目 Key 和当前会话 Token,然后在 HiShell 进入需要分析的项目根目录:

export SONAR_HOST_URL='https://sonar.example.com'
export SONAR_TOKEN='<your-project-token>'
sonar-scan -Dsonar.projectKey='team:project' -Dsonar.sources=.

如果项目根目录已包含 sonar-project.properties,可以直接执行 sonar-scan。Maven、Gradle 和 .NET 项目则建议继续使用 SonarQube 对应的构建插件,以便获得完整的构建上下文。

七、当前功能边界

当前版本已在 HarmonyOS PC 真机覆盖以下主链路:

  • HAP 签名安装、启动和 2in1 窗口布局;
  • SonarQube HTTP/HTTPS 地址校验与 /api/system/status 连通性检查;
  • 服务版本读取与连接状态显示;
  • 项目 Key 配置与扫描命令生成;
  • 公共 HNP 命令 sonar-scan 在 HiShell 中启动;
  • AArch64 musl Java 21 与 SonarScanner CLI 运行;
  • 质量门状态和未解决问题总数查询;
  • 系统浏览器打开完整项目报告;
  • Token 通过当前会话和环境变量传递,不写入项目文件。

边界同样需要说清。鸿蒙客户端不在本地启动完整 SonarQube Server,因此扫描提交、结果查询和报告查看都需要远端服务可达。管理规则、安装语言插件、创建项目、管理 Token、配置质量门和查看完整问题列表,仍属于远端 SonarQube 的职责。

此外,当前默认 JVM 参数主要面向稳定性和兼容性,还不代表已完成所有语言、超大仓库、低内存和长时间连续扫描的性能定型。企业环境仍应根据仓库规模调整 SONAR_SCANNER_JAVA_OPTS,并在远端配置对应语言分析插件。

八、总结

SonarQube 的鸿蒙 PC 适配证明,面对复杂服务端项目时,最重要的往往不是尽可能多地打包二进制,而是先找准平台上真正需要的使用闭环。本项目将多 JVM、索引和数据库继续留在远端 SonarQube,将必须贴近源码的 SonarScanner 以 HNP 形式带到鸿蒙 PC,再用 ArkTS 客户端串起连接、命令、结果和报告。

真机上完成的服务版本读取、Scanner 命令启动、质量门与问题数查询,以及完整报告打开,表明当前适配已经形成可用的代码质量工作流,而不只是一个可安装的界面壳。这套分层方法同样适用于其他有重量服务端的开发工具:让服务端留在适合稳定运维的位置,让本地客户端聚焦开发者真正需要的交互和运行入口。

Logo

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

更多推荐