2018年8月28日 星期二

Winform 軟體自動更新

Winform 的更新方式很多,最方便的莫過於微軟的 ClickOnce。這次的需求無法用這個機制滿足User,只好自己開發,順便紀錄一下。

網路上能找了幾篇來參考:



最後整理出一些重點符合需求也能兼顧效能與彈性,我的版本:


  1. 更新檔直接放共享網路。(不用架設額外 Web 或 FTP,大家也都能存取)
  2. 更新檔封裝為一個壓縮檔,縮短下載(複製)時間。
  3. 放置一個純文字文件紀錄目前版本供本地端讀取比較。
  4. 更新時不需出現確認視窗,有更新就直接執行。(ClickOnce會出現)
  5. 需於主程式啟動判斷更新,並可定時檢查與手動執行。

簡單畫個圖 (包含專案佈署流程):





使用的步驟如下:

一、主程序專案的 App.config 加入以下變數。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="UpdateProc" value="更新程序名稱"/>
    <add key="UpdatePath" value="更新程序所在路徑(含\)"/>
    <add key="LocalFile" value="主程序名稱"/>
    <add key="LocalPath" value="主程序路徑(含\)"/>
    <add key="RemotePath" value="更新檔所在路徑(含\)"/>
    <add key="RemoteTxt" value="版本文件名稱"/>
    <add key="RemoteZip" value="壓縮檔名稱"/>
  </appSettings>
</configuration>

專案要加入參考
System.configuration
程式要引用
using System.Configuration;

二、主程序的應用程式進入點 Program.cs 改為帶入參數。
[STAThread]
static void Main(string[] args)
{
    ....
    ....
}

三、同樣於 Main() 內加入更新程序,完整程式如下。
static void Main(string[] args)
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    // 如果沒有傳遞參數,則呼叫更新程序;更新後再次呼叫會帶參數,就不會重覆執行更新。
    if (args.Length == 0)
    {
        string _update_exe = ConfigurationManager.AppSettings["UpdateProc"];
        string _update_path = ConfigurationManager.AppSettings["UpdatePath"];
        string _local_exe = ConfigurationManager.AppSettings["LocalFile"];
        string _local_path = ConfigurationManager.AppSettings["LocalPath"];
        string _remote_path = ConfigurationManager.AppSettings["RemotePath"];
        string _remote_txt = ConfigurationManager.AppSettings["RemoteTxt"];
        string _remote_zip = ConfigurationManager.AppSettings["RemoteZip"];
        
        // 呼叫更新程序時,要帶入主程序(路徑含檔名)
        Process p = new Process();
        p.StartInfo.FileName = _update_path + _update_exe;
        p.StartInfo.Arguments = string.Format("{0} {1} {2} {3} {4}", _local_exe, _local_path, _remote_path, _remote_txt, _remote_zip);
        p.Start(); // 啟動更新程序,更新完畢會自動啟動主程序
        
        // 先離開主程序,以免無法更新(覆蓋檔案)
        Application.Exit();
    }
    else
        Application.Run(new frmLogin()); // 更新後啟動,開啟登入表單
}

四、準備好更新壓縮檔與版本文字檔,放到更新路徑上,即可測試啟動時自動更新。

五、正式發布給User安裝後,路徑可能與開發時不同,佈署前記得修改 App.config。

六、搭配一個 Timer 可實現按時自動更新,呼叫更新程序方法同上。

七、針對手動更新,有另外撰寫一個類別進行版本比對,比對後如需更新,呼叫方法同上。