如何从具有PySide2 GUI的Python脚本构建Mac OS应用程序?

18

背景:

我正在使用 PySide2 GUI 开发一个简单的 Python 应用程序。它目前在 Windows、Linux 和 Mac 上都运行良好。在 Windows 上,我可以使用 PyInstaller 和 InnoSetup 构建一个简单的安装程序。然后我尝试在 Mac 上做同样的事情。很快就出了问题,因为系统拒绝启动由 PyInstaller 生成的命令或应用程序,原因是它没有正确签名。而我不是苹果开发者,无法签署任何内容。

经过一些研究,我尝试了 py2app。我在这里可以进行更进一步的操作。使用

python setup.py py2app -A

我可以创建可运行的应用程序,但很明显无法在其他系统上移植,因为它使用了我的开发文件夹。如果我使用 python setup.py py2app,生成的程序无法启动,因为py2app没有复制所有需要的Qt组件。我尝试逐个添加缺失的库,但最终系统找不到插件,我放弃了...

问题:

有人能帮我提供一份将使用Qt GUI的Python脚本或软件包转换为Mac便携式应用程序的方法吗?理想情况下,该方法应说明如何使用自定义应用程序图标,但这不是必需的。

参考文献:

  • Python 3.8.5
  • macOS 10.15.7 Catalina
  • PySide2 5.15.1
  • PyInstaller 4.0
  • py2app 0.22

由于我的真正软件包太大了,无法在SO上展示,我将其缩小为一个最小可重现示例:

from PySide3.QtWidgets import *
import sys


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        hello = QLabel('Hello', self)
        hello.move(50, 50)

def run(args):
    app = QApplication(args)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    run(sys.argv)

这是用于py2app的setup.py文件:

from setuptools import setup

APP = ['app.py']
DATA_FILES = []
OPTIONS = {}

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

setup.py 中有一个拼写错误,导致它无法运行。 - anon01
你可以查看这个链接:https://medium.com/python-pandemonium/part-1-of-2-setup-create-a-python-project-with-gui-on-mac-123b37e991d8。这是关于在Mac上设置并创建一个带有GUI的Python项目的第一部分。 - Sakib Ahammed
请查看 https://www.learnpyqt.com/pyside2-book/。 - Sakib Ahammed
@anon01:我的错。通常我会复制粘贴代码以避免打错字,但这次不行。 - Serge Ballesta
以下是关于将 PyQt5 和 PySide2 应用程序打包成 Windows 可执行文件(.exe)的教程,使用的工具是 PyInstaller。这会对您有所帮助。 - Divyessh
@Divyessh:我已经成功地在Windows上使用了PyInstaller。我的问题只出现在macOS上。 - Serge Ballesta
6个回答

13

要求

  • 兼容 Python 3.8.5
  • macOS 10.15.7 Catalina
  • 使用 PySide2 和 py2app

问题

  • PySide2 必须在 OPTIONS 下添加到包列表中
  • 应用程序运行时仍会出现错误:Library not loaded: @rpath/libshiboken2.abi3.5.15.dylib, Reason: image not found

解决方案

略微修改的 setup.py 可能如下所示:

from setuptools import setup

APP = ['app.py']
DATA_FILES = []
OPTIONS = {
    'packages': ['PySide2'],
    'iconfile': 'some_icon.icns',
    'plist': {
        'CFBundleDevelopmentRegion': 'English',
        'CFBundleIdentifier': "com.ballesta.xxx",
        'CFBundleVersion': "1.0.0",
        'NSHumanReadableCopyright': u"Copyright © 2020, Serge Ballesta, All Rights Reserved"
    }
}

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

此外,已添加图标定义和一些基本信息的plist条目。

整个构建最好由类似于以下的脚本触发:

#!/bin/sh
python3 -m venv venv
. venv/bin/activate
pip install PySide2
pip install py2app
python setup.py py2app      
cp ./venv/lib/python3.8/site-packages/shiboken2/libshiboken2.abi3.5.15.dylib ./dist/app.app/Contents/Resources/lib/python3.8/lib-dynload/shiboken2

测试

这是一次测试运行的截图:

屏幕截图


2
一份详细的答案,包括完整的工作示例和演示。谢谢! - Serge Ballesta
1
谢谢,这是第一组实际可行的指令,用于构建pyside2应用程序的app bundle!您知道为什么需要这个“libshiboken2”但不会自动添加到bundle中吗? - Ralf Ebert
@RalfEbert 我没有更多的信息,但我认为这可能只是一个错误。 - Stephan Schlecht

1

在尝试了很多不同的选项后,我发现以下步骤可以很轻松地构建macOS PySide2应用程序束

