一、写在前面

欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区:https://harmonypc.csdn.net/

项目开源项目:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_Luyten

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

这篇文章记录的是 Luyten 这个 Java 反编译 GUI 工具适配 HarmonyOS PC 的完整过程。

Luyten 原本是一个经典 Java Swing 桌面应用,它的定位非常明确:

打开 .jar.zip.class 文件,查看包结构,并把 Java class 反编译成开发者可阅读的内容。

原版 Luyten 的核心能力来自 Procyon 反编译器,界面侧则使用 Swing、JTree、JTabbedPane、RSyntaxTextArea 等桌面组件。也就是说,它不是 Electron 项目,也不是 Web 项目,而是一个传统 Java 桌面工具。

这次适配的目标不是简单地让一个页面出现在鸿蒙 PC 上,而是要让它在 HarmonyOS PC 上形成一个不依赖外部服务的单机工具:

  • 不依赖 Mac 上的 Java 进程;
  • 不依赖 HTTP 后端;
  • 不需要用户额外启动服务;
  • 在鸿蒙 PC 上直接打开 .jar/.zip/.class
  • 在应用内解析 ZIP/JAR、解析 Java class、展示结构树、代码视图、字节码和元信息;
  • UI 尽量贴近原版 Luyten 桌面软件。

最终适配完成后,项目新增了一个 harmony_pc_standalone/ 鸿蒙工程。它使用 ArkTS / ArkUI 重建了 Luyten 的桌面布局,并实现了一套本地 class/JAR 解析流程。

当前版本已经实现:

  • 打开 .jar.zip.class
  • 解析 ZIP/JAR central directory;
  • 支持 ZIP storeddeflate 压缩方式;
  • 解析 Java class 基础结构;
  • 展示类名、父类、接口、字段、方法、属性、Code attribute;
  • 展示伪 Java 源码、成员列表、字节码预览、元信息;
  • 多 tab、搜索、Find Next、Find Previous、Find All;
  • Save As、Save All;
  • Recent Files;
  • 主题和偏好持久化;
  • 原版 Luyten 风格的菜单栏、Structure 树、Code 面板和底部状态栏。

需要说明的是,当前版本还不是完整 Procyon 级别 Java 反编译器。它已经完成了“打开文件、解析 class、展示结构和字节码”的核心流程,但方法体还原目前是结构化伪源码。完整的 bytecode -> CFG -> AST -> Java 源码还原,是后续继续深化的方向。

在这里插入图片描述

二、原项目分析:Luyten 是典型 Java Swing 反编译 GUI

原始 Luyten 项目根目录结构比较清晰:

Luyten-master/
├── pom.xml
├── README.md
├── src/
│   └── us/deathmarine/luyten/
│       ├── MainWindow.java
│       ├── MainMenuBar.java
│       ├── Model.java
│       ├── OpenFile.java
│       ├── FindBox.java
│       ├── FindAllBox.java
│       └── ...
└── harmony_pc_standalone/

README 中对项目的描述非常直接:

Java Decompiler Gui for Procyon

也就是说,原版 Luyten 的定位不是普通文本查看器,而是一个 Procyon 的 Java 反编译 GUI。

原项目里几个关键类分别承担不同职责:

  • MainWindow.java:主窗口,负责 JFrame、菜单、tab 容器、底部状态栏;
  • MainMenuBar.java:顶部菜单,包括 File、Edit、Themes、Operation、Settings、Help;
  • Model.java:核心界面模型,左侧 Structure 树、右侧 Code tab、JAR/class 打开逻辑;
  • OpenFile.java:代码编辑区,基于 RSyntaxTextArea;
  • FindBox.java / FindAllBox.java:查找和全局查找;
  • DecompilerEngine.java:原项目中与 Procyon 反编译相关的能力。

