掘金 后端 ( ) • 2024-04-28 17:07

Windows下打包比较简单,pyinstaller -w start.py 一条执行完毕就ok了,MacOS下略复杂。记述下,以便后续复盘。

前提:当然要安装好python3环境,使用 brew install [email protected] 安装

执行 export PATH="/usr/local/opt/[email protected]/bin:$PATH"

source ~/.bash_profile && source ~/.zshrc

设python3.10为默认python

创建python虚拟环境

image.png

先创建个空白文件夹,比如 py,然后进入文件夹,打开终端,执行命令python3 -m venv venv,执行完毕后目录内多出一个 venv 文件夹,执行在终端中执行source ./venv/bin/activate激活该虚拟环境,激活成功后,终端最前方提示符会变为 (venv)

image.png

安装pyside6 pyinstaller

继续终端中执行 pip install pyside6 pyinstaller

创建py文件 app.py

app.py中输入以下代码

# -*- coding: utf-8 -*-
import sys

from PySide6 import QtWidgets
from PySide6.QtCore import Qt, QPoint
from PySide6.QtGui import QGuiApplication


class StartWindow(QtWidgets.QWidget):
    def __init__(self):
        super(StartWindow, self).__init__()
        self.width = 1200
        self.height = 700
        
        v1 = QtWidgets.QVBoxLayout()
        v1.addStretch(1)
        h1 = QtWidgets.QHBoxLayout()
        v1.addLayout(h1)
        v1.addStretch(1)
        
        h1.addStretch(1)        
        self.lab = QtWidgets.QLabel()
        self.lab.setText(f"你好啊,这是一个pySide6窗口")
        self.lab.setStyleSheet("""font-size:16px;color:#f00;text-align:center""")
        h1.addWidget(self.lab)
        h1.addStretch(1)
        
        self.setLayout(v1)

        # 窗口大小
        self.resize(560, 350)
        self.show()
        self.center()

   

    def center(self):
        screen = QGuiApplication.primaryScreen()
        screen_resolution = screen.geometry()
        self.width, self.height = screen_resolution.width(), screen_resolution.height()
        self.move( QPoint( int( (self.width - 560) / 2), int( (self.height - 350)/ 2 ) ) )


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    try:
        startwin = StartWindow()
    except Exception as e:
        print(f"error:{str(e)}")
    sys.exit(app.exec())

如果没错的话,现在你能看到一个窗口

image.png

将这个程序使用pyinstaller打包

继续前边的终端,确认提示符是否含有(venv)

输入打包指令pyinstaller --windowed app.py

--windowed 是禁止显示控制台参数,如果不添加,打开后会显示一个黑色终端窗口

等待执行结束。 在当前目录下会多出2个文件夹 distbuild,其中build可以忽略,重点关注dist这是打包后的执行文件所在目录。

└── dist
    ├── app
    │   ├── libcrypto.1.1.dylib
    │   ├── PySide6
    │   ...
    │   ├── app
    │   └── Qt5Core
    └── app.app

如上图所示,dist/app.app 就是mac上的可执行程序,双击应该能看到和上方一样的pyside6窗口。

dist/app则是一个文件夹,里面是封装好的所有依赖.目前可以忽略它

复制数据目录和资源文件

一般程序都会有额外的资源需要包含进去,比如图标、ini配置文件

假如这个程序里 app.py 同目录下还有1个文件夹 data 需要整个复制,有一个图标 icon.ico 文件也需要复制,那么将打包命令调整为

pyinstaller --windowed --add-data="data:data" --add-data="icon.ico:icon.ico" app.py

--add-data= 代表数据复制指令,格式为 --add-data=“原始资源目录或文件:要复制到目录或文件”,其中目标目录是相对于打包后的程序根目录。

导入额外包

一般情况下 pyinstaller 自动分析依赖并将用到的包都打包进去,但有时可能会丢失某些依赖包,这时执行打包后的程序会提示“not found module”错误。

在打包时,使用--hide-import=包名 指令列出要额外包含进的包,即可解决该问题。

比如我用到了 faster-whisperpytz包,打包后提示缺少,那么重新修改下打包命令,将这2个包包含进入,打包命令更新为

pyinstaller --windowed --hidden-import=faster-whisper --hidden-import=pytz app.py

构建 dmg 磁盘映像

在Windows下,直接将打包后的 dist/app 文件夹压缩为zip,分发即可。

但在苹果系统下, app.app是可执行的程序,但本质也是一个文件夹,改为zip扩展后发送给用户,再让用户改为app后缀,其实也是可以的,但显然不符合macos逻辑。正确的方法应该是构建一个dmg映像。

先将 dist 目录下的 app文件夹 删掉,只保留 app.app 可执行程序。

接着执行brew install create-dmg 安装 create-dmg 工具.

安装成功后,终端执行构建命令

create-dmg  
  --volname "app"  
  --window-pos 200 120  
  --window-size 600 300 
  --hide-extension "app.app" 
  --app-drop-link 425 120  
  "app.dmg" 
  "dist/"
  

如果未报错的话,执行后,将在 app.py 同目录内看到一个名为 app.dmg的文件。

image.png

双击则可安装,然后就能在启动中心看到该程序了。

更多pyinstaller打包用法

https://pyinstaller.org/en/v6.0.0/index.html