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。

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

 

 

posted @ 2016-10-25 11:28  上位机  阅读(1635)  评论(0编辑  收藏  举报