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

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

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

一、为什么要适配 sbt

sbt 是 Scala 生态的主流构建工具,同时也能管理 Java 以及其他 JVM 项目。依赖解析、增量编译、测试、运行、打包和插件扩展都由它统一编排。对开发者来说,sbt 不只是一个可执行命令,它还是 Scala 工程与 Maven 仓库、编译器、测试框架和构建缓存之间的连接层。

鸿蒙 PC 要形成完整的开发者工具生态,不能只解决应用界面和原生编译问题,还需要承接已有的 JVM 工程。适配 sbt 的直接价值,是让开发者能在鸿蒙 PC 上继续使用熟悉的 compiletestrunpackage 流程;更深一层的价值,则是验证 JDK、POSIX shell、公共 HNP、应用沙箱、依赖缓存与真机终端能否组成一条可持续交付的工具链。

本次适配没有把 sbt 改写成 ArkTS 图形应用。sbt 的核心价值在命令行构建语义,重写界面无法替代 JVM 上已经成熟的任务引擎。项目因此采用“JVM-only 命令行发行包 + HAP/HNP 安装入口”的路线:核心 sbt 保持上游实现,由 BiSheng JDK 17 提供运行时,鸿蒙工程则负责安装、命令注册、用户指引和终端交付。

二、先确定边界:sbt 是构建服务,不是界面进程

sbt 的启动链表面上只有一条命令,实际上要同时满足 JVM、launcher、项目定义、依赖仓库、缓存目录和 shell 环境等多个条件。如果只把 sbt-launch.jar 复制到设备,用户仍然可能因为没有 Java、主目录不可写、缓存不完整或 shell 不兼容而无法开始一次构建。

当前实现将这条链路分成四层:

层次核心问题鸿蒙侧实现
JVM 运行层sbt 需要可用的 Java 17使用 BiSheng JDK 17 HarmonyOS 版,随公共 HNP 安装
命令入口层目标终端不应强依赖 Bash生成 POSIX sh 主入口,保留上游 launcher 作为内部实现
构建数据层boot、Ivy、Coursier 和用户配置需要稳定可写目录显式设置 user.homeSBT_CONFIG_HOMESBT_LOCAL_CACHE 及 Coursier 缓存
安装交付层JDK 和 sbt 命令需要进入真实用户终端HAP 携带 bishengjdk17_0_13_06.hnpsbt.hnp,安装后由系统提供公共命令

这个设计还明确区分了“安装壳”与“构建引擎”。BundleName 为 org.scala.sbt.ohos 的 ArkUI 应用提供工具介绍、使用提示和 HNP 载体;真正的编译和测试在 HiShell 中由 JDK 和 sbt 进程完成。关闭工具箱页面不会改变构建工具的命令行定位。

三、鸿蒙版本的工程结构

仓库保留 sbt 上游的 Scala/Java 源码和标准构建模块,鸿蒙 PC 适配集中在 scripts/ohos/notes/ 中:

ohso_sbt/
├── build.sbt                              # sbt 主构建定义
├── main/ main-actions/ main-command/     # sbt 主程序与命令引擎
├── launcher-package/                     # launcher 与传统发行包逻辑
├── client/                               # sbt client / sbtn 相关模块
├── scripts/
│   ├── package-harmonyos-pc.sh           # 生成 JVM-only 发行包和可选 HNP
│   ├── assemble-harmonyos-pc-release.sh  # 组装 JDK、缓存、sbt 与交付产物
│   ├── prewarm-harmonyos-pc-cache.sh     # 预热 sbt boot 与 Coursier 缓存
│   ├── harmonyos-pc-preflight.sh         # 设备环境预检
│   ├── harmonyos-pc-smoke-sh.sh          # POSIX sh 端到端验收
│   └── deploy-harmonyos-pc-package.sh    # hdc 部署与检查
├── ohos/
│   ├── AppScope/                         # 应用名称、图标与 Bundle 配置
│   ├── entry/src/main/ets/               # ArkUI 工具箱界面
│   ├── entry/src/main/resources/         # 文案、图片与开源声明
│   └── build-profile.json5               # HarmonyOS 6.0.2(22) 构建配置
└── notes/                                 # 适配、迁移、使用与真机验收记录

