• 30 minutes
  • Moyenne
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Beaucoup d’entre vous aimeraient, qu’une fois leur programme terminé, les utilisateurs n’aient pas à se rendre sur un site web pour télécharger une nouvelle version et l’installer dès qu’une mise à jour à faite... Et bien c’est précisément ce que cet article vous aidera à faire. Avant de commencer, j’aimerais préciser que ce n’est pas la meilleure méthode si vous avez beaucoup de fichiers à mettre à jour mais qu’elle est très bien si la mise à jour ne concerne que le fichier principal (l’exécutable principal quoi). :)
Avant de commencer, il vous faudra un certain nombre d’éléments :

  • Un serveur FTP (pour stocker le fichier mis à jour ainsi qu’un fichier texte)

  • Qt (4.8 dans cet exemple)

  • Un compilateur (MinGW 4.4 dans cet exemple)

Tout d’abord, définissons ce que nous allons coder :

  • Une application principale (qui devrait être mis à jour, je l’appellerai  "application" tout au long du cours)

  • Une application secondaire, qui aura pour but de mettre à jour l’application principale (je l’appellerai  "updater" tout au long du cours)

L’application aura un bouton, il aura pour but de vérifier si une mise à jour est disponible.
L’updater, quant à lui, sera seulement doté d’une barre de progression pour suivre l’avancée du téléchargement. Dans la pratique, l’objectif sera de lancer l’application, d’appuyer sur un bouton pour vérifier que le logiciel est à jour, en récupérant le contenu d’un fichier texte sur le FTP, et de comparer la valeur avec une variable locale (propre au logiciel), et, le cas échéant, télécharger la mise à jour stockée sur le serveur FTP.

Mise en place de l'application

Pour commencer, et comme indiqué, nous allons créer l’application que l’on souhaite mettre à jour. Une fois terminée, elle ressemblera à ça :

Updater

Comme vous pouvez le voir, j’ai positionné un bouton qui nous permettra de faire la mise à jour ainsi qu’un label, pour bien montrer que le logiciel a bien été mis à jour, rien de superflu pour ne garder que l’essentiel (non, ce n’est pas une réplique de pub). :D
Niveau code, j’ai créé une classe tuto héritant de QWidget, dont voici le fichier d'en-tête :

#ifndef TUTO_H
#define TUTO_H
 
#include <QApplication>
#include <QtGui>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QCoreApplication>
#include <QUrl>
 
class tuto : public QWidget
{
    Q_OBJECT
 
    public:
        tuto();
 
    protected:
        QPushButton *updateSoftware;
        QNetworkReply *reply;
        QString version; // Version actuelle
        QString versionNew; // Version de la nouvelle version si elle existe
        QLabel label;
 
    public slots:
        void updater(); //Slot de mise à jour
};
#endif // TUTO_H

Rien de bien intéressant, passons donc au fichier source :

#include "tuto.h"
tuto::tuto() : QWidget()
{
    setFixedSize(225,75);
    setWindowTitle("Application | Tuto");
    version = "1.0"; //Mettez ici la version actuelle de votre application
                     //C'est ce string qui sera comparé pour déterminer s'il y a bien une nouvelle version (aurait pu être une define).
    
    label.setText("<strong>Version actuel :</strong>" + version);
    updateSoftware = new QPushButton("-- Vérifier la présence de mise à jour --", this);
    QVBoxLayout *VLayout = new QVBoxLayout(this);
    VLayout->addWidget(&label);
    VLayout->addWidget(updateSoftware);
    QObject::connect(updateSoftware,SIGNAL(clicked()),this,SLOT(updater()));
}
void tuto::updater()
{
    QNetworkAccessManager manager;
    reply = manager.get(QNetworkRequest(QUrl("http://site.fr/version.txt"))); // Url vers le fichier version.txt
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    updateSoftware->setEnabled(false);
    loop.exec();
    versionNew = reply->readAll();
    updateSoftware->setEnabled(true);
    if (version != versionNew)
    {
        QProcess *qUpdater = new QProcess(this);
        qUpdater->start("updater.exe");
        close();
    }
    else
    {
        QMessageBox::information(this,"Logiciel à jour", "Aucune mise à jour trouvée.");
    }
}

Détaillons tout cela : pour commencer, j’ai déclaré un QString version qui aura pour but de contenir la version actuelle du logiciel, afin de pouvoir être comparée avec la valeur contenue dans le fichier version.txt qui sera téléchargée plus tard. J’ai ensuite connecté le SIGNAL clicked() de mon bouton au SLOT updater() de ma fenêtre. Ce SLOT updater() va nous permettre de vérifier s’il existe une nouvelle version sur le serveur FTP.

