Не удается получить CFBundleIdentifier из динамически загружаемого NSBundle

Я пытаюсь загрузить пакет динамически, чтобы в некоторых случаях использовать его вместо mainBundle. Мне удалось загрузить пакет с некоторыми ресурсами, такими как Localizable.strings и так далее. И когда я использую localizedStringForKey для этого пакета, загружается правильная локализованная строка. Это означает, что это работает.

Тем не менее, я хотел бы получить даже идентификатор пакета. Таким образом, я добавил в корень папки пакета файл info.plist, содержащий строку CFBundleIdentifier. Это не работает. Когда я пытаюсь получить идентификатор через

[myBundle bundleIdentifier]

Я получаю нулевое значение. Я попытался назвать файл как

Info.plist

и

MyBundle-Info.plist

где MyBundle — имя пакета (содержимое хранится в MyBundle.bundle). Но не повезло.

Я действительно не понимаю, что случилось. Должен ли я устанавливать другие ключи в информационном списке? А может проблема в названии? Любая помощь будет более чем оценена.


person Nicola Miotto    schedule 26.03.2013    source источник


Ответы (1)


В итоге я посмотрел исходный код Core Foundation (в конце концов, NSBundle основан на CFBundle) и понял, в чем проблема. Так..

За сбор содержимого info.plist отвечает функция CFBundleGetInfoDictionary. Это вызывается каждый раз, когда запрашивается информация, теоретически содержащаяся в plist.

Глядя на CFBundle.c, реализация CFBundleGetInfoDictionary проверяет, инициализировано ли поле _infoDict пакета, и, если это не так, инициализирует его:

if (!bundle->_infoDict) bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle), bundle->_url, bundle->_version);

При вызове этой функции в моем CFBundle мне не повезло, поэтому я предположил, что что-то не так должно происходить в _CFBundleCopyInfoDictionaryInDirectoryWithVersion.

Глядя на исходный код, я заметил, что в зависимости от bundle->_version, для поиска в информационном списке используется другой путь. Версия в этом случае зависит от структуры каталога, используемой для установки пакета. Если быть точным, моя версия была 0, потому что, как указано в функции _CFBundleURLLooksLikeBundleVersion (используется во время инициализации пакета), пакет с каталогом Resources:

// check for existence of "Resources" or "Contents" or "Support Files"
    // but check for the most likely one first
    // version 0:  old-style "Resources" bundles
    // version 1:  obsolete "Support Files" bundles
    // version 2:  modern "Contents" bundles
    // version 3:  none of the above (see below)
    // version 4:  not a bundle (for main bundle only)

Итак, чтобы закончить историю, базовый URL-адрес Info.plist инициализируется в _CFBundleCopyInfoDictionaryInDirectoryWithVersion на основе версии 0

    infoURLFromBase = _CFBundleInfoURLFromBase0;

что определяется как:

#define _CFBundleInfoURLFromBase0 CFSTR("Resources/Info.plist")

Тааак... Я поместил свой Info.plist в каталог Resources, а не снаружи, и теперь он работает.

Наверное, я какой-то идиот из-за того, что проделал всю эту поездку, учитывая, что этот материал, вероятно, написан где-то в документе, но я не мог его найти :(

person Nicola Miotto    schedule 26.03.2013