从源码到设备的交付关系可以概括为:

sbt 源码 / sbt-launch.jar
    └── POSIX sh 发行包
          ├── runtime/jdk 或 BiSheng JDK 公共 HNP
          ├── runtime/cache/sbt 预热缓存
          └── sbt 公共 HNP
                 └── 随 ArkUI HAP 统一签名安装
                        └── HiShell 中执行 compile / test / run / package

当前发行链路使用 sbt 2.0.0 稳定 launcher,真机 Java 运行时为 BiSheng JDK 17.0.13+6,目标架构为 aarch64。源码仓库本身仍可按上游方式演进,平台特定内容主要停留在包装与交付层,避免将鸿蒙分支变成难以同步的平行实现。

四、真机上的五个核心功能验证

以下五张图均在已连接的 HarmonyOS PC 2in1 真机上重新启动和执行后截取,原始屏幕分辨率为 3120×2080。命令由设备上的 HiShell 执行,图中的编译、下载、测试和打包输出都来自当次真机运行。

1. HAP 工具箱能够在鸿蒙 PC 正常启动

安装后启动 org.scala.sbt.ohos 的 EntryAbility,系统打开“OHOS sbt”工具箱窗口。页面没有把 sbt 伪装成图形化编译器,而是清楚列出 compileruntestpackage 与内置 JDK/缓存信息,并引导用户进入 HiShell。
在这里插入图片描述

这一屏验证了已签名 HAP 的安装状态、Stage 模型 Ability 启动、桌面浮动窗口和 ArkUI 资源加载。当前应用版本为 1.0.1,目标与兼容 SDK 均为 HarmonyOS 6.0.2(22)

2. 验证 JDK、编译器与 sbt 命令入口

在真机 HiShell 中执行 java -versionjavac -versionsbt --script-version。终端返回 BiSheng OpenJDK 17.0.13+6javac 17.0.13 与 sbt 2.0.0

在这里插入图片描述

这一组输出说明 HAP 内声明的两个公共 HNP 已被系统识别,JDK 运行时和 sbt 命令也已进入真实用户终端的可用路径。它验证的不是页面中的版本文字,而是设备上实际启动的 JVM 和命令入口。

3. Scala 项目能够执行清理与编译

进入真机用户目录中的 Scala 示例工程,执行 sbt clean compile。sbt 加载项目定义后完成 clean 与 compile,两个任务都以 [success] 结束,编译阶段同时命中了已预热的磁盘构建缓存。

在这里插入图片描述

截图中可以看到 JLine 原生库在用户存储目录解压时遇到权限警告。当前命令行路线会回退到非原生终端实现,因此批处理编译继续完成。这个警告不应被隐藏:它不阻断当前的构建主流程,但也说明原生 JLine 和完整交互式终端仍是后续要单独解决的能力。

4. 依赖解析、测试编译与 MUnit 用例完成闭环

为避免只展示已缓存的编译结果,本次在真机上重新运行 POSIX sh smoke test。过程实际访问 Maven 仓库解析 Scala 3.7.3、MUnit 及其依赖,随后编译主源码和测试源码,执行 MainSuite 中的 message 用例。

在这里插入图片描述

最终输出为 Passed: Total 1, Failed 0, Errors 0, Passed 1,并打印 HarmonyOS PC sh smoke test completed.。这一步同时覆盖了网络仓库访问、Coursier 解析、Scala 编译器、测试代码编译和测试运行器。终端上方偶发的 tput 提示来自颜色/终端能力检测,不影响测试结果。

5. 主程序运行与 JAR 打包产物同时验证

最后在同一真机项目中执行 sbt run package,并查找 target 下实际生成的 JAR。主程序打印 sbt command installed by HarmonyOS Apprunpackage 均以 [success] 结束,随后列出了根项目的 SNAPSHOT JAR 以及编译桥产物。

在这里插入图片描述

这张图把“命令存在”与“能产生有效构建结果”区分开来。真机不仅启动了 sbt,还真正加载编译后的用户程序并完成打包,因此形成了从项目定义到运行与产物的最小闭环。

