将Python程序打包成App过程和排错

前言

最近写了一个Python工具,需求是要在Mac笔记本上使用。
(不依赖于DCC软件,独立运行)

因为工具依赖了一些第三方库,不可能在每台电脑上对这些库逐一进行安装。
想到最好的方法是将其打包成一个Mac App,并制作成一个dmg文件。

这样只需要分享这个映像文件,使用者只需双击安装使用即可。
在网上找到打包Mac App的库:py2app

于是开始了踩坑和一步步排错的过程。

使用py2app打包程序

1.首先安装py2app

1
pip install py2app

2.构建安装文件

1
py2applet --make-setup myApplication.py

(这里的myApplication.py为自己工具的主程序接口。)

3.配置setup.py文件

DATA_FILES 放自己写的模块,和一些附件(比如UI里插入的图片)。
OPTIONS 里配置App的图标(需要icns格式),和使用的第三方模块。

下面是一个参考:

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

Usage:
python setup.py py2app
"""

from setuptools import setup

APP = ['myApplication.py']
DATA_FILES = ['ui_logo.png'] # 附件
OPTIONS = {'iconfile': 'AppIcon.ICNS', # 图标
'packages': ['PySide2', 'shotgun_api3']} # 第三方库

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

4.打包App

python setup.py py2app

这里直接跳过了测试阶段,一般会先添加 -A 参数进行测试打包。
添加-A参数打包速度快,但是不会将依赖打包进去,打包出来的程序会很小。
这里就直接进行整体打包。(因为之前已经测试过了)

5.运行App并进行排错

打包完成可以看到当前目录多了dist和build两个文件夹。
进入dist文件夹可以看到打包好的app。
双击运行它:


程序报错崩溃了。
这个时候可以右键 - 显示包内容


进入到这个层级 myApplication.app/Contents/MacOS ,双击直接运行主程序。


这里可以通过终端观察到报错信息。


从报错信息可以看到,像是缺少了什么东西。
于是google搜了下,在无数帖子中找到了原因。
这里放个帖子链接:http://nfail.com/q/f6QYYx

是因为PySide2依赖shiboken2模块,而在打包后的这个模块中,
缺少libshiboken2-python2.7v.5.15.dylib文件。

解决方式就是直接从来源的shiboken2模块复制这个文件到App的包中。

cp ./venv/lib/python3.8/site-packages/shiboken2/libshiboken2.abi3.5.15.dylib ./dist/app.app/Contents/Resources/lib/python3.8/lib-dynload/shiboken2

这个时候双击再App图标,程序可以正确的运行了。
(至少在本机是正常运行了。)

将App封装成dmg映像文件

可以运行了,兴冲冲的就想把它封装成一个dmg文件并分享给同事。
这个过程网上很多讲解的,也比较简单。
这里参考的是知乎专栏的一篇帖子:https://zhuanlan.zhihu.com/p/56864296

1.打开磁盘工具,新建空白映像文件


填写必要参数:
文件名称自己定义,
大小则要根据自己App包的大小来定。
(不要和App包大小一样,要多预留一些)

2.配置映像文件

首先是将App包拷贝到映像文件中,这里打开终端,创建一个link

1
2
cd /Volumes/myApplication
ln -s /Applications Applications

这里可以看到应用程序的文件夹被link到了这里。


这样别人打开这个dmg文件后,直接拖动App包到Applications里,
程序就可以正常安装了。

在其他主机进行安装测试

拷贝这个dmg文件,到同事电脑进行安装。
双击运行app,果不其然的又报错崩溃了。


这里就出现了一个千古问题:
“在我电脑上可以用啊,为什么在你电脑上就不行?”
依旧按照惯例,右键进入包,直接运行主程序。


看起来同样是缺少了什么文件,但是这次没有提示是哪一个模块,哪一个包。
不过有了刚刚的经验,至少知道要怎么去解决这样的问题。

使用搜索功能,输入缺失的文件名libffi.7.dylib 。(在自己的主机上搜索)
因为我用的miniconda搭建的环境,所以在miniconda的文件夹中搜索到了这个文件。

现在问题来了,这个文件要拷贝到App包的什么地方。
观察App包的层级结构可以看到,基本上所有的依赖项都被放在了
app.app/Contents/Resources/lib 文件夹中。

于是尝试将刚刚找到的文件拷贝到这里,运行app。
又报错了!
庆幸的是这次的报错和上次的不一样,说明刚刚的问题已经解决了。
不过报错依旧是说缺少某个文件,重复上述的解决方法即可。

到了这里这次打包过程遇到的问题都解决了,
将刚刚提示缺失的所有文件手动复制到指定位置。
重新存储成dmg文件,然后就可以交差了。

总结

这次使用py2app对python程序进行打包,
主要遇到的问题就是,打包后依赖不全。
需要根据报错提示,从一步一步的去从源文件找到文件,手动拷贝到过来。
不过后来想想也有可能是我操作不当,在写setup文件的时候没有配置好。

文章是一次排错经历分享,如果觉得文章还不错或者有所帮助可以关注下公众号。
也欢迎大佬们一起讨论。