在 Windows 下开发的 Python 程序可以通过 pyinstaller 来打包。在 Mac 下可以使用 py2app 来打包 Python 程序。

生成程序图标

Mac 下程序图标扩展名是 icns,Mac 下自带有程序能够生成这种类型的图标。假设我们有一个 png 图像想要制作为 Python 程序的图标,那么我们可以使用如下的程序 icon.py 生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Jinzhong Xu
# @Contact : jinzhongxu@csu.ac.cn
# @Time : 2023/4/12 21:41
# @File : icon.py
# @Software : PyCharm

"""生成应用程序图标"""
import os
from datetime import datetime


def icons(img_path, icon_name, save_path='.'):
"""
通过Mac自带命令生成Python程序图标
:param img_path: PNG图像地址
:param icon_name: 图标名称
:param save_path: 图标保存路径
:return: icns 图标
"""
# 创建临时目录,存放不同大小的中间图像文件
tmp_iconset = os.path.join(os.path.dirname(img_path), datetime.now().strftime("%Y%m%d.%H%M%S_") + "tmp.iconset")
os.makedirs(tmp_iconset)
# 生成不同尺寸的中间图像
sizes = [2 ** x for x in range(4, 10)]
for size in sizes:
tmp_icon_name = f"icon_{size}x{size}.{os.path.splitext(img_path)[-1][1:]}"
cmd = f"sips -z {size} {size} {img_path} --out {os.path.join(tmp_iconset, tmp_icon_name)}"
os.system(cmd)
tmp_icon_name2 = f"icon_{size}x{size}@2x.{os.path.splitext(img_path)[-1][1:]}"
cmd2 = f"sips -z {size * 2} {size * 2} {img_path} --out {os.path.join(tmp_iconset, tmp_icon_name2)}"
os.system(cmd2)
# 把中间图像生成图标文件
save_icon = icon_name + '.icns'
cmd_icns = f"iconutil -c icns {tmp_iconset} -o {os.path.join(save_path, save_icon)}"
os.system(cmd_icns)


if __name__ == "__main__":
img_path = './resources/assets/cell.png'
icons(img_path=img_path, icon_name='Icon', save_path='./resources/assets')

程序 icon.py 运行成功后,在目录 save_path 下会生成 Icon.icns 程序图标文件。

py2app 打包程序

安装 py2app

1
pip install py2app

生成 setup.py

进入项目主目录,假设程序的入口函数是 XImage.py,那么运行如下命令

1
py2applet --make-setup XImage.py

此时,会在项目主目录生成 setup.py 文件。编写 setup.py,增加图标内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"""
This is a setup.py script generated by py2applet

Usage:
python setup.py py2app
"""

from setuptools import setup

APP = ['XImage.py']
DATA_FILES = []
OPTIONS = {'iconfile': './resources/assets/Icon.icns', # 程序显示图标
'resources': ['resources'], # 静态资源
'plist': {'CFBundleShortVersionString': '0.04'}, # 程序基本信息
"packages": ["PIL", ]} # 手动指定需要打包进程序的第三方Python包,PIL默认不能自动打包进去

setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)

注意:

  1. 在使用 PyQt5 编写 Python GUI 程序时,可能需要增加上 import matplotlib.backends.backend_tkagg,但是在 Mac 打包时须要注销掉;
  2. Mac 中字体选择系统有的,不要选没有的,我的是在 Windows 上开发,拷贝到 Mac 打包,出现宋体错误,需要在 QtDesigner 中取消掉所有宋体。

清理构建目录

1
rm -rf build dist

构建程序

1
2
3
4
# 别名模式,本地测试使用。没有将完整的 python 环境、第三方库打包到 app 中。运行程序完全依赖该电脑的 python 环境和第三方库
python setup.py py2app -A
# 把程序依赖的 python 环境、第三方库都打包进程序,一般将程序放在其他的mac电脑中,可直接运行
python setup.py py2app

此时,就在主目录下的 dist 里面包含有 XImage.app 的应用程序。

问题

出现运行问题,可以在命令行输入如下内容调试,可以看到错误提示:

1
2
3
4
# 进入项目主目录
cd /Users/jinzhongxu/projects/image0.04/image
# 打开打包后的程序,我这里程序名为 XImage
dist/XImage.app/Contents/MacOS/XImage

实际打包时,运行程序出现 libffi.8.dylib 找不到,因此,需要把本机中的 libffi.8.dylib 拷贝到打包后的程序中。

1
2
3
4
5
6
7
# 先从本机寻找 libffi.8.dylib
sudo -i
find / -name "libffi.8.dylib" -type f
# 进入项目主目录
cd /Users/jinzhongxu/projects/image0.04/image
# 拷贝本机的 libffi.8.dylib 到打包后的程序中
cp /usr/local/Cellar/libffi/3.4.3/lib/libffi.8.dylib dist/XImage.app/Contents/Frameworks/libffi.8.dylib

pyinstaller 打包程序

不需要手动创建并编辑 setup.py 文件,使用类似下面的程序即可打包

1
2
3
4
5
6
7
8
9
# -w  表示打包程序为 app,不包括“黑色”运行窗口
# Mac 下使用 icns 图标,Win 下使用 ico 图标
# --add-data SRC:DEST,把静态资源添加到打包后的程序中,不要使用 ;
import os

if __name__ == '__main__':
cmd = "pyinstaller XImage.py -w --clean -i resources/assets/Icon.icns --distpath release0.06" \
" --add-data resources:resources"
os.system(cmd)

注意:如果程序中使用了多进程 multiprocessing,则需要则主程序中增加如下内容:

1
2
3
4
5
6
7
8
9
10
import multiprocessing

# pass

if __name__ == '__main__':
multiprocessing.freeze_support() # pyinstaller 需要该语句来在打包后的程序中运行多进程程序,否则会打开多个主程序窗口。py2app 无法使用该方法运行多进程程序。
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

参考文献

  1. py2app 2.0a0 documentation
  2. Mac 系统使用 iconutil 生成 App 图标
  3. 快速生成 Mac App icns 图标
  4. 知识储备 – 用py2app将Python代码打包成MacOS可用的APP
  5. py2app-python打包工具