• QML 从无到有 3 (自动更新)


    新的需求出来啦,需要自动更新功能,不怕程序升级了。

    自动更新,QML不好写,需要c++来辅助,这里就涉及QML中调用c++功能(这里就不写了,百度一下,很多)。

    思路:获取版本》下载程序》安装程序

    第一步,获取版本信息,可以通过XMLHttpRequest获取最新版本。

    第二步,下载程序,通过Qt c++的QtNetwork

    头文件:

     1 #ifndef ZRDOWNLOAD_H
     2 #define ZRDOWNLOAD_H
     3 
     4 #include <QObject>
     5 #include <QtNetwork/QNetworkAccessManager>
     6 #include <QFile>
     7 #include <QtNetwork/QNetworkReply>
     8 #include <QtNetwork/QNetworkRequest>
     9 #include <QIODevice>
    10 
    11 class ZRDownload : public QObject
    12 {
    13     Q_OBJECT
    14     Q_PROPERTY(QString url READ GetUrl WRITE SetUrl)
    15     Q_PROPERTY(QString fileName READ GetFileName WRITE SetFileName)
    16 public:
    17     explicit ZRDownload(QObject *parent = 0);
    18     ~ZRDownload();
    19 
    20     QString GetUrl();
    21     void SetUrl(QString u);
    22     QString GetFileName();
    23     void SetFileName(QString fn);
    24 private:
    25     QString url;
    26     QString fileName;
    27     QFile *file;
    28     QNetworkAccessManager *accessManager;
    29     QNetworkRequest request;
    30     QNetworkReply *reply;
    31 
    32 signals:
    33     void progressPosition(double pre);  //更新进度条信号
    34     void downloadFinished();            //结束信号
    35 
    36 protected slots:
    37     void httpDownload();
    38     void replyFinished(QNetworkReply*reply);
    39     void onDownloadProgress(qint64 bytesSent,qint64 bytesTotal);
    40     void onReadyRead();
    41 };
    42 
    43 #endif // ZRDOWNLOAD_H
    View Code

    CPP文件:

    #include "zrdownload.h"
    #include <QDebug>
    
    ZRDownload::ZRDownload(QObject *parent) : QObject(parent)
    {
        accessManager = NULL;
        reply = NULL;
    }
    ZRDownload::~ZRDownload()
    {
    }
    
    QString ZRDownload::GetUrl()
    {
        return url;
    }
    
    void ZRDownload::SetUrl(QString u)
    {
        url = u;
    }
    
    QString ZRDownload::GetFileName()
    {
        return fileName;
    }
    
    void ZRDownload::SetFileName(QString fn)
    {
        fileName = fn;
    }
    
    void ZRDownload::httpDownload(){
    
      file=new QFile(fileName);
      bool suc = file->open(QIODevice::WriteOnly);//只读方式打开文件
    
      accessManager=new QNetworkAccessManager(this);
    
      request.setUrl(url);
      
      /******************设置http的header***********************/
      // request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data");
      // request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
      // request.setRawHeader("Content-Disposition","form-data;name='doc';filename='a.txt'");
      //request.setHeader(QNetworkRequest::ContentLengthHeader,post_data.length());
    
    
      reply=accessManager->get(request);//通过发送数据,返回值保存在reply指针里.
      connect(accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));//finish为manager自带的信号,replyFinished是自定义的
      connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT( onDownloadProgress(qint64 ,qint64 )));//download文件时进度
      connect((QObject *)reply, SIGNAL(readyRead()),this, SLOT(onReadyRead()));
    
    }
    /***************响应结束**************************/
    void ZRDownload::replyFinished(QNetworkReply *reply){
      //获取响应的信息,状态码为200表示正常
      QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
      QByteArray bytes = reply->readAll();  //获取字节
      QString result(bytes);  //转化为字符串
    
      //无错误返回
      if(reply->error() == QNetworkReply::NoError)
      {
        QByteArray bytes = reply->readAll();  //获取字节
        QString result(bytes);  //转化为字符串
    
        file->flush();
        file->close();
        delete file;
        file=NULL;
      }
      else
      {
        //处理错误
      }
    
      reply->deleteLater();//要删除reply,但是不能在repyfinished里直接delete,要调用deletelater;
      reply=NULL;
    
      accessManager->deleteLater();
      accessManager=NULL;
    
      downloadFinished();
    }
    
    /***********更新进度条*************/
    void ZRDownload::onDownloadProgress(qint64 bytesSent, qint64 bytesTotal){
    
        double pre = double(bytesSent)/bytesTotal;
    
        progressPosition(pre);
    }
    
    void ZRDownload::onReadyRead(){
    
      file->write(reply->readAll());
    }
    View Code

    上面的代码也是修改网上的代码,增加了QML调用的信息。

    注意:项目文件pro中需要添加 QT += network

    main.cpp:

    添加 qmlRegisterType<ZRDownload>("xxx.xxx.ZRDownload", 1, 0, "ZRDownload");

    QML调用:

     

     1 ZRDownload{
     2         id:download
     3         url:"http://xxx.xxx.com/xx.apk"
     4         fileName:""
     5         onProgressPosition:progressBar.update(pre) //自定义更新进度条函数
     6         onDownloadFinished: {
     7             //下载完成
     8         }
     9     }
    10 
    11 //启动下载
    12 download.fileName=getAppPath();//设置保存目录,pc和安卓不同
    13 download.httpDownload();

     

    第三步,安装程序:

    不同平台,安装程序的代码也不同,PC平台使用QProcess启动安装程序,安卓平台通过QAndroidJniObject调用Activity实现。下面是代码:

     1 #ifndef ZRINSTALL_H
     2 #define ZRINSTALL_H
     3 
     4 #include <QObject>
     5 #include <QString>
     6 
     7 class ZRInstall : public QObject
     8 {
     9     Q_OBJECT
    10     Q_PROPERTY(QString fileName WRITE SetFileName)
    11 public:
    12     explicit ZRInstall(QObject *parent = 0);
    13 
    14     void SetFileName(QString fn);
    15 signals:
    16 
    17 public slots:
    18     void install();
    19 private:
    20     QString m_FileName;
    21 };
    22 
    23 #endif // ZRINSTALL_H
    头文件
     1 #include "zrinstall.h"
     2 #include <QDebug>
     3 #if defined(Q_OS_ANDROID)
     4 #include <QtAndroid>
     5 #else
     6 #include <QProcess>
     7 #endif
     8 
     9 ZRInstall::ZRInstall(QObject *parent) : QObject(parent)
    10 {
    11 
    12 }
    13 
    14 void ZRInstall::SetFileName(QString fn)
    15 {
    16     m_FileName = fn;
    17 }
    18 
    19 void ZRInstall::install()
    20 {
    21 #if defined(Q_OS_ANDROID)
    22     //安装apk
    23     QAndroidJniObject path = QAndroidJniObject::fromString("file://"+m_FileName);
    24     QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", path.object<jstring>());
    25     QAndroidJniObject param = QAndroidJniObject::getStaticObjectField<jstring>("android/content/Intent", "ACTION_VIEW");
    26     QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V",param.object<jstring>());
    27     QAndroidJniObject type = QAndroidJniObject::fromString("application/vnd.android.package-archive");
    28     QAndroidJniObject result = intent.callObjectMethod("setDataAndTypeAndNormalize", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;", uri.object<jobject>(), type.object<jstring>());
    29     QtAndroid::startActivity(intent, 1001, 0);
    30 #else
    31     //qDebug()<<m_FileName;
    32     QProcess * proc = new QProcess();
    33     proc->startDetached(m_FileName,QStringList());
    34     delete proc;
    35 #endif
    36 }
    CPP文件
    1 android{
    2     QT += androidextras
    3 }
    项目文件pro

    调用就不写了,可以参考上面download。

    这样整个版本自动更新就写好了,有一些细节自己需要注意,如下载安装文件不同,安装目录不同。

     

  • 相关阅读:
    easyui 获取分页栏中的行数(pageSize)和页码数(pageNumber)
    C# 跨盘符移动文件
    C# Json简单处理
    HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth之完全详解
    Jquery中的(function($){...})(jQuery)
    前端框架你究竟选什么
    Kindeditor使用心得
    jvm——内存模型
    jvm——NIO
    Java——静态类型 实际类型
  • 原文地址:https://www.cnblogs.com/SamFang/p/5996056.html
Copyright © 2020-2023  润新知