鸿蒙PC迁移:JD-GUI Java 反编译工具鸿蒙PC适配全记录:从 Swing 桌面程序到 ArkUI 真机可运行版本
一、写在前面
欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区:https://harmonypc.csdn.net/
项目开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_JD-GUI
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
这篇文章记录的是 JD-GUI 这个经典 Java 反编译图形工具适配 HarmonyOS PC / 鸿蒙真机的完整过程。
JD-GUI 对 Java 开发者来说并不陌生。它的核心作用很明确:
打开
.jar、.class、.war、.ear、.zip等 Java 包或 class 文件,查看包结构,并把.class反编译成可阅读的 Java 源码。
原版 JD-GUI 是一个传统 Java Swing 桌面应用。它的 UI 建立在 Swing、菜单栏、工具栏、树形控件、tab 和源码文本区这些桌面组件上;真正的反编译能力来自 JD-Core。
这类项目适配鸿蒙时,和 Electron 项目不太一样。Electron 应用通常可以围绕 Web 页面、资源路径、Node 能力和 HAP 打包去处理;但 JD-GUI 是 Java Swing 程序,不能直接把 JFrame、JTree、JTabbedPane 原样搬到 ArkUI 上。
因此这次没有选择“硬迁 Swing”,而是采用了一个更适合第一阶段落地的方案:
HarmonyOS ArkTS / ArkUI 客户端
负责 JD-GUI 风格界面、文件选择、树展示、源码展示、保存导出
本机 Java 反编译服务
负责接收文件、扫描 JAR/ZIP 树、调用 JD-Core 反编译、导出 sources.zip
原 JD-GUI / JD-Core 能力
尽量复用原项目的反编译核心,不破坏原 Swing 桌面版本
最终效果是:在鸿蒙真机上可以安装一个 JD-GUI 风格的 HAP 应用,界面保留原版 JD-GUI 的菜单栏、工具栏、左侧 archive tree、右侧源码区域和底部状态栏。反编译能力通过本机 Java 服务提供,真机客户端通过 127.0.0.1:8766 访问服务。USB 真机调试时,可以用 hdc rport 把真机上的 127.0.0.1:8766 反向映射到 Mac 上的服务端口。
当前版本已经完成:
- 鸿蒙 ArkTS / ArkUI 客户端工程;
- JD-GUI 风格菜单栏、工具栏、文件 tab、左侧树、右侧源码 viewer、底部 find/status bar;
- Java 本地 HTTP 反编译服务;
- 上传
.jar/.class/.zip/.war/.ear/.aar/.kar; - 扫描 archive tree;
- 点击
.class后调用 JD-Core 反编译; - 读取普通
.java或资源文本; - 导出全部反编译源码为
sources.zip; - HAP 构建、签名、安装到鸿蒙真机;
- 真机启动后状态栏显示
Service connected。
需要说明的是,当前版本是一个“鸿蒙客户端 + 本机 Java 服务”的适配版本,还不是完全离线的纯鸿蒙反编译器。它已经可以作为内部测试版 / MVP 使用;如果要做面向普通用户的正式版本,后续还需要处理服务自动启动、包名签名、异常提示、完整文件流程测试和更完整的源码高亮体验。

二、原项目分析:JD-GUI 是典型 Java Swing 反编译桌面工具
适配前先看原项目。JD-GUI 原始工程大致是这样的结构:
jd-gui-master/
├── app/
│ └── src/main/java/org/jd/gui/
├── services/
│ └── src/main/java/org/jd/gui/
├── api/
├── build.gradle
├── settings.gradle
└── ...
原项目本身是一个多模块 Gradle Java 项目。核心信息有几个:
app/:原 Swing 桌面 UI;services/:文件加载、源码保存、反编译相关服务;api/:容器、加载器等基础抽象;jd-core:真正把 class 反编译成 Java 源码的核心依赖;RTextArea / RSyntaxTextArea:原桌面端源码查看体验;- Swing 菜单、工具栏、JTree、tab 面板:原版 JD-GUI 的桌面外观。
原版 JD-GUI 的使用路径非常清晰:
打开 jar/class
-> 左侧显示包结构
-> 点击 class
-> 右侧显示 Java 源码
-> 搜索 / 保存 / 导出
所以这次适配的重点并不是“做一个全新的移动端页面”,而是尽量保留 JD-GUI 桌面工具的心智。尤其在鸿蒙 PC 或大屏真机上,桌面工具类软件更适合继续保留菜单栏、工具栏、树形结构和源码面板。

