Mac OS X如何运行应用程序包?

时间:2013-06-16 19:30:09

标签: macos bundle nsbundle

我正在使用py2app捆绑Mac应用程序,并试图弄清楚它是如何工作的。基于阅读Bundle Programming Guide,似乎CFBundleExecutable是必需的密钥,这是OSX用来确定要运行的MacOS子文件夹中的哪个文件的关键。但是,我将Info.plist文件剥离到以下内容,应用程序加载正常:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>PyMainFileNames</key>
        <array>
                <string>__boot__</string>
        </array>
        <key>PyRuntimeLocations</key>
        <array>
                <string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
        </array>
</dict>
</plist>

怎么会这样?鉴于确切的plist文件,OSX如何加载我的应用程序?

1 个答案:

答案 0 :(得分:3)

CFBundleExecutable键是你真正需要的,但是CoreFoundation会尽力处理它的缺席。通过looking at the source of CFBundle,我们可以了解它如何处理此密钥:

static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
    CFStringRef executableName = NULL;

    // …

    if (infoDict) {
        // Figure out the name of the executable.
        // First try for the new key in the plist.
        executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
        // Second try for the old key in the plist.
        if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
        if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
            CFRetain(executableName);
        } else {
            executableName = NULL;
        }
    }
    if (!executableName && url) {
        // Third, take the name of the bundle itself (with path extension stripped)

所以你可以看到他们按顺序寻找以下内容:

  1. CFBundleExecutable键。
  2. NSExecutable密钥,一个早于OS X公测版的遗留名称。
  3. 如果两者都不存在,则回退到使用已移除路径扩展名的捆绑包的名称。
  4. 确定了可执行文件名后,找到它所在目录的方式同样充满了怪癖。我会把这些发现作为有兴趣的各方的练习。