原版界面的几个主要特征也很明确:

  1. 顶部是传统桌面菜单栏;
  2. 左侧是 Structure 树;
  3. 右侧是 Code tab;
  4. 代码区域是只读编辑器;
  5. 底部有状态栏和进度条;
  6. 支持打开 JAR/class、切换主题、搜索、保存、导出。

这也决定了本次适配不能做成一个完全陌生的移动端页面。鸿蒙 PC 端最好保留桌面工具的工作流,让用户一眼能看出它还是 Luyten。

在这里插入图片描述

三、路线选择:不再依赖 Java 服务,改成鸿蒙 PC 单机 ArkTS 实现

适配 Luyten 时,最开始有几条路线可以选。

第一条路线是保留原 Java + Procyon,把鸿蒙端做成一个前端,背后仍然由 Mac 或某台机器上的 Java 服务反编译。这条路线验证快,但用户每次使用都需要额外启动服务,不符合“鸿蒙 PC 自己跑完整流程”的目标。

第二条路线是尝试把 Java Swing/AWT 搬到鸿蒙 PC。这个方向成本很高,因为 Swing 的窗口体系、菜单、文件选择器、文本编辑器、JTree、JTabbedPane 都不是鸿蒙 ArkUI 的组件模型。即使能保留一部分 Java 代码,桌面 UI 也要重新适配。

第三条路线是重新做一个 HarmonyOS PC 单机版本。也就是:

  • 使用 ArkTS / ArkUI 实现界面;
  • 用 ArkTS 本地读取文件;
  • 用 ArkTS 解析 ZIP/JAR;
  • 用 ArkTS 解析 class 文件;
  • 在鸿蒙 PC 端直接展示结构树、代码、字节码和元信息。

最终选择的是第三条路线。

原因很简单:用户需要的是一个不依赖外力的鸿蒙 PC 应用。只要安装 HAP,就可以打开 .jar/.class,不需要 Mac 端 Java 服务,也不需要 HTTP 接口。

因此项目新增了:

harmony_pc_standalone/
├── AppScope/
├── build-profile.json5
├── oh-package.json5
└── entry/
    ├── build-profile.json5
    ├── oh-package.json5
    └── src/main/
        ├── ets/
        │   ├── entryability/
        │   ├── pages/
        │   │   └── Index.ets
        │   └── parser/
        │       ├── ByteReader.ets
        │       ├── ClassParser.ets
        │       ├── FileLoader.ets
        │       ├── Inflater.ets
        │       └── ZipParser.ets
        └── resources/
            └── rawfile/
                └── demo.jar

这个目录就是本次适配后的鸿蒙 PC 单机工程。

在这里插入图片描述

四、核心实现一:本地读取 JAR/ZIP/class 文件

鸿蒙端打开文件使用的是系统 DocumentViewPicker。最初文件过滤器分成了两个选项:

fileSuffixFilters: ['Java archives|.jar,.zip', 'Java class|.class']

这个写法能用,但在真实鸿蒙 PC 文件选择器中暴露出一个问题:如果默认停留在 Java archives,进入一个只有 .class 文件的目录时,文件列表会显示为空,用户就会以为 class 文件不能选。

最终修复为只保留一个过滤项:

fileSuffixFilters: ['Java files|.jar,.zip,.class']

这样 .jar.zip.class 都会在同一个过滤条件下显示,不会再出现“目录里明明有 class,但打开后是空的”的问题。

读取文件后,流程会判断文件类型:

  1. 如果前四个字节是 CAFEBABE,按单个 .class 解析;
  2. 否则按 ZIP/JAR 解析;
  3. 如果是 JAR/ZIP,读取 central directory;
  4. 找出所有 .class entries;
  5. 建立左侧 Structure 树;
  6. 默认打开第一个 class。

其中 ZIP/JAR 解析主要在:

entry/src/main/ets/parser/ZipParser.ets

class 文件读取主要在:

entry/src/main/ets/parser/ClassParser.ets

文件读取封装在:

entry/src/main/ets/parser/FileLoader.ets

这一步完成后,应用已经能在鸿蒙 PC 上打开真实文件,而不是只加载内置 demo。

在这里插入图片描述

五、核心实现二:纯 ArkTS ZIP deflate 解压和 class 解析

JAR 本质上是 ZIP 文件。很多 JAR 里的 class entry 使用的是 deflate 压缩方式,也就是 compression method 8。

一开始尝试过使用系统 zlib 能力,但在真机运行时出现过对象异常。因此后续改成了纯 ArkTS 的 raw deflate 实现,核心文件是:

entry/src/main/ets/parser/Inflater.ets

这样处理后,JAR 中的 deflated class entry 可以直接在鸿蒙 PC 端解压,不再依赖 native zlib 流对象。

class 解析部分由 ClassParser.ets 实现,主要完成:

  • 校验 CAFEBABE magic;
  • 读取 minor / major version;
  • 读取 constant pool;
  • 解析 class name;
  • 解析 super class;
  • 解析 interfaces;
  • 解析 fields;
  • 解析 methods;
  • 读取 method 的 Code attribute;
  • 解码一部分 JVM bytecode 指令;
  • 渲染 summary、members、bytecode、metadata;
  • 生成结构化伪 Java 源码。

当前生成的 Java 视图类似:

package demo;

public class DemoHello {
    private final String name;

    public DemoHello(String arg0) {
        // bytecode length: 10, maxStack: 2, maxLocals: 2
    }

    public String greet() {
        // bytecode length: 10, maxStack: 1, maxLocals: 1
    }
}

这说明类结构、字段、方法签名已经能还原出来。完整方法体反编译还需要继续做栈模拟、表达式还原、控制流还原和 AST printer,这是后续反编译核心深化的重点。


六、核心实现三:把前端做回原版 Luyten 的桌面样式

适配早期版本曾经做成过“分析器风格”的界面:左侧 class 列表,右侧 Source / Members / Bytecode / Metadata 切换。这个界面能用,但不像 Luyten。

后面重新对照原版 Luyten,把 UI 调整为桌面工具布局:

  • 顶部菜单:FileEditThemesOperationSettingsHelp
  • 左侧标题框:Structure
  • 右侧标题框:Code
  • 右侧支持 tab;
  • 代码区使用 monospace 字体;
  • 底部状态栏显示 Complete、加载状态和进度;
  • 主题支持默认和暗色;
  • 应用标题改回 Luyten

菜单功能也逐步补齐:

  • File -> Open File...
  • File -> Close File
  • File -> Save As...
  • File -> Save All...
  • File -> Recent Files
  • File -> Clear Recent Files
  • Edit -> Find
  • Edit -> Find Next
  • Edit -> Find Previous
  • Edit -> Find All
  • Themes -> Default / Dark
  • Operation -> Package Explorer Style
  • Operation -> Filter Out Inner Class Entries
  • Settings -> Java / Bytecode / Bytecode AST / Members

这里的重点不是追求一个全新的现代 UI,而是让原版 Luyten 用户来到鸿蒙 PC 版时还能识别出熟悉的使用路径:

打开 JAR/class -> 左侧选 class -> 右侧看代码 -> 搜索/保存/切换视图

七、搜索、保存、最近文件和偏好持久化

除了打开和解析 class,本次适配还补了桌面工具常用能力。

7.1 搜索

当前支持:

  • Find
  • Find Next
  • Find Previous
  • Find All

搜索栏可以输入关键字,显示匹配数量和当前匹配行号。Find All 会生成一个 Find Results tab,列出匹配的 tab、行号、列号和预览内容。

7.2 保存

当前支持:

  • Save As...:导出当前 tab;
  • Save All...:导出当前已打开的所有 tabs。

Java 视图默认导出 .java,其他视图导出 .txt。保存走鸿蒙 PC 的 DocumentViewPicker.save(),由用户选择保存位置。