五、适配过程中最棘手的几个问题

难点一:先有可用 JVM,才谈得上 sbt

sbt 本身大部分是平台无关的 JVM 代码,但“字节码跨平台”不等于“拷贝 JAR 就能使用”。已连接设备的调试 shell 最初不包含 Java,用户终端也不应依赖开发机的临时目录。项目最终将 BiSheng JDK 17 HarmonyOS 版组装为公共 HNP,与 sbt.hnp 一起由 HAP 声明和安装。

这种做法把 Java 运行时从“用户自行摆放的前置条件”收敛为“应用交付的可验证组件”。安装后可以同时检查 javajavacsbt,不再把 JDK 缺失留到用户第一次构建时才暴露。

难点二:开发机有 Bash,目标终端未必有

上游 sbt Unix 启动脚本使用了 Bash 语法,而鸿蒙 PC 的基础终端环境不能默认提供 Bash。如果将上游脚本原样暴露给用户,sbt 会在 Java 启动之前就失败。

包装脚本因此生成新的 bin/sbt POSIX sh 入口,上游脚本保留为 bin/sbt-launcher。真机 smoke test 也提供专门的 harmonyos-pc-smoke-sh.sh,用实际编译和测试验证主路径没有暗中依赖 Bash。这比只检查脚本首行是否写着 /bin/sh 更可靠。

难点三:用户主目录与构建缓存不能交给 JVM 自行猜测

sbt 启动后会使用多组可写目录:JVM 的 user.home、sbt boot 目录、Ivy 仓库、Coursier 缓存和用户配置。HarmonyOS 的用户、沙箱和终端路径与传统 Linux 发行版并不完全相同,直接调用 launcher 容易把缓存写到不存在或不稳定的位置。

新入口会显式设置用户名、主目录、sbt 配置和本地缓存,发行包还可以携带 runtime/cache/sbt 作为首次启动的缓存种子。截图中的 disk cache hits 证明缓存路径已被真正使用;同时,重新下载 MUnit 依赖的测试又证明缓存并没有把在线解析能力变成只读快照。

难点四:公共 HNP 必须真正进入最终 HAP

生成 sbt.hnp 和 JDK HNP 只是中间步骤。最终 HAP 必须在 module.json5 中声明两个公共包,并在签名前将它们组装进安装包。否则页面可以正常启动,但用户终端中不会出现 javasbt

当前真机包的 Bundle 信息中能够同时查到 bishengjdk17_0_13_06.hnpsbt.hnp,安装后的公共命令链接也能启动 sbt。这一验证是 HAP/HNP 交付的关键门禁,不能用“本地已生成 HNP 文件”代替。

难点五:JVM 主链路可用,不代表所有 Native 边缘能力自动兼容

sbt 的构建引擎能够纯 JVM 运行,但 JLine、原生终端交互、native sbtn 和部分插件可能携带平台原生库。真机中 JLine 动态库因用户存储目录的执行权限受限而回退,批处理任务仍能通过;但这不能被解读为所有原生扩展都已经兼容。

项目当前默认使用 JVM server,不把 native sbtn 作为核心流程的前置条件。这一取舍让编译、测试、运行和打包先形成可用基线,同时保留了对 Native ABI 问题的真实边界。

六、构建、安装与运行

这个项目不属于 Electron 或 Qt,开发机主要需要 sbt 自身的构建环境、HarmonyOS/OpenHarmony SDK、DevEco Studio/Hvigor、HNP 打包工具与可用的 BiSheng JDK HarmonyOS 产物。

如果已有 BiSheng JDK HarmonyOS 的 tar 包,可以组装命令行发行包并同时生成 HNP:

scripts/assemble-harmonyos-pc-release.sh \
  --jdk-tar /path/to/bisheng-jdk-17.0.13-HarmonyOS-release.tar.gz \
  --hnp

只生成 JVM-only 发行包时,可执行:

scripts/package-harmonyos-pc.sh \
  --jdk-tar /path/to/bisheng-jdk-17.0.13-HarmonyOS-release.tar.gz

