如何从具有 PySide2 GUI 的 python 脚本构建 mac os 应用程序?

How to build an mac os app from a python script having a PySide2 GUI?

上下文:

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

经过一些研究,我尝试了py2app。我可以在这里更进一步。有

python setup.py py2app -A

我可以创建一个可运行的应用程序。这显然不能移植到不同的系统,因为它使用我的开发文件夹。如果我使用 python setup.py py2app 生成的程序无法启动,因为 py2app 没有复制所有必需的 Qt 内容。我试着把缺失的库一个一个补上,结果系统找不到插件我放弃了...

问题:

有人可以帮助我将 python 脚本或使用 Qt GUI 的程序包转换为 Mac 上的便携式应用程序吗?理想情况下,配方应该说明如何使用自定义应用程序图标,但这不是必需的。

参考文献:

由于我的真实包对于一个 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'],
)

我认为您缺少的是在您的应用程序包中包含 Python3 框架。我最近自己开发了一个简单的 macOS 应用程序,但是我想更深入地了解如何这样做,所以我深入研究了应用程序的实际结构。基本上,您要将所有内容放入一个带有应用程序名称的普通文件夹中。将此文件夹命名为 MyApp。在这个文件夹中,我们将有另一个名为 Contents 的文件夹。根据我的理解,py2app 只是获取构成您的应用程序的所有内容,并将它们构建在此文件夹中,并创建一个 Info.plist 文件,该文件也位于 Contents 中.到目前为止,这是你所拥有的:

MyApp

-> Contents

-> -> Info.plist

除了包含所有必要 propertiesInfo.plist 文件外,在您的 Contents 文件夹中,您将有一个 MacOS 文件夹和一个 Resources 文件夹至少。您的问题是您还需要一个 Frameworks 文件夹,您可以在其中添加所需版本的 Python.

现在,您的应用层次结构应如下所示:

MyApp

-> Contents

-> -> Info.plist

-> -> MacOS

-> -> Resources

-> -> Frameworks

Frameworks 文件夹中,您可以放置​​用于构建应用程序的完整 Python 3 框架,以及您需要的任何 site-packages 运行 应用程序,然后您可以在可执行文件中反映所有这些更改,以便您指向正确的安装。

据我了解,要使应用程序在 MacOS 上正常运行,只需确保您的主要可执行文件位于 MacOS 文件夹中,并指向 Python 中的 Frameworks文件夹,你的图标.icns文件放在Resources文件夹里,你的Info.plist文件就建好了

为了让 MacOS 将其识别为完整的应用程序,我相信您可能需要使用 productbuild 并包含开发人员许可证书,但只有在您希望分发应用程序时才需要这样做。否则,我只是将扩展名 .app 添加到 MyApp,这会将其转换为应用程序。

如果没有 above-mentioned license/certificate 无论如何,它可能不会识别它应该找到您的图标文件并添加它,所以如果您在预览中打开它,select-all,并复制它,你应该可以在应用程序上right-click,按'Get Info',然后将图标粘贴到window中当前图标的顶部,使其正确显示。

编辑:我学习制作 macOS 应用程序的资源:

Bundle structure

Including frameworks

Signing your application

productbuild manpage

我认为可以找到您问题的解决方案here. First, create a virtual environment并将所有模块安装到同一个虚拟环境。

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

更新

首先,确保您 运行 您的代码在同一个虚拟环境中,并将其转换为标准 mac OS 应用程序,您可以使用 py2app or pyinstaller .另外,如果在执行相同的过程后它不能与您当前的版本一起使用,请尝试降级您的 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

并且您必须创建 a config file or see this example 并包含您拥有的任何文件

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

如果出现任何问题,请参考这些参考资料1, 2, and 3. Also, there are alternatives ways 将您的应用程序转换为 os。

阅读您的评论后,我试图查看问题所在,我发现 this 它可能会解决问题,或者您可以使用替代工具,例如 bbFreezepyInstallercx_Freeze

我已经使用 fbs 成功构建了应用程序。 它旨在构建 Python+PyQt5 应用程序(您也可以使用 PySide2)并且它应该也适用于 Mac OS(根据 documentation/tutorial)。

使用 PyInstaller 时,它常常因包含 PyQt5 依赖项而失败(尤其是当我使用 pyqtgraph 时),但使用 fbs 时效果很好。

如果要为 OSX 打包,您应该

创建 Brew Tap

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

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

  • 在 git 中托管您的代码(不需要 GitHub)
  • 创建一个公式(Formula Cookbook
  • 在 GitHub
  • 上分叉 homebrew-core
  • 添加您的公式并创建拉取请求以将其放入主仓库
  • 支持您的拉取请求,使其完成

加入 Apple 开发者计划

这对于闭源开发人员来说可能最有意义

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

该程序每年花费 99 美元,但允许您签署 package/final 二进制文件并自行分发或在他们的 App Store 上分发

创建帐户后,这里是 OSX https://developer.apple.com/forums/thread/128166

的打包和签名指南
  • 构造您的代码以支持签名(添加构建步骤以将您的工作复制到干净的路径中以避免令人沮丧的返工)
  • % codesign -s <Developer ID Application signing identity> /path/to/code
  • 选择存储格式(.zip.dmg.pkg)并捆绑您的应用程序

要求

  • 适用于 Python 3.8.5
  • macOS 10.15.7 卡特琳娜
  • 使用 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

测试

这里是测试截图运行:

build a macOS bundle for a PySide2 application 的不同选项中摆弄了很多之后,我发现以下步骤几乎可以开箱即用。

使用 pyinstaller 创建 macOS 应用程序包的此配方已在 macOS Catalina 10.15.7 上使用 Python 3.9.1、PySide2 5.15.2、pyinstaller 4.2 进行了测试。

  • 安装 pyenv 和最新的 Python 框架支持(有关 pyenv 工作原理的一般介绍,请参阅 Pyenv, How to manage multiple Python versions and virtual environments):

    brew install pyenv
    PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.9.1
    
  • 为示例创建一个文件夹,创建一个示例pyside应用程序:

    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_())
    
  • 为项目创建一个venv,安装python个包:

    pyenv local 3.9.1
    python3 -m venv venv
    source venv/bin/activate
    pip install pip pyside2 pyinstaller --upgrade
    
  • 使用 python 解释器尝试 运行 应用程序:

    python3 hello.py
    
  • 创建 macOS 应用程序包:

    pyinstaller --windowed hello.py
    
  • 运行 使用应用程序包的应用程序:

    open dist/hello.app
    
  • 查看生成的 hello.spec 构建配置,使用 pyinstaller hello.spec 重新构建应用程序。