Je ne vous refais pas un cours sur l’utilisation de la classe QtNetwork , puisqu’il en existe déjà un très bon ici-même. Nous lançons donc une requête avec comme paramètre l’URL de notre fichier version.txt que nous stockons dans notre QString versionNew. De là, on fait une comparaison avec les valeurs de version et versionNew : si les valeurs diffèrent, on lance notre updater et on quitte l’application, sinon, on informe l’utilisateur qu’aucune nouvelle version n’est disponible grâce à une boîte de message.

Voilà, la réalisation de l’application s’arrête ici. Passons maintenant à notre updater.

Mise en place de l'updater

Notre updater sera tout simple, une fenêtre contenant une barre de progression afin de tracker la fin du téléchargement, c’est amplement suffisant. Bien sûr, libre à vous de rajouter/personnaliser votre updater comme vous le voulez, j’essaye ici de minimiser les éléments graphiques afin de ne pas encombrer le code.

Niveau code, voilà le contenu du fichier d’en-tête (basique ) :

#ifndef UPDATERFEN_H
#define UPDATERFEN_H
 
#include <QApplication>
#include <QtGui>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QCoreApplication>
#include <QUrl>
 
class UpdaterFen: public QWidget
{
    Q_OBJECT
 
    public:
        UpdaterFen();
 
    private:
        QProgressBar *progression;
        QNetworkReply *reply;
        QNetworkAccessManager manager;
 
    public slots:
        void progressionTelechargement(qint64 bytesReceived, qint64 bytesTotal);
        void enregistrer();
 
};
 
#endif // UPDATERFEN_H

Comme précédemment, rien à commenter sur ce code, passons au fichier source, et plus précisement, au constructeur de ma classe UpdaterFen :

UpdaterFen::UpdaterFen() : QWidget()
{
//Windows Options
setFixedSize(258,112);
setWindowTitle("Updater");
 
progression = new QProgressBar(this);
progression->setValue(0);
 
reply = manager.get(QNetworkRequest(QUrl("http://site.fr/last/application.exe")));
 
connect(reply, SIGNAL(finished()), this, SLOT(enregistrer()));
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(progressionTelechargement(qint64, qint64)));
 
}

Ici, nous créons la requête qui va nous permettre de récupérer la nouvelle version de notre application depuis le serveur FTP. On connecte ensuite notre SIGNAL finished() de notre réponse au SLOT enregistrer() de notre application, ainsi que le SIGNAL downloadprogress() de notre réponse au SLOT progressionTelechargement() de notre application, qui va nous permettre de faire augmenter notre barre de progression en fonction du nombres de bytes téléchargés.

Voilà notre SLOT progressionTelechargement() :

void UpdaterFen::progressionTelechargement(qint64 bytesReceived, qint64 bytesTotal)
{
    if (bytesTotal != -1)
    {
        progression->setRange(0, bytesTotal);
        progression->setValue(bytesReceived);
    }
}

Ainsi que notre SLOT enregistrer() :

void UpdaterFen::enregistrer()
{
    reply->deleteLater();
    QFile lastversion("application.exe");
    
    if ( lastversion.open(QIODevice::WriteOnly) )
    {
        lastversion.write(reply->readAll());
        lastversion.close();
        QMessageBox::information(this, "Fin de téléchargement", "Téléchargement terminé !");
    }
    close();
}

Les étapes à suivre :

  • Création d'un QFile qui va représenter le fichier sur le disque dur

  • Test pour vérifier que l'ouverture du fichier se déroule bien

  • Écriture du fichier sur le disque dur

  • Fermer le fichier. La réponse du serveur se détruit.

Puis on informe l’utilisateur que le téléchargement est terminé. Enfin, si vous vouliez, par exemple, écrire le fichier dans un dossier plus « haut »
dans l’arborescence, il vous suffirait de faire précéder le nom de votre application par ../ lors de sa création.

Voilà, c’est la fin de ce cours, n’hésitez pas à me faire vos retours, à m’indiquer si le cours comporte des erreurs, que ce soit orthographique ou technique. Je compte, du moins, j'espère avoir le temps d'améliorer ce cours dans le futur en y ajoutant une seconde partie sur le téléchargement de plusieurs fichiers via un parsing de fichier XML/JSON. ;)

Exemple de certificat de réussite
Exemple de certificat de réussite