好久沒有寫部落格,2021年就以 “JavaFX桌面應用-版本升級” 開篇吧,記錄一下JavaFX應用版本升級的開發流程。
桌面應用升級的方案應該很多,這裡只是自己想到的方案。
1. 效果展示
首先,先看一下版本升級的最終效果(先不討論UI美不美觀的問題,UI美化可以檢視其他部落格)
如上圖,程式啟動後會自動檢測是否有最新版本,如果用則提示使用者,由使用者決定是否進行應用升級,如果使用者點選了升級,則會啟動升級程式進行升級,並在升級後重新啟動新版的APP。
2. 升級流程
在展開說明具體的功能開發前,簡單介紹一下應用升級的流程,以及涉及的各個端。
這裡的應用升級主要涉及3個方面:
- App(主應用)
- 升級SDK(封裝升級流程,App整合即可)
- 升級程式(負責App升級)
應用升級的流程其實比較簡單,大致分為這幾個步驟:
- 獲取最新版本資訊
- 詢問使用者是否升級
- 執行版本升級
升級的流程如下圖所示:
3. 升級細節
在上面的升級流程看起來沒有什麼問題,但實際應用起來有一些細節需要注意,比如:
- 版本怎麼計算
- 升級程式怎麼獲取更新包
- 升級程式怎麼開啟APP
一般來說,升級程式開發完成後可能很少修改,或者說,希望只開發一個升級程式,供所有app升級使用,這樣就不需要為每一個應用都開發一個升級程式。
上圖是升級程式獲取更新包的流程,這裡SDK和升級程式是通過本地檔案update_info
作為通訊的媒介,具體的流程為:
- APP啟動後呼叫SDK向伺服器拉取版本資訊,並將拉取版本資訊的地址寫入到本地檔案
update_info
中 - 如果發現有新版本,並且使用者同意升級,那麼啟動升級程式
- 升級程式啟動後,從本地檔案
update_info
讀取獲取獲取版本資訊的地址,從伺服器獲取版本資訊及更新包,執行版本更新
這裡為什麼需要SDK每一次都把獲取版本資訊的地址寫入到本地檔案中呢?就如上面所說的,升級程式可以是通用的,但每一個APP獲取版本資訊的地址是不同的,另外同一個APP不同版本獲取版本資訊的地址也可能是不同的(比如伺服器在某個時間點更換了域名等等)。
升級程式和SDK的通訊解決了,整理流程也沒有什麼大問題,那麼版本應該怎麼計算呢?
最簡單的處理方式就是,發現版本號不一樣時就升級,這種方式不是不可以,但是可能會有很多問題,因為有些時候APP可能更新了一些不相容舊版的功能,對於相容的情況可以選擇增量更新APP,而對於不相容的情況就需要全量更新APP了,而且不排除讓使用者重新安裝程式的情況。
這裡介紹一下自己使用的一種方案,版本號規範約定為 x.y.z
,客戶端APP將x.y.z轉化為整數(x*100+y*10+z)與伺服器返回的版本進行比較,如果APP的版本小於服務版本則進行升級,服務端可以根據客戶端提供的x.y.z提供合適的升級版本資訊及更新包。
版本計算簡要程式碼如下:
private int versionToInt(String version) {
String[] items = version.split("\\.");
int versionInt = 0;
for (String item : items) {
versionInt *= 10;
versionInt += Integer.parseInt(item.trim());
}
return versionInt;
}
所以每一個APP都得提供自己的版本號以及獲取最新版本的介面地址,這個可以在APP通過定義一些常量來記錄:
public interface Version {
// 獲取版本的介面地址
String versionUri = "http://localhost:8090/itqn/version";
// 當前版本號
String version = "1.0.0";
}
這樣,程式就可以每次啟動後獲取自己版本號,再從伺服器獲取版本資訊計算是否需要升級,但是這樣對有“跳過版本”這種升級流程來說是有問題的,按照上面的流程,當使用者點選了“跳過版本”後,下次啟動APP時,從伺服器獲取升級資訊計算後仍需要升級,會彈出升級提示,這樣很不友好。
這裡稍微調整一下讀取版本的流程:
- 使用者點選跳過版本後,將最新版本號寫入到本地檔案
version
中 - APP正常升級後,升級程式也將最新版本號寫入到本地檔案
version
中 - 程式啟動的時候,優先讀取本地檔案
version
的版本號進行計算,如果本地沒有version
檔案,才讀取APP版本號常量
對應的版本計算實現程式碼如下:
private void checkVersion() {
int curVersion = 0;
File f = new File("version");
char[] buf = new char[30];
try (FileReader fr = new FileReader(f)) {
int ret = fr.read(buf);
curVersion = versionToInt(new String(buf, 0, ret));
} catch (Exception ignore) {
// use AppVersion if occur exception
}
if (curVersion == 0) {
curVersion = versionToInt(Version.version);
}
UpdateExecutor.execute(Version.versionUri, curVersion);
}
最後,關於升級程式怎麼開啟APP這個問題可以參考升級程式和SDK的通訊方案。當然也用更新簡單的方案,就是升級程式開啟非自己名稱的exe應用,這種方式只能用於應用程式只有一個exe檔案的情況。
// 這裡ITQN_update是升級程式的名稱
File[] fs = new File(".").listFiles((dir, name) -> name.endsWith(".exe") && !name.equals("ITQN_update.exe"));
if (fs != null && fs.length > 0) {
try {
Desktop.getDesktop().open(fs[0]);
} catch (IOException e) {
new Alert(Alert.AlertType.ERROR, e.getMessage()).show();
}
}
應用升級這一塊涉及的問題比較多,更多的細節可以通過公眾號獲取原始碼,具體閱讀原始碼吧,展開說明的話太多了。
=========================================================
關注 公眾號 “HiIT青年” 閱讀推文“JavaFX桌面應用-版本升級”,文章底部可以獲取原始碼。
關注公眾號,閱讀更多文章。