三、路线选择:不直接迁 Swing,拆成 ArkUI 客户端 + Java 服务
JD-GUI 这种项目理论上有几条适配路线。
第一条路线是直接把 Swing 搬到鸿蒙上。这条路成本很高,因为 Swing 的窗口体系、绘制模型、事件模型和 ArkUI 并不是同一套东西。JFrame、JMenuBar、JTree、JTabbedPane、RSyntaxTextArea 都需要重新适配。
第二条路线是把 JD-Core 完全迁到鸿蒙端,让 ArkTS 直接本地反编译。这条路线最终体验最好,但第一版工作量很大。Java class 读取、依赖类加载、JD-Core 运行环境、源码输出、错误恢复都要重新处理。
第三条路线是先把 UI 和反编译能力拆开:
- 鸿蒙端用 ArkTS / ArkUI 重建 JD-GUI 风格界面;
- Java 端保留 JD-Core 反编译能力;
- 两边通过本机 HTTP API 通信;
- 真机调试时用 HDC 反向端口把设备端口映射到 Mac 服务。
这次选择的是第三条路线。
它的好处是:
- 不破坏原 JD-GUI Swing 桌面工程;
- 反编译能力继续复用 JD-Core;
- ArkUI 端可以快速还原桌面 UI;
- 能尽快跑到鸿蒙真机上验证;
- 后续如果要做纯鸿蒙单机版,也可以继续沿用这次沉淀下来的 UI 和交互。
最终新增的主要内容如下:
jd-gui-master/
├── harmony_pc_client/
│ ├── AppScope/
│ ├── build-profile.json5
│ ├── entry/
│ │ └── src/main/ets/
│ │ ├── entryability/
│ │ └── pages/Index.ets
│ └── ...
├── services/src/main/java/org/jd/gui/harmony/
│ ├── HarmonyPcService.java
│ ├── JdDecompilerEngine.java
│ ├── ArchiveScanner.java
│ ├── FileStore.java
│ ├── JsonWriter.java
│ └── ...
└── scripts/start-harmony-pc-service.sh
这一版适配不是把原 Java UI “翻译”成 ArkTS,而是保留原软件的产品结构:
菜单栏 + 工具栏 + 文件标签 + 左侧 Archive Tree + 右侧 Source Viewer + 底部状态栏
四、第一步:新增 Java 本地反编译服务
鸿蒙客户端需要一个稳定的反编译入口,所以首先在 services 模块里新增了:
services/src/main/java/org/jd/gui/harmony/
├── HarmonyPcService.java
├── JdDecompilerEngine.java
├── ArchiveScanner.java
├── FileStore.java
├── JsonWriter.java
├── QueryParams.java
├── ArchiveNode.java
├── UploadedFile.java
├── DecompileResult.java
├── ExportedFile.java
└── ...
HarmonyPcService 使用 JDK 自带的 com.sun.net.httpserver.HttpServer 启动一个轻量 HTTP 服务。默认监听:
http://127.0.0.1:8766
当前提供的接口包括:
GET /api/health
POST /api/files
GET /api/files/{fileId}/tree
GET /api/files/{fileId}/decompile?entryPath=...
GET /api/files/{fileId}/source?entryPath=...
GET /api/files/{fileId}/export
GET /api/exports/{exportId}/download
其中核心流程是:
- 鸿蒙客户端选择文件;
- 把文件二进制上传到
/api/files; - 服务端保存到临时目录;
/tree扫描 JAR/ZIP/class 结构;- 点击
.class时调用/decompile; JdDecompilerEngine调用 JD-Core 生成 Java 源码;- 客户端把源码显示到右侧代码区域;
- 导出时服务端生成
sources.zip,客户端再下载保存。
启动服务的脚本是:
sh scripts/start-harmony-pc-service.sh 8766
健康检查:
curl http://127.0.0.1:8766/api/health
正常返回类似:
{"status":"ok","name":"JD-GUI Harmony PC service"}
Gradle 兼容处理
原 JD-GUI 项目比较老,构建里包含 Windows / Linux 桌面打包插件。新机器上使用 Java 17、Gradle 7 时,这些老插件容易先于服务编译阶段报错。
为了只跑 Harmony 服务,新增了一个轻量构建模式:
-Djd.gui.harmony.lightBuild=true
build.gradle 中根据这个参数跳过旧桌面打包插件,只保留 Java 编译和服务运行所需内容。services/build.gradle 中新增:
task runHarmonyPcService(type: JavaExec, dependsOn: classes) {
description = 'Starts the JD-GUI HarmonyOS PC local decompiler service.'
group = 'application'
main = 'org.jd.gui.harmony.HarmonyPcService'
classpath = sourceSets.main.runtimeClasspath
args '--port=' + (project.findProperty('harmonyPort') ?: '8766')
}
另外还做了一个 Java 17 兼容修复:
FileSystem subFileSystem = FileSystems.newFileSystem(tmpPath, (ClassLoader)null);
这是为了解决 FileSystems.newFileSystem(...) 在新 JDK 下的重载歧义问题。
五、第二步:新增 HarmonyOS ArkUI 客户端
鸿蒙客户端放在:
harmony_pc_client/
核心页面是:
harmony_pc_client/entry/src/main/ets/pages/Index.ets
客户端使用的主要 HarmonyOS 能力:
@ohos.file.picker:选择.jar/.class/.zip/.war/.ear/.aar/.kar文件;@ohos.net.http:访问本机反编译服务;@ohos.file.fs:保存源码和导出 zip;- ArkUI:重建 JD-GUI 风格界面。
界面结构按原 JD-GUI 的桌面布局来做:
File / Edit / Navigation / Search / Help 菜单栏
灰色工具栏 + 原 JD-GUI 图标
文件 tab strip
左侧 archive tree
右侧 source tabs + source viewer
底部 find panel
底部 status bar
为了让用户一眼能看出这是 JD-GUI,而不是一个全新的文件浏览器,界面颜色没有做成移动端风格,而是保留了经典桌面工具的灰色菜单、灰色工具条、白色树、灰色源码空状态。
关键字段如下:
private serviceUrl: string = 'http://127.0.0.1:8766';
真机上 127.0.0.1 默认指向设备本身。USB 调试时,需要使用 HDC 反向端口:
hdc rport tcp:8766 tcp:8766
这样鸿蒙应用访问设备侧的 127.0.0.1:8766 时,就能通过 USB 转到 Mac 上的 127.0.0.1:8766 Java 服务。

