QT程序自动升级方案

基于QSimpleUpdater, 但是QSimpleUpdater无法在qml应用下使用,因此对其做了一定封装,,特点如下:

  • 依赖QSimpleUpdater,但是没有修改其任何代码;
  • 支持自定义下载文件名;
  • 自定义下载路径;
  • 灵活的嵌入到qml;

下面上代码

代码

qt.pro文件里面添加QSimpleUpdater依赖

include ($$PWD/QSimpleUpdater/QSimpleUpdater.pri)

C Class

qmlmqttclient.cpp

#pragma execution_character_set("utf-8")

#include "qmlUpdater.h"
#include <QDateTime>
#include <QDebug>
#include <QDesktopServices>
#include <QJsonDocument>
#include <QJsonObject>
QmlUpdater::QmlUpdater(QObject *parent) : QObject(parent) {

  m_updater = QSimpleUpdater::getInstance();
  m_downloader = new Downloader();

  connect(m_updater, SIGNAL(appcastDownloaded(QString, QByteArray)), this,
          SLOT(displayAppcast(QString, QByteArray)));

  connect(m_downloader, SIGNAL(downloadFinished(QString, QString)), this,
          SIGNAL(downloadFinished(QString, QString)));

  DEFS_URL = DEFS_URL +
             "?t=" + QString::number(QDateTime::currentDateTime().toTime_t());
  checkForUpdates();
}

QmlUpdater::~QmlUpdater() {}

void QmlUpdater::checkForUpdates() {
  /* Apply the settings */
  //  m_updater->setModuleVersion(DEFS_URL, "0.1");
  m_updater->setNotifyOnFinish(DEFS_URL, true);
  m_updater->setNotifyOnUpdate(DEFS_URL, true);
  m_updater->setUseCustomAppcast(DEFS_URL, true);
  m_updater->setDownloaderEnabled(DEFS_URL, true);
  m_updater->setMandatoryUpdate(DEFS_URL, true);

  /* Check for updates */
  m_updater->checkForUpdates(DEFS_URL);
}

void QmlUpdater::updateChangelog(const QString &url) {
  QString log = m_updater->getChangelog(url);
  qDebug() << "updateChangelog " << log;
  if (url == DEFS_URL) {
    //    setChangeLog(log);
  }
}

void QmlUpdater::displayAppcast(const QString &url, const QByteArray &reply) {
  if (url != DEFS_URL) {
    return;
  }

  /* Try to create a JSON document from downloaded data */
  QJsonDocument document = QJsonDocument::fromJson(reply);

  /* JSON is invalid */
  if (document.isNull()) {
    qDebug() << " update json is error!!";
    return;
  }

  /* Get the platform information */
  QJsonObject updates = document.object().value("updates").toObject();
  QJsonObject platform =
      updates.value(m_updater->getPlatformKey(url)).toObject();

  /* Get update information */
  QString m_openUrl = platform.value("open-url").toString();
  QString m_changelog = platform.value("changelog").toString();
  m_downloadUrl = platform.value("download-url").toString();
  QString m_latestVersion = platform.value("latest-version").toString();
  if (platform.contains("mandatory-update")) {
    bool m_mandatoryUpdate = platform.value("mandatory-update").toBool();
  }

  if (compare(m_latestVersion, m_updater->getModuleVersion(url))) {
    emit notifyUpdate(m_latestVersion, m_updater->getModuleName(url),
                      m_changelog);
  }
}

void QmlUpdater::finish(QString filepath) {
  QDesktopServices::openUrl(QUrl::fromLocalFile(filepath));
}

void QmlUpdater::startDownload() {
  QString path = QCoreApplication::applicationDirPath() + "/../"; //下载文件保存地址
  QString filename = m_downloadUrl.split("/").last();  //文件名

  qDebug() << "download path" << path;
  qDebug() << "download url" << m_downloadUrl << " file name " << filename;

  m_downloader->setUseCustomInstallProcedures(true);
  m_downloader->setUrlId(DEFS_URL);
  m_downloader->setDownloadDir(path);
  m_downloader->setFileName(filename);
  m_downloader->setMandatoryUpdate(true);
  m_downloader->startDownload(QUrl(m_downloadUrl));
}

