VB.NET: Actualizações Automáticas da Aplicação

As actualizações nos programas são frequentes e obrigam muitas as vezes a um trabalho moroso na actualização dos clientes finais (os utilizadores). Este processo pode e deve ser automatizado efectuando uma actualização directa de um servidor ou via Internet.

Um dos métodos aconselhados para fazer a distribuição e actualização das aplicações é o ClickOnce da Microsoft (mais informações em ClickOnce Deployment).

No entanto muitos programadores preferem não utilizar o ClickOnce por diversos motivos, com por exemplo, apenas permite fazer a actualização do executável, não permite indicar o local de instalação, não cria automaticamente os atalhos, etc.

Mas é possível criar o nosso próprio sistema de actualização da aplicação apenas com um ficheiro. É verdade que não é possível apagar um ficheiro quando este está a ser utilizado mas é possível renomeá-lo. Assim o sistema é simples:
1 – Verificar se existem actualizações
2 – Descarregar o ficheiro de actualização
3 – Renomear o executável para um nome diferente
4 – Renomear o ficheiro de actualização para o nome do executável
5 – Reiniciar a aplicação

É claro que são necessárias mais algumas validações pelo meio mas isto é o essencial!

É possível ler a versão directamente no ficheiro mas se o mesmo for grande então existe um grande tempo de espera para a verificação. Daí a utilizações de um ficheiro de actualização auxiliar (formato txt pela sua simplicidade).

Estrutura do ficheiro txt:
Linha 1 – Versão do ficheiro de actualização
Linha 2 – Ficheiro de actualização com a extensão .update
Linha 3 e restantes – Ficheiros a actualizar

Exemplo:
1.1.0.0
ftp://74.82.141.111/private/exemplo.exe.update
ftp://74.82.141.111/private/exemplo.dll
ftp://74.82.141.111/private/exemplo.xml

Vamos agora ver o código:

Imports System.IO
Imports System.Net

‘ ——————————————————
‘ Informação a alterar
‘ ——————————————————
Private updateServer As String = "74.82.141.111"
Private updateFileName As String = "ftp://74.82.141.111/private/demo_update.txt"
Private updateUserName As String = "username"
Private updatePassword As String = "password"
Private msgboxTitle As String = "Actualização da Aplicação"
Private connTimeout As Integer = 8000
‘ ——————————————————

‘ Constantes
Private Const delExtension As String = ".delete"
Private Const uptExtension As String = ".update"

‘ Variáveis
Private MyWebClient As New WebClient
Private txtInfo As String
Private txtInfoArray() As String
Private appFullName As String
Private appDirectory As String
Private appName As String

”’ <summary>
”’ Formatação da versão do ficheiro
”’ </summary>
”’ <param name="Version">String com a versão a formatar</param>
Private Function GetVersion(ByVal Version As String) As String
    Dim x() As String = Split(Version, ".")
    Return String.Format("{0:00000}{1:00000}{2:00000}{3:00000}", Int(x(0)), Int(x(1)), Int(x(2)), Int(x(3)))
End Function

”’ <summary>
”’ Apaga ficheiros antigos (caso existam)
”’ </summary>
”’ <param name="FileName">Nome do ficheiro</param>
Private Sub DeleteFile(ByVal FileName As String)
    Try

        Dim sFile As String = Dir(FileName)
        Do While sFile <> ""
            Try
                File.Delete(sFile)
            Catch ex As Exception
            End Try
            sFile = Dir()
        Loop

        Catch ex As Exception
            ‘ ignora o erro
    End Try
End Sub