ArkTS 严格类型问题
鸿蒙 ArkTS 编译比较严格,适配过程中遇到过几个典型问题:
Object literal must correspond to some explicitly declared class or interface;Use explicit types instead of any, unknown;Indexed access is not supported for fields;toolbar和 ArkUI 组件基类属性命名冲突。
最终处理方式是:
http.request的 options 显式声明成http.HttpRequestOptions;- JSON 响应定义明确接口,例如
HealthResponse、UploadResponse、TreeResponse、SourceResponse、ExportResponse; - 不再用
data['name'],改成data.name; - 把 builder 方法
toolbar()改名为jdToolbar(),避免与基类属性冲突; hvigor/hvigor-config.json5补上:
{
"modelVersion": "5.0.0",
"dependencies": {}
}
这些问题都不算业务难点,但是真机 HAP 编译前必须处理干净。最终 ArkTS 编译通过,只剩 getContext deprecated 和部分 API 异常提示类 warning,不影响当前运行。
六、第三步:构建、签名、安装到真机
鸿蒙客户端构建前先进入工程目录:
cd harmony_pc_client
ohpm install
构建 HAP:
/Users/yourname/ohos/command-line-tools/bin/hvigorw assembleHap \
--mode module \
-p module=entry@default \
-p product=default
构建成功后可以看到:
BUILD SUCCESSFUL
SignHap
entry-default-signed.hap
签名 HAP 路径类似:
harmony_pc_client/entry/build/default/outputs/default/entry-default-signed.hap
查看设备:
hdc list targets -v
配置 USB 反向端口:
hdc rport tcp:8766 tcp:8766
hdc fport ls
安装到真机:
hdc install -r harmony_pc_client/entry/build/default/outputs/default/entry-default-signed.hap
启动应用:
hdc shell aa start -b com.example.jdgui -a EntryAbility
这里的 bundleName 要换成自己签名 profile 对应的包名。本次调试过程中有一个小插曲:调试 profile 绑定的 bundleName 和项目里 AppScope/app.json5 的 bundleName 不一致,导致 SignHap 报错:
The bundleName in app.json does not match the bundleName in the generated SigningConfigs.
处理方式有两种:
- 正式方式:重新生成和项目 bundleName 一致的调试 profile;
- 临时真机验证方式:把
AppScope/app.json5里的 bundleName 临时改成 profile 绑定的包名。
实际项目要发布时,建议使用第一种方式,避免包名混乱。

