使用 Webclient 實現應用自動更新

jopen 10年前發布 | 14K 次閱讀 Webclient

本文提供了一個通過URL下載文件的簡易實現。

背景

很多應用都會提供一個自動更新的功能,這樣終端用戶能獲得最好的用戶體驗。簡單地說,自動更新可以通過兩步完成:

  • Step 1: 訪問程序的服務端來檢查是否有可用的新版本。

    </li>

  • Step 2: 詢問用戶是否要更新并遵從用戶的選擇。

    </li> </ul>

    本文主要會講解圍繞上面兩步所展開的工作流程。這是我的實際工作經驗。如果您有什么疑問可以給我留言。

    代碼

    1.從服務器取得最新版本信息.

    通常應用會有一個像1.20.11這樣的版本號,這是一個通過'.'分隔的一系列數字。當檢查服務器上的最新版本是否比用戶的當前版本新時,使用版本號是一個很不錯的方法。通常我們會認為1.20.22的版本要比1.20.11的版本新。

    [Update]

    CurrentVersion = 1.10.12

    IniPath = ftp://192.168.29.19//Version.ini</pre>

    此處有兩個數據行。"CurrentVersion"代表了當前(用戶)的應用版本,"IniPath"代表了服務器的Version.ini文件路徑。我們可以下載這個Version.ini文件并讀取它的版本號來做對比,這樣就可以檢查是否需要通知用戶(是否要更新應用)。

    服務端的Version.ini內容:

    [Update]

    CurrentVersion = 1.11.00

    ExePath = ............</pre>

    第一個數據行表示了服務器上的應用的最新版本號,第二行代表了新版本應用的下載路徑。

    稍后我們會介紹如何下載這個文件,現在我先介紹如何比較兩個版本號:

    /** 
         *  
         * @param version1 
         * @param version2 
         * @return if version1 > version2, return 1, if equal, return 0, else return -1 
         */  
        public static int compare(String version1, String version2)
        {  
            if (version1 == null || version1.Length == 0 || version2 == null || version2.Length == 0 )
            {
                return -1;
            } 
            int index1 = 0;  
            int index2 = 0;  
            while(index1 < version1.Length && index2 < version2.Length)
            {  
                int[] number1 = getValue(version1, index1);  
                int[] number2 = getValue(version2, index2);  
                  
                if (number1[0] < number2[0]) return -1;  
                else if (number1[0] > number2[0]) return 1;  
                else 
                {  
                    index1 = number1[1] + 1;  
                    index2 = number2[1] + 1;  
                }             
            }  
            if(index1 == version1.Length && index2 == version2.Length) return 0;  
            if(index1 < version1.Length)   
                return 1;  
            else  
                return -1;  
        }  
         /** 
         *  
         * @param version 
         * @param index the starting point 
         * @return the number between two dots, and the index of the dot 
         */  
        public static int[] getValue(string version, int index) 
        {  
            int[] value_index = new int[2];  
            StringBuilder sb = new StringBuilder();  
            while(index < version.Length && version.ElementAt(index) != &apos;.&apos;) 
            {  
                sb.Append(version.ElementAt(index));  
                index++;  
            }  
            value_index[0] = Convert.ToInt32(sb.ToString(),10); 
            value_index[1] = index;  
              
            return value_index;  
        }

    這段代碼通過'.'字符來分隔version字符串,然后對取得的數字依次進行比較.

    (譯者注:

    本人覺得這個方法太過繁瑣,如果使用android應用的版本控制會好點:定義一個versionName和versionCode,versionName是一個字符串,它作為版本的數字序列或名稱,而versionCode作為int型的版本號,查檢更新的時候可以通過versionCode這個int型的數字直接比較)

    2. 從服務端下載文件.

    正如本文標題所說,此方法會用到webclient接口來進行下載。它提供了很多用于下載的方法。

    webclient提供了同步和異常方法。同步方法會阻塞線程。它通常用于下載耗時較短的小文件。在這我們使用同步方法來下載INI文件。代碼如下:

    // New a webclient object
        WebClient web  = new WebClient();

    //Download synchronized 

    try {      string UserName = AutoUpdate.Form1.GetStringFromFile("UpdateInfo", "ID_USER_NAME");      string PassWord = AutoUpdate.Form1.GetStringFromFile("UpdateInfo", "ID_USER_PASSWORD");      web.Credentials = new NetworkCredential(UserName, PassWord);      web.DownloadFile(new Uri(ServerIniPath.ToString()), ItemSavePath);         } catch (System.Exception ex) {                        throw ex; }</pre>

    我們可以從INI文件中取得最新應用的下載路徑,如果需要下載它,我們應該使用異步方法.

    try
    {
        web.DownloadFileAsync(new Uri(DownLoadAddress), ItemSavePath);
        web.DownloadProgressChanged += client_DownloadProgressChanged;
        web.DownloadFileCompleted += client_DownloadFileCompleted;
    }
    catch (System.Exception ex)
    {
        throw ex;
    }

    從代碼我們可以看到當調用下載方法后,我們也為它添加了兩個事件handler(處理器)。這兩個handler可以告知我們下載的詳細信息,例如已下載百分比,已下載字節數等等。handler代碼如下:

    void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
       Action<AsyncCompletedEventArgs> onCompleted = progressCompleted;
       onCompleted.Invoke(e);
    }

    void client_DownloadFileProgresschanged(object sender, AsyncCompletedEventArgs e) {    Action<DownloadProgressChangedEventArgs> onCompleted = progressChanging;    onCompleted.Invoke(e); }</pre>

    方法progressCompleted和progressChanging可以按需實現。

    3. 下載異常.

    這個異常并不是通過try和catch捕獲的異常。這是一個真正的異常:網絡不可用,用戶取消更新,服務器不可用。因為我們使用異步方法進行下載,這會導致很多并發問題。接下來我會介紹我是如何處理它們的。

    網絡不可用.

    這個問題隨時都會發生,所以我需要啟用另一個線程,它會根據時間來檢查網絡狀態。一旦發現網絡斷開了,我會調用下載線程來通知用戶。

    如何檢查網絡狀態其實很簡單,我們可以使用 "wininet.dll"提供的方法。

    [DllImport("wininet.dll")]
      public static extern bool InternetGetConnectedState(out int lpdwFlags, int dwReserved);

    用戶取消下載:

    weblient已經考濾到了這種情況,它提供了cancel方法來停止下載和dispose方法釋放下載進程占用的資源。

    結束.

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!