好久没有写文章了,这次介绍一种简单的PC客户端软件升级方案,从客户端到后台实现都是亲自手撸代码实现,并且在实际项目中应用(一般本人介绍的技术方法或者方案都是在实际项目中真实应用,并且介绍的案例都是基于真实项目),话不多说,进入正题。
1 技术背景
PC客户端软件:这里的客户端软件是本人自己业余做的一款机器人控制软件,使用C++/Qt开发;
软件更新后台:使用Python语言开发,web框架采用Flask;
2 更新步骤
好吧,我承认我不会画图,我会认真学习的。但是图糙理不糙,更新过程中前后台的交互就如同上图所示,只需要两步:第1步是客户端软件向发送请求获取最新的版本信息;第2步是客户端软件根据第一步的结果来下载最新版的客户端软件。下面详细介绍这两个过程使用的技术和实现方法:
2.1 客户端发送请求获取最新版本信息
这是更新流程的第一步,我采取的方法是在客户端启动之后便发送一次http请求,根据预先定义好的接口(这里的接口下面介绍后台实现的时候介绍)请求向后台获取最新的版本信息(获取到的版本信息具体有哪些,在介绍后台接口实现的时候会详细介绍,这里最重要的信息主要包括两个:一个是版本号,一个是最新版软件的下载地址),然后将获取到的版本号跟当前软件的版本号进行比较,如果最新软件的版本号大于当前软件的版本号,则客户端弹框提示当前软件有新版,询问客户是否需要更新,如果更新,则客户端根据后台返回的下载地址进行下载。
2.1.1 如何发送请求获取最新版本信息
这里我定义的软件最新版本的后台api是http://domainname/api/software/check_version,这里的url中的domainname可以是后台域名也可以是ip:port的形式,在客户端软件中,我使用的http库是Qt的QNetworkAccessManager库,关于QNetworkAccessManager的用法这里不做过多介绍,Qt的文档里面很详细,下面是客户端软件中发出请求的一段代码:
QNetworkRequest
上面代码里面networkAccessMgr()方法返回的是QNetworkAccessManager的实例,由于获取最新版本信息的接口是get请求,故只需要调用QNetworkAccessManager的get方法即可,QNetworkRequest是Qt用来封装请求地址,请求头,请求参数等,QNetworkReply是Qt用来封装请求的响应。
2.1.2 如何根据最新信息判断是否有新版本软件
发送请求之后,后台接收请求会查询数据库中最新的版本信息,然后封装成json格式返回,客户端接收到之后处理返回来的数据,还是拿一部分实际代码来说明吧:
QJsonObject
上面是客户端代码中收到后台请求之后,根据返回的http响应来提取返回的结果,QNetworkReply的readAll()方法会读取http响应的body部分,由于返回的是json结构,所以使用QJsonDocument::fromJson的静态方法来从QByteArray中格式化json成QJsonObject方便使用,这里的m_soft_update_date_item_->updateFromJson(jsonObj.value(“data”).toObject());这一句主要就是把json结构数据转换成本地实体类结构,展示一下该方法的实现就知道返回的json里面主要包含的字段信息了:
void
从上述代码的注释中可以看到包含的主要信息,这里我们就先关注major_version,minor_version,fixed_version以及filepath即可,现在有了后台返回的最新版本信息,则只要跟软件中当前的版本号比对即可,下面是对处理数据后发出的信号reqLatestVersionResponse做的处理,也是比对版本号的代码:
void
以上代码主要是用服务器返回来的版本信息与软件当前的版本信息比较,看看当前版本是否低于服务端的最新版本,如果低于,则提示用户更新,上面代码中的三个常量值分别是客户端软件中标记当前的版本号,并且每次软件更新会修改这几个版本号再编译打包
const
2.1.3 下载最新版本并安装
如果有最新版本,客户端软件可以弹框提示用户是否需要更新,可以像下面这样提示
点击更新按钮,便可以开始从后台下载最新安装包,在2.1.2中说的后台返回来的最新版本信息中包含了相对下载路径,这里便可以用来生成后台下载路径了
bool
上面是下载安装包文件的代码,由于我后台有个统一下载文件的地址前缀,http://domainname/download/相对下载路径,只要把url中的相对下载路径部分改成上面后台返回来的相对下载路径就是安装包文件的下载地址了,从上面可以看到,客户端下载文件也是使用QNetworkAccessManager,因为下载文件在网络层来说也是http请求,至于如何使用QNetworkAccessManager下载文件,Qt的文档里面有例子,这里不做过多介绍。这里将下载下来的文件写入指定的目录即可,我是保存在程序目录下的downloads目录,下载完成之后先执行安装包程序,再退出当前程序即可,这样升级过程的客户端操作便完成
// 进行安装操作
上面两句代码,第一句是使用QProcess::startDetached()分离式启动刚刚下载的安装包文件,第二句便是退出当前的客户端程序。
2.2 客户端软件升级的服务端实现
服务端采用的是Python语言编写,使用的web框架是Falsk,数据库使用Mysql,部署在阿里云上,这里不介绍整个实现过程,后面我会单独写一遍文章来介绍基于Flask的web项目的部署,接下来介绍的内容可能需要一定的web开发的知识才能够看懂。下面是软件版本信息存储在mysql中的表结构
class
然后是从数据表中查找最新版本信息的方法
def
从上面可以看出,后台的ORM使用的是SQLAlchemy库,有了service层的方法,则下面便是获取最新版本信息的接口了
api
这里的make_api_response是自己封装的方法,主要是讲service层的返回结果以json格式的数据发送出去,这便是最新版本信息接口的实现了,没啥好说的,如果不理解,可以学习一下web开发的知识,可以学习Flask框架作为web开发的入门框架,上手快。
接下来便是文件下载功能的实现了,也是直接上代码
from
主要使用了flask的send_file方法。
3 小结
至此,PC客户端的在线更新功能的实现方案就介绍完了,当然,这是我自己在实际项目中写的一种升级方案,因为之前看了一些现成的或者开源的工具实现,觉得太麻烦了,刚好自己也在学习后台开发方面的知识,便写了这么一种简单的升级方法。其实上面介绍的还是比较笼统的,很多细节我也没有展开说,特别说后台实现那一块,因为后台实现那一块展开说的话就要把如何使用Flask进行web开发给介绍一遍了,没这个必要。其实要是会一些web后台开发的知识的话,无论使用哪一种web框架实现上述的升级功能都很简单,因为很多东西框架已经为你做好了,这就是轮子的作用吧,反而是客户端那边的实现会有一些难度,更何况是用C++编写的客户端。