”’ <summary>
”’ Inicia a verificação/update do ficheiro caso esteja disponível
”’ </summary>
Public Sub CheckUpdate()

    ‘ Informação da aplicação
    appFullName = Application.ExecutablePath.ToString
    appDirectory = Application.StartupPath.ToString + "\"
    appName = Application.ProductName.ToString

    ‘ Elimina os ficheiros antigos
    Call DeleteFile(appFullName + delExtension)

    ‘ Apaga updates antigos
    Call DeleteFile(appFullName + uptExtension)

    Try

       ‘ Verifica a existência do servidor onde está o ficheiro txt
        If Not My.Computer.Network.Ping(updateServer) Then Exit Sub

     ‘ Descarrega o ficheiro TXT para uma variável
       Dim networkCredentials As New Net.NetworkCredential()
        With networkCredentials
          .UserName = updateUserName
          .Password = updatePassword
       End With
      MyWebClient.Credentials = networkCredentials
       txtInfo = MyWebClient.DownloadString(updateFileName.ToString)

      ‘ Separa a variável em linhas
      txtInfoArray = txtInfo.Split(vbNewLine)

     ‘ Verifica a versão do ficheiros (original e update)
      Dim fInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(appFullName)
     Dim appVersion As String = GetVersion(fInfo.FileMajorPart + "." + fInfo.FileMinorPart + "." + fInfo.FileBuildPart + "." + fInfo.FilePrivatePart)
      Dim UpdateVersion As String = GetVersion(txtInfoArray(0))

     ‘ Verifica se é necessário fazer a actualização
      Dim UpgradeRequired As Boolean = UpdateVersion > appVersion

     ‘ Caso seja necessário actualizar
     If UpgradeRequired Then

         ‘ Confirma a intenção de actualizara aplicação
          Dim msgStart As String = "Existe uma nova actualização do programa." + vbCrLf + vbCrLf + "Deseja efectuar a actualização agora ?"
         Dim resultStart As DialogResult = MessageBox.Show(msgStart, msgboxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation)
         If resultStart <> Forms.DialogResult.Yes Then
             Exit Sub
         End If

          Application.DoEvents()

          ‘ Descarrega o ficheiro principal
          Dim updateName As String = txtInfoArray(1).Substring(txtInfoArray(1).LastIndexOf("/") + 1)
          My.Computer.Network.DownloadFile(txtInfoArray(1).ToString, appDirectory + updateName, _
              updateUserName, updatePassword, False, connTimeout, True)

          ‘ Caso existam mais ficheiros
          If txtInfoArray.Length – 1 >= 2 Then

               ‘ Descarrega o(s) ficheiro(s) que estão na lista
               For x As Byte = 2 To txtInfoArray.Length – 1
                  Try
                      ‘ Caso a linha não esteja em branco
                      If Not String.IsNullOrEmpty(txtInfoArray(x).Trim) Then

                          ‘ Nome e localização dos ficheiro
                          Dim updateFile As String = txtInfoArray(x).Trim
                          Dim updateFiles As String = txtInfoArray(x).Substring(txtInfoArray(x).LastIndexOf("/") + 1)

                         ‘ Inicia o Download do ficheiro
                          My.Computer.Network.DownloadFile(updateFile, appDirectory + updateFiles, _
                                               updateUserName, updatePassword, False, connTimeout, True)

                    End If
                Catch ex As Exception
                    ‘ Ignora os erro …
                End Try
            Next

       End If

        ‘ Verifica se está disponível o novo ficheiro
        If File.Exists(appDirectory + updateName) Then

            ‘ Renomeia o principal e depois o ficheiro a actualizar
            With My.Computer.FileSystem
                .RenameFile(appFullName, appName + ".exe" + delExtension)
                .RenameFile(appDirectory + updateName, appName + ".exe")
            End With

            ‘ Mensagem final de actualização
            Dim msgFinish As String = "Terminou a actualização da aplicação." + vbCrLf + vbCrLf + "Deseja reiniciar o programa agora ?"
            Dim resultFinish As DialogResult = MessageBox.Show(msgFinish, msgboxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information)
            If resultFinish = MsgBoxResult.Yes Then
                Application.DoEvents()
                Application.Restart()
            End If

        End If

     End If

    Catch ex As Exception
        MessageBox.Show("Ocorreu um erro na actualização do ficheiro. Mensagem original: " + ex.Message, msgboxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
End Sub

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!

Um comentário sobre “VB.NET: Actualizações Automáticas da Aplicação

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s