本次真机验证中,还额外确认了:
hdc shell pidof <bundleName>
hdc shell aa dump -l
hdc fport ls
curl http://127.0.0.1:8766/api/health
结果显示:
- 应用进程存在;
- 任务栈里有
EntryAbility; tcp:8766 tcp:8766 [Reverse]存在;- 本机 Java 服务 health 正常;
- 真机前台显示 JD-GUI 主窗口;
- 底部状态栏显示
Service connected。
七、第四步:真机运行效果和文件流程
应用启动后,如果服务和端口映射都正常,底部状态栏会显示:
Service connected
JD-GUI Harmony PC service
这说明鸿蒙客户端已经能访问本机 Java 反编译服务。
用户侧的预期使用流程是:
File -> Open File...
-> 选择 .jar / .class / .zip / .war / .ear / .aar / .kar
-> 上传到本机服务
-> 左侧显示 archive tree
-> 点击 .class
-> 右侧显示反编译 Java 源码
-> Save 或 Save All Sources
当前客户端已经实现了这些入口:
File -> Open File...File -> SaveFile -> Save All SourcesEdit -> Find...Navigation -> Open Type...Search -> Search...- 工具栏 Open / Save / Save All / Search / Back / Forward / Service
需要注意的是,当前版本的 Back / Forward 只是 UI 占位,完整导航历史还没有做完。源码区域目前是普通文本区,和原版 JD-GUI 的完整语法高亮、超链接跳转还有差距。

八、适配过程中踩到的几个关键问题
8.1 真机上的 127.0.0.1 不是 Mac 的 127.0.0.1
鸿蒙应用中写:
http://127.0.0.1:8766
在真机上默认指的是设备自己,不是 Mac。
如果 Java 服务运行在 Mac 上,真机直接访问 127.0.0.1:8766 会失败。调试阶段最方便的做法是使用 HDC 反向端口:
hdc rport tcp:8766 tcp:8766
这样设备侧的 127.0.0.1:8766 会被转发到 Mac 侧的 127.0.0.1:8766。
8.2 服务端只绑定 127.0.0.1 更安全
当前 Java 服务代码中使用:
new InetSocketAddress("127.0.0.1", port)
这意味着服务只监听本机回环地址。调试时配合 hdc rport 即可,不需要开放到局域网。
不要为了方便直接绑定 0.0.0.0 暴露到局域网,除非后续补上认证、访问控制、临时文件清理和安全策略。反编译服务可以读取并处理用户上传文件,随便暴露端口风险比较高。
8.3 老 Gradle / 老插件和新 JDK 的兼容问题
JD-GUI 原工程里包含一些桌面打包插件。新环境下只想编译服务模块时,不应该让这些老插件先把构建卡死。
因此增加了 light build:
-Djd.gui.harmony.lightBuild=true
并在 scripts/start-harmony-pc-service.sh 中默认带上这个参数。这样服务端可以在新机器上稳定启动,原桌面打包流程仍然保留。
8.4 ArkTS 不能按 TypeScript 的“宽松写法”来写
ArkTS 对类型更严格,尤其在 HarmonyOS 新版 SDK 下,很多普通 TypeScript 写法会被拦住。
比如:
const response = await request.request(url, {
method: method,
header: {},
extraData: extraData
});
需要改成:
const options: http.HttpRequestOptions = {
method: method,
extraData: extraData,
connectTimeout: 10000,
readTimeout: 120000
};
JSON 返回也尽量定义成明确接口,而不是 any、unknown 或动态索引对象。
8.5 签名 profile 的 bundleName 必须和 app.json5 一致
真机安装前必须签名。签名 profile 里绑定了 bundleName,如果它和:
AppScope/app.json5
里的 bundleName 不一致,构建会在 SignHap 阶段失败。
正式处理方式是在 DevEco Studio 的 Signing Configs 中为当前包名生成正确 profile。临时调试时可以改包名对齐 profile,但文章和项目整理阶段不建议长期这样做。
九、当前完成度和后续方向
当前 JD-GUI 鸿蒙适配版已经完成了第一阶段闭环:
Mac 启动 Java 反编译服务
-> 鸿蒙真机安装 HAP
-> hdc rport 反向端口
-> App 启动
-> Service connected
-> 打开 JAR/class
-> 展示包结构
-> 调用 JD-Core 反编译
-> 显示 Java 源码
-> 保存 / 导出
这次适配最重要的经验是:传统 Java Swing 工具迁到鸿蒙 PC,不一定要一开始就追求“原代码原窗口完整迁移”。对于 JD-GUI 这种核心能力和 UI 能力可以拆开的软件,先把反编译核心封成服务,再用 ArkUI 重建桌面界面,是一个能快速验证、能跑真机、也方便后续继续演进的路线。
从最终效果看,JD-GUI 已经可以在鸿蒙真机上以接近原版桌面软件的方式运行。它保留了开发者熟悉的使用路径,也为后续把更多 Java 开发者工具迁到 HarmonyOS PC 提供了一套可复用思路。
更多推荐




所有评论(0)