使用pyinstaller创建macOS应用程序束的这个配方是在macOS Catalina 10.15.7上使用Python 3.9.1、PySide2 5.15.2和pyinstaller 4.2测试的。

  • Install pyenv and latest Python with Framework support (see Pyenv, How to manage multiple Python versions and virtual environments for a general introduction into how pyenv works):

    brew install pyenv
    PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.9.1
    
  • Create a folder for the example, create an example pyside application:

    mkdir hello && cd hello
    nano hello.py
    

    hello.py:

    import sys
    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtWidgets import *
    
    class MainWindow(QMainWindow):
    
        def __init__(self):
            QMainWindow.__init__(self)
            self.setWindowTitle("Hello World")
    
            self.button = QPushButton("Click me")
            self.button.clicked.connect(self.say_hello)
    
            self.setCentralWidget(self.button)
    
        @Slot()
        def say_hello(self, url):
            self.button.setText("Hello!")
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
    
        window = MainWindow()
        window.show()
    
        sys.exit(app.exec_())
    
  • Create a venv for the project, install python packages:

    pyenv local 3.9.1
    python3 -m venv venv
    source venv/bin/activate
    pip install pip pyside2 pyinstaller --upgrade
    
  • Try running the app using the python interpreter:

    python3 hello.py
    
  • Create a macos app bundle:

    pyinstaller --windowed hello.py
    
  • Run the app using the app bundle:

    open dist/hello.app
    
  • Check out the generated hello.spec for the build configuration, re-build the app with pyinstaller hello.spec.


1
我认为你缺少的是在应用程序包中包含Python3框架。最近我自己开发了一个简单的macOS应用程序,但我想更深入地了解如何做到这一点,因此我对应用程序的实际结构进行了一些挖掘。基本上,您将把所有内容放入一个名为应用程序名称的普通文件夹中。将此文件夹命名为MyApp。在这个文件夹里面我们会有另一个叫做Contents的文件夹。据我所知,py2app只需要将组成您的应用程序的所有东西放在这个文件夹中,并创建一个Info.plist文件,该文件也位于Contents文件夹中。到目前为止,您已经有了以下内容:
除了包含所有必要属性Info.plist文件外,在您的Contents文件夹中,至少还有一个MacOS文件夹和一个Resources文件夹。您的问题在于还需要一个Frameworks文件夹,您需要在其中添加所需版本的Python。
现在,您的应用程序层次结构应如下所示: MyApp - > Contents - > -> Info.plist - > -> MacOS - > -> Resources - > -> FrameworksFrameworks文件夹中,您可以放置完整的Python 3框架以构建应用程序,以及运行应用程序所需的任何site-packages,并且您可以反映所有这些更改到可执行文件中,以便您指向正确的安装。
据我了解,在MacOS上使应用程序功能正常所需的全部是确保您的主可执行文件位于MacOS文件夹中,并指向位于Frameworks文件夹中的Python,您的图标.icns文件位于Resources文件夹中,以及构建了您的Info.plist文件。
为了让MacOS将其识别为完整的应用程序,我认为您可能需要使用productbuild并包括开发者许可证证书,但只有在您想要分发应用程序时才真正需要。否则,我只是将扩展名.app添加到MyApp中,这将其转换为应用程序。
没有上述提到的许可证/证书,它可能无法识别应该找到您的图标文件并添加它,因此如果在Preview中打开它,选择全部,然后复制它,您应该能够右键单击应用程序,按“获取信息”,并将图标粘贴到窗口中的当前图标上以使其正确显示。
编辑:我学习制作macOS应用程序的资源: Bundle结构 包括框架 签署您的应用程序 {{link4:productbuild命令手册}}

谢谢您的回答。它有助于了解macOS应用程序的内部情况。框架包含的要点可能是手动构建应用程序的一种可能方式。我还提供了一个提示,即链接到Python以调用自己的PySide2代码的本地/C应用程序应该可以工作。如果我无法让py2app完成工作(如果我不使用PySide2,它会做什么...),我将尝试一下。 - Serge Ballesta
PySide2只是GUI包。即使我使用Tkinter构建了我的应用程序,相同的原则仍然适用。为了使生活变得更加轻松,您可以将Python的版本传输到Frameworks文件夹中(复制您在应用程序之外使用的任何版本),然后调用该Python的pip安装程序来下载PySide和Qt。我相信这将确保它们安装在您的应用程序内部。只需使用path/to/app/python3 -m pip install PySide2 PyQt5 - jthree8

1
如果您想为OSX打包,您应该选择以下之一:

创建一个Brew Tap

这对于开源开发人员可能是最有意义的

