Python编写的桌面图形界面程序实现更新检测和下载安装

在Python中我们有很多种方案来编写桌面图形用户界面程序,譬如内置的Tkinter、强大的PyQt5PySide2,还有wxPython。借助这些或内置或第三方的模块,我们可以轻松地编写跨平台的桌面图形界面程序。

同时,我们还能直接使用PyInstallerNuitkacx_FreezePython第三方程序打包模块,将编写好桌面图形界面程序打包为各个平台的二进制可执行程序文件,比如Windows下的exe程序执行文件。

通常我们会将程序按需打包为单个的exe可执行文件或包含整个文件夹的可执行文件。

程序更新

随着版本的迭代和功能的优化,我们编写的程序会需要进行更新。

在 Web 应用中,这个问题几乎不需要处理,因为只要服务器更新了,浏览器打开的页面或功能都将是最新的。

而在桌面图形界面程序中,则有点棘手。因为我们打包好的程序都是离线分发的,按照以往的流程,我们需要重新打包程序,然后,在某个页面放上新版本程序的下载链接,最后提醒使用者下载更新。

如果使用者没有注意到,那么就凉拌了。

如何解决呢?我们需要在编写的桌面图形界面程序中,额外添加一个更新机制,用于检测更新、下载更新和完成更新。

下面我们来介绍一下这个流程。

检测更新

要实现程序的更新,我们首先需要让程序能够检测到软件存在更新。在这里,我们需要一个远程的更新服务器,来提供更新的检测响应。

然后,在程序启动的时候,调用一个子线程,向远程服务器发起请求,以获得是否需要进行更新。

下载更新

如果没有程序的更新,自然就略过了。

如果有程序的更新,我们就需要对新版本的程序进行下载。

下载有两种方式:

  1. 直接通过主程序进行下载;
  2. 编写一个单独的更新程序,主程序调用更新程序进行下载;

直接通过主程序进行下载的方式对于下载是可行的,但是没法自己覆盖更新自己。所以我们选择第二种方式。

主程序通过一个子线程使用subprocess.Popen()调用打包为单个文件的更新程序。

然后更新程序再核对一遍是否存在版本更新,如果存在更新,那么继续请求远程服务器,下载新版本的程序。

程序文件的下载,我们可以直接使用requests模块,示例代码如下所示:


def work(self):
    # 新建一个文件对象
    temp_file = os.path.join(self.download_path,'update.zip') # 指定更新包下载的路径
    logger.info("下载临时文件路径为:{}".format(temp_file))
    with open(temp_file,'wb') as self.fileobj:
        # 请求更新文件包
	f = requests.get(self.download_url, stream=True)
	# 写入文件
	offset = 0
	for chunk in f.iter_content(chunk_size=self.buffer):
	    if not chunk:
		break
	    self.fileobj.seek(offset)
	    self.fileobj.write(chunk)
	    offset = offset + len(chunk)
	    proess = offset / int(self.filesize) * 100
	    # logger.info("写入块:{},{}".format(offset,proess))
	    self.download_proess_signal.emit(int(proess))
	

 

解压覆盖

新版本的程序下载完,我们就需要将其解压到原有的文件夹了。这时候,更新程序和主程序分开打包的好处就出来了,我们通过更新程序将正在运行的主程序进程结束掉,然后将新版本的程序压缩包解压覆盖现有程序所在的文件夹:

def work(self):
    # 1.杀死主程序进程
    for proc in psutil.process_iter():
        if proc.name() == 'xxx.exe':
            proc.kill()
    # 2.获取程序本地路径
    current_path = os.path.dirname(os.path.abspath(__file__))
    logger.info("当前程序路径:{}".format(current_path))
    # 3.解压新版本压缩包到程序本地路径
    update_file_path = os.path.join(self.download_temp_path, 'update.zip')
    shutil.unpack_archive(
        filename=update_file_path,
        extract_dir=current_path
    )
    # 4.删除临时文件夹和文件
    os.remove(update_file_path)
    shutil.rmtree(self.download_temp_path)

这样,我们就实现了Python编写的桌面图形界面程序的更新检测、下载和覆盖安装。

猜你也喜欢

发表评论

邮箱地址不会被公开。