默认命令行产物为:

target/harmonyos-pc/sbt-harmonyos-pc-2.0.0.tar.gz

如果希望降低首次构建对网络和 Maven 响应速度的敏感度,可以先预热缓存,再通过 --cache-dir 传入组装脚本。缓存是可用性优化,不是验收的替代品;交付前仍应至少完成一次缓存命中构建和一次真实依赖解析。

构建 HarmonyOS HAP 时,ohos/entry/src/main/module.json5 会声明两个公共 HNP。只有当 HNP 载荷已注入最终 HAP,并使用与目标设备、BundleName 相匹配的授权材料签名后,才可以进入真机安装阶段。连接鸿蒙 PC 后,安装与启动方式如下:

hdc list targets
hdc install -r /path/to/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b org.scala.sbt.ohos -m entry

安装后应先检查运行时和入口:

java -version
javac -version
sbt --script-version

随后在一个真实 Scala 项目中完成主流程:

sbt clean update compile test run package

建议将 scripts/harmonyos-pc-preflight.shscripts/harmonyos-pc-smoke-sh.sh 纳入每次发行验收。前者检查架构、shell、可写目录和 Java,后者创建独立的 Scala/MUnit 工程,覆盖 launcher、依赖解析、编译和测试。

七、当前功能边界

当前版本已在 HarmonyOS PC 真机上验证以下核心能力:

  • 签名 HAP 安装、EntryAbility 启动与 ArkUI 工具箱展示;
  • BiSheng JDK 17 与 sbt 两个公共 HNP 被安装包正确声明;
  • HiShell 可直接调用 javajavacsbt
  • POSIX sh 启动主路径,不以 Bash 作为必需条件;
  • sbt 2.0.0 launcher 启动和项目定义加载;
  • Maven 仓库依赖解析与本地 Coursier/sbt 缓存;
  • Scala 3 源码编译与增量构建缓存;
  • MUnit 测试源码编译和用例执行;
  • run 执行用户主程序;
  • package 生成可查找的 JAR 产物。

同时,当前范围没有将以下内容宣称为已完成:

  • native sbtn 薄客户端的 HarmonyOS ABI 适配;
  • JLine 原生库加载、完整交互式终端与原生 PTY 体验;
  • BSP 与 IDE 完整集成;
  • sbt 插件生态的全量兼容,特别是依赖外部原生命令的插件;
  • JavaFX、AWT 或 Swing 图形工作负载;
  • 无网络情况下所有 Scala/sbt/插件版本的完整物料覆盖;
  • 大型多模块工程的长时间稳定性、内存上限和性能基准。

因此,当前成果更准确的定位是“可在 HarmonyOS PC 上安装和使用的 sbt 2.0.0 JVM 命令行开发版”。它已经覆盖 Scala 开发的最小主流程,但不等同于所有桌面终端特性、原生客户端和第三方插件都已逐项验证。

八、总结

sbt 的鸿蒙 PC 适配证明,JVM 项目的迁移并不是简单的“跨平台 JAR 复制”。只有 JDK、shell、用户目录、缓存、仓库访问、HNP 命令注册和 HAP 签名安装形成连续契约,用户才能真正在目标设备上完成一次构建。

本项目通过 BiSheng JDK 17 解决 JVM 前提,通过 POSIX sh 入口消除 Bash 强依赖,通过显式用户与缓存路径稳定构建数据,再由公共 HNP 和 ArkUI HAP 完成用户可安装的交付。真机上的版本检查、Scala 编译、MUnit 测试、主程序运行与 JAR 打包表明,当前链路已经越过“能启动 launcher”的阶段,形成了可验收的开发工作流。

后续工作应聚焦在 JLine/PTY、native sbtn、BSP/IDE 集成、常用插件分级兼容和大型工程压力验证,而不是对已经跑通的 JVM 主链路重复包装。这条路线也为其他 JVM 开发工具适配鸿蒙 PC 提供了可复用的参考:保留成熟的语言生态内核,将平台差异收敛到运行时、入口、缓存和安装边界,最后用真机上的实际产物完成验收。

Logo

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

更多推荐