通用说明 https://docs.brew.sh/How-to-Create-and-Maintain-a-Tap

  • 将您的代码托管在git中(不需要是GitHub)
  • 创建一个Formula(Formula Cookbook
  • 在GitHub上fork homebrew-core
  • 添加您的Formula并创建一个pull request以将其合并到主repo中
  • 支持您的pull request以使其完成

加入Apple开发计划

这对于闭源开发人员可能是最有意义的

概述:https://developer.apple.com/programs/how-it-works/

这个程序每年需要花费99美元,但是可以让你自己或在他们的应用商店上签署和分发你的软件包/二进制文件。
创建账户后,这里有一个打包和签名OSX的指南https://developer.apple.com/forums/thread/128166
- 结构化你的代码以支持签名(添加一个构建步骤将你的工作复制到一个干净的路径中,以避免繁琐的重新工作)。 - % codesign -s <Developer ID Application signing identity> /path/to/code - 选择一个存储格式(.zip.dmg.pkg)并将你的应用程序捆绑为它。

1
感谢提供有关如何为macOS构建应用程序的通用信息。 brew 部分可能会有所帮助。但是,我目前遇到的问题集中在Qt for Python(PySide2)应用程序上,您的答案并没有真正解决我的问题。 - Serge Ballesta
@SergeBallesta 希望对后来的用户有所帮助!看起来您的Qt部分通过安装程序运行良好,但是您正在努力自己签名或跳过安装程序并将依赖项管理上移。 - ti7

0

我已经成功使用fbs构建了应用程序。

它旨在构建Python+PyQt5应用程序(您也可以使用PySide2),并且应该在Mac OS上工作(根据文档/教程)。

使用PyInstaller时,由于包含PyQt5依赖项(特别是在使用pyqtgraph时),它经常失败,但使用fbs却非常好用。


你能确认你是否成功在macOS Catalina上运行了链接的教程吗?在我的系统上,命令“fbs run”可以正确地显示一个漂亮的窗口,但是“fbs freeze”会出现错误:“7136 ERROR: Can not find path ./libshiboken2.abi...” - Serge Ballesta

0

我认为您的问题的解决方案可以在这里找到。首先,创建虚拟环境并将所有模块安装到同一虚拟环境中。

mkvirtualenv --python="PATH/TO/PYTHON3.6.5/python.exe" venv

安装Qt框架
# Install qt via homebrew
brew install qt
# Switch to version 5.11.1
brew switch qt 5.11.1
# Do this to link qmake with qt
brew link qt5 --force

然后,安装PySide2

git clone --recursive https://code.qt.io/pyside/pyside-setup

之后,

 cd pyside-setup && git checkout 5.11

构建并安装PySide2,确保设置与Qt安装一起的QMAKE路径。

#To get the path
 which qmake
# Make sure that your virtual environment is activated
# Build PySide2 from source
python setup.py install --qmake=<PATH/TO/QMAKE> --build-tests --ignore-git --jobs=8
# Install PySide2
python setup.py build --qmake=/path/to/qmake --build-tests --ignore-git --jobs=8

更新

首先,请确保您在相同的虚拟环境中运行代码,并且要将其转换为标准的macOS应用程序,您可以使用py2apppyinstaller。此外,如果您按照相同的过程进行操作后仍无法使用当前版本的py2app,请尝试降级。

sudo easy_install py2app
#or
pip install -U git+https://github.com/metachris/py2app.git@master

创建 setup.py 文件

py2applet --make-setup app.py
Wrote setup.py

你需要创建一个配置文件或者查看这个例子,并且包含任何你拥有的文件。

from setuptools import setup

APP = ['app.py']
DATA_FILES = []
OPTIONS = {
    'argv_emulation': True,
    'iconfile': 'app.icns'
}

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

构建应用程序请使用

python setup.py py2app -A

要运行应用程序,您必须使用这种方式

./dist/app.app/Contents/MacOS/app

如果使用 python setup.py py2app -A 没有问题,那就表示一切正常,你需要使用它。

rm -rf build dist
python setup.py py2app

如果出现任何问题,请参考这些参考资料123。此外,还有替代方法将您的应用程序转换为操作系统。

在阅读了您的评论后,我尝试查看问题所在并发现了this,它可能解决问题,或者您可以使用其他工具,如bbFreezepyInstallercx_Freeze


1
谢谢您的回答,但这是关于在macOS上使用PySide2的问题。这部分已经解决了,如果我使用python3 app.py,它可以正常运行。我的问题是,我想将其转换为标准的macOS应用程序,就像我可以使用PyInstaller和InnoSetup为Windows构建可安装的独立程序一样。 - Serge Ballesta
@SergeBallesta 我已经更新了答案,并确保您在相同的虚拟环境中运行代码。 - I_Al-thamary
我已经可以使用 python setup.py py2app -A。问题出现在当我移除 -A 尝试构建一个独立应用程序时。 - Serge Ballesta
你使用了相同的环境吗?如果是这样,请尝试使用答案中提到的替代工具,例如 pyInstallercx_Freeze。请参阅 https://docs.python-guide.org/shipping/freezing/。 - I_Al-thamary
1
我想要的是一个包含所有相关版本的工作环境示例,如果可能的话,在macOS Catalina上还需要一个经过测试的示例。 - Serge Ballesta
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接