bool QmlUpdater::compare(const QString &x, const QString &y) {
  QStringList versionsX = x.split(".");
  QStringList versionsY = y.split(".");

  int count = qMin(versionsX.count(), versionsY.count());

  for (int i = 0; i < count; ++i) {
    int a = QString(versionsX.at(i)).toInt();
    int b = QString(versionsY.at(i)).toInt();

    if (a > b)
      return true;

    else if (b > a)
      return false;
  }

  return versionsY.count() < versionsX.count();
}

头文件qmlUpdater.h

#ifndef UPDATER_H
#define UPDATER_H

#include <QObject>
#include <QSimpleUpdater.h>
#include <QSimpleUpdater/src/Downloader.h>

namespace Ui {
class QmlUpdater;
}

class QSimpleUpdater;

class QmlUpdater : public QObject {
  Q_OBJECT
public:
  explicit QmlUpdater(QObject *parent = nullptr);
  ~QmlUpdater();
  Q_INVOKABLE void checkForUpdates();
  Q_INVOKABLE void startDownload();

public slots:
  void finish(QString filepath);

private slots:
  void updateChangelog(const QString &url);
  void displayAppcast(const QString &url, const QByteArray &reply);

private:
  bool compare(const QString &x, const QString &y);

signals:
  void notifyUpdate(QString ver, QString name, QString log);
  void downloadFinished(const QString &url, const QString &filepath);

private:
  QString DEFS_URL = "http://wiki.developlink.cloud/vcom/updates.json";  //更新文件json地址
  QString m_downloadUrl;
  QSimpleUpdater *m_updater;
  Downloader *m_downloader;
};

#endif // UPDATER_H

qml 文件 UpdatePage.qml

import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
import QtQuick.Window 2.2
import QmlUpdater 1.0

Window {
    id: root
    property int space: 10
    property real progressValue: 0

    width: 400
    height: 300

    QmlUpdater {
        id: updater
        onNotifyUpdate: {
            root.visible =  true
            infoLabel.text = "发现新版本: " + ver + " " + name
            logText.text = log
        }
        onDownloadFinished: {
            console.log("onDownloadFinished")
            updater.finish(filepath)
            Qt.quit()
        }
    }

    Rectangle {
        id: rectangle
        ProgressBar {
            id: progressBar
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.leftMargin: space
            anchors.rightMargin: space
            height: 30
            from: 0
            to: 100
            value: progressValue
            onValueChanged: {
                //console.log("valueChanged:"+progressValue)
                if (value > 0 && value < 100)
                    okBtn.enabled = false
                else
                    okBtn.enabled = true
            }
        }

        TextEdit {
            id:  logText
            width: 341
            height: 150
            text: ""
            wrapMode: Text.WrapAnywhere
            anchors.top: tipLabel.bottom
            readOnly: true
            anchors.left: tipLabel.left
            anchors.leftMargin: 0
            anchors.topMargin: 0
        }

        Button {
            id: cancleBtn
            y: 243
            width: 80
            text: "取消"
            anchors.bottom: parent.top
            anchors.bottomMargin: -291
            anchors.left: parent.left
            anchors.leftMargin: 101
            font.bold: true
            font.pointSize: 12
            onClicked: close()
        }

        Button {
            id: okBtn
            width: 80
            text: "更新"
            font.bold: true
            font.pointSize: 12
            anchors.left: cancleBtn.right
            anchors.leftMargin: 45
            anchors.top: cancleBtn.bottom
            anchors.topMargin: -48
            highlighted: true
            onClicked: updater.startDownload()
        }

        Label {
            id: infoLabel
            text: "没有可用升级!"
            font.pointSize: 10
            anchors.left: parent.left
            anchors.leftMargin: 27
            anchors.top: parent.top
            anchors.topMargin: 25
        }

        Label {
            id: tipLabel
            width: 129
            height: 30
            text: qsTr("更新内容:")
            font.bold: true
            anchors.left: infoLabel.left
            anchors.leftMargin: 0
            anchors.top: infoLabel.bottom
            anchors.topMargin: 10
            font.pointSize: 12
        }
    }
}

