一、写在前面

欢迎加入鸿蒙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 服务。

这次选择的是第三条路线。

它的好处是:

  1. 不破坏原 JD-GUI Swing 桌面工程;
  2. 反编译能力继续复用 JD-Core;
  3. ArkUI 端可以快速还原桌面 UI;
  4. 能尽快跑到鸿蒙真机上验证;
  5. 后续如果要做纯鸿蒙单机版,也可以继续沿用这次沉淀下来的 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

其中核心流程是:

  1. 鸿蒙客户端选择文件;
  2. 把文件二进制上传到 /api/files
  3. 服务端保存到临时目录;
  4. /tree 扫描 JAR/ZIP/class 结构;
  5. 点击 .class 时调用 /decompile
  6. JdDecompilerEngine 调用 JD-Core 生成 Java 源码;
  7. 客户端把源码显示到右侧代码区域;
  8. 导出时服务端生成 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 编译比较严格,适配过程中遇到过几个典型问题:

  1. Object literal must correspond to some explicitly declared class or interface
  2. Use explicit types instead of any, unknown
  3. Indexed access is not supported for fields
  4. toolbar 和 ArkUI 组件基类属性命名冲突。

最终处理方式是:

  • http.request 的 options 显式声明成 http.HttpRequestOptions
  • JSON 响应定义明确接口,例如 HealthResponseUploadResponseTreeResponseSourceResponseExportResponse
  • 不再用 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.

处理方式有两种:

  1. 正式方式:重新生成和项目 bundleName 一致的调试 profile;
  2. 临时真机验证方式:把 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 -> Save
  • File -> Save All Sources
  • Edit -> 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 返回也尽量定义成明确接口,而不是 anyunknown 或动态索引对象。

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 提供了一套可复用思路。

Logo

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

更多推荐