7.3 最近文件

打开外部文件后,会记录到 Recent Files。偏好写入鸿蒙本地 preferences:

preferences.getPreferencesSync(getContext(this), { name: 'luyten_preferences' })

保存的内容包括:

  • 最近文件 URI;
  • Package Explorer Style;
  • Filter Out Inner Class Entries;
  • Single Click Open;
  • Dark Theme;
  • 当前视图模式。

7.4 主题和视图模式

目前支持默认主题和暗色主题。代码视图支持:

  • Java
  • Members
  • Bytecode
  • Metadata

其中 Java 是结构化伪源码,Bytecode 可以看到方法内的 JVM 指令预览,Metadata 可以看到 class 文件的结构信息。

在这里插入图片描述
在这里插入图片描述

八、构建、安装和真机运行

鸿蒙工程路径:

~/XM/Luyten-master/harmony_pc_standalone

构建命令:

cd ~/XM/Luyten-master/harmony_pc_standalone
~/ohos/command-line-tools/bin/hvigorw assembleHap --mode module -p module=entry -p product=default --no-daemon

签名后的 HAP 路径:

~/XM/Luyten-master/harmony_pc_standalone/entry/build/default/outputs/default/entry-default-signed.hap

查看连接设备:

/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc list targets

安装到鸿蒙 PC:

/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc install -r entry/build/default/outputs/default/entry-default-signed.hap

启动应用:

/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc shell aa start -b com.phototonic.viewer -a EntryAbility

本次适配过程中,最终验证结果是:

BUILD SUCCESSFUL
install bundle successfully
start ability successfully

九、适配过程中踩到的几个关键问题

9.1 Uint8Array 不能随便放进 @State

早期版本曾经把 Uint8Array 放进 ArkUI @State,真机上出现过运行时异常。后面改成普通字段:

private fileBytes: Uint8Array = new Uint8Array(0);
private zipEntries: Array<ZipEntryInfo> = [];
private isArchive: boolean = false;

界面真正需要响应刷新的数据,比如 class 列表、tree rows、open tabs,才保留为 @State

9.2 系统 zlib 流对象在真机上不稳定

JAR 里的 class entry 常见压缩方式是 deflate。曾经尝试走系统 zlib,但真机上遇到对象异常。后面改成纯 ArkTS raw deflate 实现,避免依赖外部 native 流对象。

这也是本次单机能力能跑通的关键一步。

9.3 文件选择器过滤项会影响 class 可见性

如果文件选择器默认选中 Java archives,目录里的 .class 会被隐藏。最终只保留一个过滤项:

fileSuffixFilters: ['Java files|.jar,.zip,.class']

这样用户打开 class 文件时不会踩坑。

9.4 UI 不能偏离原版工具心智

一开始做成“分析器面板”时,功能能跑,但不像 Luyten。用户真正想要的是“原开源软件那种前端”。所以最终界面还是回到:

菜单栏 + Structure 树 + Code tab + 底部状态栏

这类桌面工具迁移到鸿蒙 PC 时,保留原有工作流比做一个全新页面更重要。


十、当前完成度和后续方向

当前版本已经完成了 Luyten 鸿蒙 PC 单机版的基础闭环:

打开 JAR/class
-> 解析 ZIP/JAR
-> 解压 class entry
-> 解析 class 文件
-> 显示 Structure
-> 打开 Code tab
-> 查看 Java 伪源码 / Members / Bytecode / Metadata
-> 搜索
-> 保存
-> 记录最近文件和偏好

这次适配最重要的收获是:对于传统 Java Swing 工具,不一定要把 Swing 原样搬上鸿蒙 PC。只要先把核心文件处理链路拆出来,再用 ArkTS 按鸿蒙 PC 的方式实现本地解析和桌面 UI,就可以在不依赖外部服务的前提下,先把一个开发者工具真正跑起来。

Logo

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

更多推荐