/*##^##
Designer {
    D{i:4;anchors_x:27;anchors_y:81}D{i:5;anchors_x:98;anchors_y:298}D{i:6;anchors_x:235;anchors_y:298}
D{i:7;anchors_x:57;anchors_y:136}D{i:8;anchors_x:57;anchors_y:100}
}
##^##*/

使用

  1. main 里面注册qml类型
  qmlRegisterType<QmlUpdater>("QmlUpdater", 1, 0, "QmlUpdater");
  1. qml main page 里面实例化
import QtQuick 2.12
import QtQuick.Controls 2.5
import Qt.labs.settings 1.0

ApplicationWindow {
    visible: true
    width: 800
    height: 640

    UpdatePage {
        id: updatepage
        visible: false
    }
}

就这样,程序运行后自动检查更新服务器更新json文件;

  1. 服务器json文件,修改对应的verison,新程序下载链接,更新记录
{
  "updates": {
    "windows": {
      "open-url": "",
      "latest-version": "1.0",
      "download-url": "https://raw.githubusercontent.com/alex-spataru/QSimpleUpdater/master/tutorial/download/YesItWorks.jpg",
      "changelog": "This is an example changelog for Windows. Go on...",
      "mandatory": true
    },
    "osx": {
      "open-url": "",
      "latest-version": "1.0",
      "download-url": "https://raw.githubusercontent.com/alex-spataru/QSimpleUpdater/master/tutorial/download/YesItWorks.jpg",
      "changelog": "This is an example changelog for Mac OS X. Go on...",
      "mandatory": true
    },
    "linux": {
      "open-url": "",
      "latest-version": "1.0",
      "download-url": "https://raw.githubusercontent.com/alex-spataru/QSimpleUpdater/master/tutorial/download/YesItWorks.jpg",
      "changelog": "This is an example changelog for Linux. Go on...",
      "mandatory": true
    },
    "ios": {
      "open-url": "",
      "latest-version": "1.0",
      "download-url": "https://raw.githubusercontent.com/alex-spataru/QSimpleUpdater/master/tutorial/download/YesItWorks.jpg",
      "changelog": "This is an example changelog for iOS. Go on...",
      "mandatory": true
    },
    "android": {
      "open-url": "",
      "latest-version": "1.0",
      "download-url": "https://raw.githubusercontent.com/alex-spataru/QSimpleUpdater/master/tutorial/download/YesItWorks.jpg",
      "changelog": "This is an example changelog for Android. Go on...",
      "mandatory": true
    }
  }
}

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt自动升级程序通过HTTP同步下载是指利用Qt框架中的相关功能,实现软件自动升级时通过HTTP协议进行文件的同步下载。下面是基本的实现思路。 首先,我们需要在应用程序中编写自动升级的功能模块。这个模块负责检测是否有新版本可供升级,并在有新版本时触发升级过程。 其次,我们需要在服务器端建立一个存放更新文件的目录,并将最新的软件版本和对应的更新文件放置在该目录下。这个目录需要通过HTTP协议对外提供访问。 然后,在自动升级功能模块中,我们需要使用Qt框架提供的HTTP模块,通过HTTP协议访问服务器的更新文件目录。我们可以使用QNetworkAccessManager类和QNetworkRequest类来发送HTTP请求,并利用QNetworkReply类来接收服务器的响应。 在收到服务器响应后,我们可以根据需要下载的文件大小、下载进度等信息,使用QNetworkReply类提供的相关函数来实现文件的下载。在下载过程中,可以利用QFileDialog类提供的UI界面,实现文件下载的进度显示和用户操作(暂停、取消等)。 最后,下载完成后,文件将被保存在本地,我们可以使用QFile类提供的函数来完成文件的保存,然后通过Qt的相关机制进行文件的更新操作。 总结,Qt自动升级程序通过HTTP同步下载使用了Qt框架提供的网络模块,实现了软件自动升级时的文件下载功能。这个功能模块可以方便地应用到基于Qt开发的软件中,提供了一种简洁高效的更新机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值