如何在纯Python应用程序中更改OSX菜单栏的应用名称?

4 投票
3 回答
3161 浏览
提问于 2025-04-15 23:18

我正在尝试为一个wxPython应用程序创建一个纯Python的应用包。我按照苹果文档的说明,创建了一个.app目录,里面有Info.plist文件等。这个应用包和“正常”应用的唯一不同之处在于入口点(CFBundleExecutable)是一个脚本,开头有以下这一行:

#!/usr/bin/env python2.5

一切运行得很好,但在OSX的菜单栏中,应用的名称仍然显示为“Python”,尽管我在Info.plist中设置了CFBundleName(实际上我是复制了py2app的结果)。完整的Info.plist可以在这里查看

我该如何更改这个名称呢?我到处都看到说菜单栏的名称只由CFBundleName决定。为什么Python解释器在运行时会改变这个呢?

注意:我之前使用过py2app,但生成的文件太大了(超过50MB,而现在的只有100KB),而且在Leopard和Snow Leopard之间甚至不能移植……所以看起来手动创建一个纯Python的应用包比转换py2app的输出要简单得多。

3 个回答

1

其实,如果你创建一个指向Python可执行文件的软链接,然后在你的MyApp.app/Contents/MacOs/-script-中使用这个软链接,而不是直接使用可执行文件,所有的东西似乎都能正常工作。我个人是用一个“#! /bin/sh”的脚本,然后使用“exec”命令。(你可能还是需要用wx.App.SetAppName(MyAppName)这行代码。)例如:

#! /bin/sh

export PYTHONPATH=/Applications/MyApp.app/Contents/Resources/[myPythonCode]
export DYLD_LIBRARY_PATH=/Library/Frameworks/Python.framework/Versions/2.6/lib
exec "/Applications/MyApp.app/Contents/MacOS/[SoftLinkToPythonExe]" "/Applications/MyApp.app/Contents/Resources/myAppMain.py"
3

把一个叫做 LSHasLocalizedDisplayName 的键值在 Info.plist 文件里改成 true,像这样:

<key>LSHasLocalizedDisplayName</key>
<true/>

然后在可执行文件的包里创建一个文件

foo.app/Contents/Resources/English.lproj/InfoPlist.strings

这个文件里要有以下内容

CFBundleName="name in the menu bar";
CFBundleDisplayName="name in the Finder";
3

随Python开发工具一起提供的“Build Applet.app”其实是一个纯Python的应用包。它的主要功能有:

  • MacOS/目录中放置(或链接)一个Python解释器。
  • 可执行的脚本(Foo.app/Contents/MacOS/Foo)会设置一些环境变量,然后调用os.execve()来启动这个解释器。

这个可执行的脚本大致长这样(假设程序的入口点在Resources/main.py):

#!/System/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python
import sys, os
execdir = os.path.dirname(sys.argv[0])
executable = os.path.join(execdir, "Python")
resdir = os.path.join(os.path.dirname(execdir), "Resources")
libdir = os.path.join(os.path.dirname(execdir), "Frameworks")
mainprogram = os.path.join(resdir, "main.py")

sys.argv.insert(1, mainprogram)
pypath = os.getenv("PYTHONPATH", "")
if pypath:
    pypath = ":" + pypath
os.environ["PYTHONPATH"] = resdir + pypath
os.environ["PYTHONEXECUTABLE"] = executable
os.environ["DYLD_LIBRARY_PATH"] = libdir
os.environ["DYLD_FRAMEWORK_PATH"] = libdir
os.execve(executable, sys.argv, os.environ)

撰写回答