=
文章目录
前言
首先说一下,搞这个软件修复的背景,本人是一个小说迷,无意中发现这个大神做的软件,用了一段时间,感觉软件很棒,后来这个大神因某些原因,停止更新并且把软件封了。这个程序是在github开源的:https://github.com/unclezs/uncle-novel。后来,我就硬着头皮研究代码,修改代码并编译出来了。
不想看接下来的长篇大论的,想要直接获取软件包的自取,链接如下:https://github.com/liangyunshan/uncleNovel-PC/releases/tag/5.0.38,有条件的给个star。
一、需要解决的问题?
这个软件是pc版的小说阅读器,软件一直更新到了5.0版本,支持功能如下:
- 搜书文本小说
- 搜书有声小说
- 全网搜书
- 文本小说书架
- 文本小说阅读器
- 有声小说书架
- 解析下载
- 下载管理
- 书源管理
- 软件设置
- 全局热键
- 主题定制
- 国际化支持
- 备份与恢复(WebDav)
某一天,软件作者决定停止更新与维护这个开源软件了,同时将软件封了,进软件后直接告警弹框,然后只能退出程序,总之无法正常使用。为了能继续正常使用这个软件,开始了阅读源码、修改源码、编译、打包这样的过程。
二、具体步骤
1.下载源码
访问github网速较慢的话,可以直接下载源码的zip包,不携带版本控制信息。修改后的源码上传到了我的github上,只希望了解源码修改情况或者直接编译打包,可以去这个仓库地址下载源码:https://github.com/liangyunshan/uncleNovel-PC
ps:以下贴的链接都为原始仓库地址。
如果希望保留版本控制相关信息,比如仓库信息、提交更新日志,可以通过git下载源码:
git clone https://github.com/unclezs/uncle-novel.git
2.问题分析
- 问题一:怎么禁用软件自动更新?
一直做的都是C/C++的嵌入式开发,没做过java 应用与Android APP的开发,在网上临时学习了解了一些信息。就急匆匆上手了,踩坑之路就这样开始了。
一开始的思路是,直接修改软件中发起版本检查并获取更新的源码,后来发现不行,因为软件运行后,首先运行的是一个launcher,这个launcher会主动执行版本检查与更新,更新后,本地的app.jar包会被替换为远程仓库中托管的更新文件。
再次去看源码,发现源码依赖一个自动更新模块com.unclezs:jfx-launcher,经过更多的搜索了解到,这个模块来源于另一个开源软件,github仓库地址为:GitHub - unclezs/jfx-launcher: OpenJFX应用的启动器,支持热更新。使用模块化API动态加载模块启动,支持动态修改模块化打破规则。,这又是增加了工作难度。换个思路,直接拉取这个jfx-launcher的源码,将jfx-launcher源码中自动检查更新并拉取更新文件的入口注释掉,然后编译为jar包替换到uncle-novel的打包路径下,并重新打包。经过尝试,毫无疑问的失败了[挠头],那两天秀发掉了不少,哈哈。
2.问题二:为什么将jfx-launcher的jar包替换后不起作用?
继续看源码的编译过程,又百度一通搜索,再次get到几个知识点:
(1)uncle-novel使用的是gradle编译,编译时会从某个远程仓库拉取编译时依赖的jar包等相关内容;
(2)软件作者将uncle-novel依赖的jar等资源,全部托管在Maven Repository中;
再次经过搜索,找到Maven Repository这个远程托管仓库,地址是:https://mvnrepository.com/artifact/com.unclezs/jfx-launcher,很显然,这个远程托管仓库我是没有发布权限的(有权限也不知道具体步骤)。
根据上面的探索,明白了这些依赖的jar包肯定下载到了本地,只是不知道具体路径,再次百度搜索了解相关内容,再次get到一个知识点:
(1)使用gradle编译时,依赖的jar包会下载到本地的.gradle文件夹下,这个文件夹默认是在用户目录下;
比如在我的ubuntu中,这个目录是/home/ts/.gradle/;在我的windows中,这个目录是C:\Users\ts-lys\.gradle\。这里的ts或者ts-lys是当前登录的用户名称。
接着,通过在这个目录下搜索,找到jfx-launcher-1.1.9.jar这个jar包所在路径,然后将修改并重新编译好的jfx-launcher包替换到对应的目录下,并保持名称一致。
3.问题三:怎么阻止jfx-launcher拉取更新文件到本地?
继续看jfx-launcher的源码,了解到jfx-launcher的主窗口是继承java中的Application类实现的,因此运行时的入口函数应该是main函数,源码中也看到这部分代码在在Launcher.java文件中,Launcher类继承Application类并重写了其中的一些函数。Application类中的main函数经过一连串的内部初始化,最终调用start函数,Launcher类源码中重写了start函数,start函数中调用了startApplication函数,startApplication函数中调用checkForUpgrade函数来检测更新升级信息,checkForUpgrade函数调用syncManifest函数来同步manifest,将更新同步到本地。
我的做法是将syncManifest函数中大部分实现代码注释掉,直接返回false即没有更新,其中加了一些调试log,修改如下:
/**
* 同步manifest
*
* @return true 有更新
*/
public boolean syncManifest() {
ui.setPhase("liangys1115说肯定没有新版本...");
// try {
// log.log(Level.INFO, "liangys1115获取远程配置文件:{0}", manifest.remoteManifest());
// ui.setPhase("liangys1115正在检测是否有新版本...");
// Manifest remoteManifest = Manifest.load(manifest.remoteManifest());
// if (!checkNew(remoteManifest)) {
// ui.setPhase(String.format("liangys1115当前已是最新版本:%s", manifest.getVersion()));
// this.newVersion = false;
// return false;
// }
// // 显示更新内容
// ui.initUpdateView();
// ui.setPhase(String.format("liangys1115检测到新版本:%s", manifest.getVersion()));
// Path localManifest = manifest.localManifest();
// if (Files.notExists(localManifest)) {
// Files.createDirectories(localManifest.getParent());
// }
// Files.writeString(manifest.localManifest(), remoteManifest.toJson());
// manifest = remoteManifest;
// // 显示更新内容
// if (!manifest.getChangeLog().isEmpty()) {
// log.log(Level.INFO, "liangys1115更新内容:{0}", manifest.getChangeLog());
// ui.setWhatNew(manifest.getChangeLog());
// }
// return true;
// } catch (Exception e) {
// // 忽略更新失败
// log.log(Level.SEVERE, "liangys1115更新失败", e);
// }
return false;
}
4.问题四:怎么禁止软件在主窗口中告警弹窗?
继续看源码,通过软件运行时告警弹窗的显示内容,在uncle-novel源码中全局搜索,找到了代码所在位置:
看这部分代码,做过桌面应用的攻城狮应该知道,这里实现的是显示一个模态对话框(ModalBox),只有一个cancle的按钮选项,点击后直接退出程序(stopApp)。
注释其中几行代码,具体如下:
/**
* 启动
*
* @param stage 舞台
* @throws Exception 启动失败
*/
@Override
public void start(Stage stage) throws Exception {
super.init();
super.start(stage);
initStage(stage);
stage.show();
// ModalBox.none().message("bye~").title("bye~").cancel("bye~").showAndWait();
// App.stopApp();
// 检测更新
// UpdateUtils.checkForUpdate(stage);
// MixPanelHelper.event(EVENT_LAUNCH);
log.trace("启动耗时:{}ms", (System.currentTimeMillis() - LAUNCH_TIME));
}
接下来就是重新编译、打包、运行自测了。
3.配置编译与打包环境
windows(我用的是win10) |
openjdk 11 |
exe4j |
4.源码编译
ps:不知道开发java这类桌面应用到底用什么IDE工具,踩了这么多坑,也不想再去踩配置IDE的坑了,直接命令行走起。
4.1重新编译jfx-launcher
首先,需要cd到对应的源码目录下,然后执行命令:
./gradlew.bat build
编译成功时,如下图所示:
编译成功后,将对应的jar包替换到.gradle路径下。
4.2重新编译uncle-novel
./gradlew.bat build
编译成功时,如下图所示:
4.3打包uncle-novel
在windows中打包依赖exe4j这个程序,在打包之前需要安装并配置好环境变量。
./gradlew.bat packageWin64
打包成功后如图所示:
在源码的app/build/packager/目录下有对应的打包文件,将压缩包拷贝到自己的目录下,解压后运行Uncle小说.exe即可。
总结
对于uncle-novel的修复步骤感兴趣的,可以交流交流。