Как я могу отобразить версию приложения в пакете настроек моего приложения? - PullRequest
81 голосов
/ 18 мая 2009

Я бы хотел включить версию приложения и внутреннюю ревизию, например 1.0.1 (r1243), в комплект настроек моего приложения.

Файл Root.plist содержит фрагмент, подобный этому ...

     <dict>
        <key>Type</key>
        <string>PSTitleValueSpecifier</string>
        <key>Title</key>
        <string>Version</string>
        <key>Key</key>
        <string>version_preference</string>
        <key>DefaultValue</key>
        <string>VersionValue</string>
        <key>Values</key>
        <array>
            <string>VersionValue</string>
        </array>
        <key>Titles</key>
        <array>
            <string>VersionValue</string>
        </array>
    </dict>

и я хотел бы заменить строку "VersionValue" во время сборки.

У меня есть скрипт, который может извлечь номер версии из моего репозитория, мне нужен способ обработки (предварительной обработки) файла Root.plist во время сборки и замены номера ревизии, не затрагивая исходный файл .

Ответы [ 9 ]

68 голосов
/ 30 июня 2009

Существует еще одно решение, которое может быть намного проще, чем любой из предыдущих ответов. Apple встраивает инструмент командной строки под названием PlistBuddy в большинство своих инсталляторов и включает его в Leopard на /usr/libexec/PlistBuddy.

Поскольку вы хотите заменить VersionValue, предполагая, что у вас есть значение версии, извлеченное в $newVersion, вы можете использовать эту команду:

/usr/libexec/PlistBuddy -c "Set :VersionValue $newVersion" /path/to/Root.plist

Нет необходимости возиться с sed или регулярными выражениями, этот подход довольно прост. См. справочную страницу для получения подробных инструкций. Вы можете использовать PlistBuddy для добавления, удаления или изменения любой записи в списке свойств. Например, мой друг написал в блоге о увеличении числа сборки в Xcode с использованием PlistBuddy.

Примечание: Если вы указываете только путь к списку, PlistBuddy переходит в интерактивный режим, поэтому вы можете выполнить несколько команд, прежде чем принять решение о сохранении изменений. Я определенно рекомендую сделать это перед тем, как добавить его в ваш скрипт сборки.

64 голосов
/ 17 июля 2009

Моим ленивым решением было обновить номер версии из кода моего приложения. У вас может быть значение по умолчанию (или пустое) в Root.plist, а затем где-нибудь в вашем коде запуска:

NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
[[NSUserDefaults standardUserDefaults] setObject:version forKey:@"version_preference"];

Единственная проблема в том, что ваше приложение должно быть запущено хотя бы один раз, чтобы обновленная версия появилась на панели настроек.

Вы можете пойти дальше и обновить, например, счетчик того, сколько раз было запущено ваше приложение, или другую интересную информацию.

59 голосов
/ 11 октября 2012

Основываясь на ответе @ Куинна, здесь представлен весь процесс и рабочий код, который я использую для этого.

  • Добавьте пакет настроек в ваше приложение. Не переименовывайте его.
  • Откройте Settings.bundle / Root.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>PreferenceSpecifiers</key>
    <array>
        <dict>
            <key>Title</key>
            <string>About</string>
            <key>Type</key>
            <string>PSGroupSpecifier</string>
        </dict>
        <dict>
            <key>DefaultValue</key>
            <string>DummyVersion</string>
            <key>Key</key>
            <string>version_preference</string>
            <key>Title</key>
            <string>Version</string>
            <key>Type</key>
            <string>PSTitleValueSpecifier</string>
        </dict>
    </array>
    <key>StringsTable</key>
    <string>Root</string>
</dict>
</plist>
  • Создайте Run Script этап сборки, перейдите к этапу Copy Bundle Resources . Добавьте этот код:

    cd "${BUILT_PRODUCTS_DIR}"
    buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_PATH}" )
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $buildVersion" "${WRAPPER_NAME}/Settings.bundle/Root.plist"
    
  • Замените MyAppName на фактическое имя вашего приложения, а 1 после PreferenceSpecifiers - на индекс вашей версии в настройках. В приведенном выше примере Root.plist он имеет индекс 1.

17 голосов
/ 19 августа 2016

Использование списка Бена Клейтона https://stackoverflow.com/a/12842530/338986

Добавить Run script со следующим фрагментом после Copy Bundle Resources.

version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
build=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PROJECT_DIR/$INFOPLIST_FILE")
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $version ($build)" "$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist"

Добавление CFBundleVersion в дополнение к CFBundleShortVersionString. Это испускает версию как это:

image

Письмом $CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist вместо того, что в $SRCROOT, есть некоторые преимущества.

  1. Не изменяет файлы в рабочей копии репозитория.
  2. Вам не нужно указывать путь к Settings.bundle в $SRCROOT. Путь может отличаться.

Тестирование на Xcode 7.3.1

12 голосов
/ 05 июля 2010

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

#! /usr/bin/env python
import os
from AppKit import NSMutableDictionary

settings_file_path = 'Settings.bundle/Root.plist' # the relative path from the project folder to your settings bundle
settings_key = 'version_preference' # the key of your settings version

# these are used for testing only
info_path = '/Users/mrwalker/developer/My_App/Info.plist'
settings_path = '/Users/mrwalker/developer/My_App/Settings.bundle/Root.plist'

# these environment variables are set in the XCode build phase
if 'PRODUCT_SETTINGS_PATH' in os.environ.keys():
    info_path = os.environ.get('PRODUCT_SETTINGS_PATH')

if 'PROJECT_DIR' in os.environ.keys():
    settings_path = os.path.join(os.environ.get('PROJECT_DIR'), settings_file_path)

# reading info.plist file
project_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(info_path)
project_bundle_version = project_plist['CFBundleVersion']

# print 'project_bundle_version: '+project_bundle_version

# reading settings plist
settings_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(settings_path)
  for dictionary in settings_plist['PreferenceSpecifiers']:
    if 'Key' in dictionary and dictionary['Key'] == settings_key:
        dictionary['DefaultValue'] = project_bundle_version

# print repr(settings_plist)
settings_plist.writeToFile_atomically_(settings_path, True)

Вот Root.plist, который я получил в Settings.bundle:

<?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>PreferenceSpecifiers</key>
    <array>
        <dict>
            <key>Title</key>
            <string>About</string>
            <key>Type</key>
            <string>PSGroupSpecifier</string>
        </dict>
        <dict>
            <key>DefaultValue</key>
            <string>1.0.0.0</string>
            <key>Key</key>
            <string>version_preference</string>
            <key>Title</key>
            <string>Version</string>
            <key>Type</key>
            <string>PSTitleValueSpecifier</string>
        </dict>
    </array>
    <key>StringsTable</key>
    <string>Root</string>
</dict>
</plist>
8 голосов
/ 09 мая 2016

Другие ответы не работают правильно по одной причине: Фаза сборки сценария запуска не выполняется, пока ПОСЛЕ пакета настроек не было упаковано. Таким образом, если ваш Info.plist версии 2.0.11, и вы обновляете его до 2.0.12, а затем создайте / заархивируйте свой проект, пакет настроек все равно будет 2.0.11. Если вы откроете пакет настроек Root.plist, вы увидите, что номер версии не обновляется до конца процесса сборки. Вы можете построить проект СНОВА, чтобы корректно обновить комплект настроек, или вместо этого добавить сценарий к этапу предварительной сборки ...

  • В XCode отредактируйте схему для цели вашего проекта
  • Нажмите стрелку раскрытия на схеме BUILD
  • Затем нажмите на пункт «Предварительные действия»
  • Щелкните знак «плюс» и выберите «Действие при запуске нового сценария»
  • Установить значение оболочки в / bin / sh
  • Установите "Предоставить параметры сборки из" для цели проекта
  • Добавьте ваш скрипт в текстовую область. Следующий скрипт работал на меня. Возможно, вам придется изменить пути в соответствии с настройками вашего проекта:

    versionString = $ (/ usr / libexec / PlistBuddy -c "Print CFBundleVersion" "$ {PROJECT_DIR} / $ {INFOPLIST_FILE}")

    / usr / libexec / PlistBuddy "$ SRCROOT / Settings.bundle / Root.plist" -c "устанавливает PreferenceSpecifiers: 0: DefaultValue $ versionString"

Это правильно запустит скрипт ДО того, как пакет настроек будет упакован в процессе сборки / архивирования. Если вы откроете пакет настроек Root.plist и соберете / заархивируете свой проект, вы увидите, что номер версии обновляется в начале процесса сборки, и ваш пакет настроек будет отображать правильную версию.

3 голосов
/ 19 мая 2009

Мне удалось сделать то, что я хотел, с помощью pListcompiler (http://sourceforge.net/projects/plistcompiler) open source porject.

  1. Используя этот компилятор, вы можете записать файл свойств в файл .plc, используя следующий формат:

    plist {
        dictionary {
            key "StringsTable" value string "Root"
            key "PreferenceSpecifiers" value array [
                dictionary {
                    key "Type" value string "PSGroupSpecifier"
                    key "Title" value string "AboutSection"
                }
                dictionary {
                    key "Type" value string "PSTitleValueSpecifier"
                    key "Title" value string "Version"
                    key "Key" value string "version"
                    key "DefaultValue" value string "VersionValue"
                    key "Values" value array [
                        string "VersionValue"
                    ]
                    key "Titles" value array [
                        string "r" kRevisionNumber
                    ]
                }
            ]
        }
    }
    
  2. У меня была фаза сборки пользовательского сценария запуска, которая извлекала мою ревизию репозитория в файл .h, как описано Брэдом-Ларсоном здесь .

  3. Файл plc может содержать директивы препроцессора, такие как #define, #message, #if, #elif, #include, #warning, #ifdef, #else, #pragma, #error, #ifndef, #endif Переменные окружения xcode. Так что я смог сослаться на переменную kRevisionNumber, добавив следующую директиву

    #include "Revision.h"
    
  4. Я также добавил фазу сборки собственного скрипта в свою цель xcode, чтобы запускать компилятор каждый раз, когда идет сборка проекта

    /usr/local/plistcompiler0.6/plcompile -dest Settings.bundle -o Root.plist Settings.plc
    

И это было все!

1 голос
/ 23 декабря 2018

Мой рабочий пример на основе ответа @Ben Clayton и комментариев @Luis Ascorbe и @Vahid Amiri:

Примечание: этот подход изменяет файл Settings.bundle / Root.plist в рабочей копии хранилища

  1. Добавьте пакет настроек в корневой каталог вашего проекта. Не переименовывайте его
  2. Откройте Settings.bundle / Root.plist как SourceCode

    Заменить содержимое на:

    <?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>PreferenceSpecifiers</key>
        <array>
            <dict>
                <key>DefaultValue</key>
                <string></string>
                <key>Key</key>
                <string>version_preference</string>
                <key>Title</key>
                <string>Version</string>
                <key>Type</key>
                <string>PSTitleValueSpecifier</string>
            </dict>
        </array>
        <key>StringsTable</key>
        <string>Root</string>
    </dict>
    </plist>
    
  3. Добавьте следующий скрипт в раздел «Построение, предварительные действия» схемы проекта (цели)

    version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
    build=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PROJECT_DIR/$INFOPLIST_FILE")
    
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:DefaultValue $version ($build)" "${SRCROOT}/Settings.bundle/Root.plist"
    
  4. Построить и запустить текущую схему

1 голос
/ 18 мая 2009

Я полагаю, что вы можете сделать это, используя способ, аналогичный тому, что я описал в этом ответе (на основе этого поста )

Во-первых, вы можете сделать VersionValue переменной в Xcode, переименовав ее в $ {VERSIONVALUE}. Создайте файл с именем versionvalue.xcconfig и добавьте его в свой проект. Перейдите к цели вашего приложения и перейдите к настройкам Build для этой цели. Я считаю, что вам нужно добавить VERSIONVALUE в качестве пользовательской настройки сборки. В правом нижнем углу этого окна измените значение «На основе» на «versionvalue».

Наконец, перейдите к своей цели и создайте фазу сборки Run Script. Проверьте этап Run Script и вставьте его в текстовое поле Script. Например, мой скрипт для пометки моего параметра BUILD_NUMBER текущей сборкой Subversion выглядит следующим образом:

REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "BUILD_NUMBER = $REV" > ${PROJECT_DIR}/buildnumber.xcconfig

Это должно помочь заменить переменную, когда эти значения изменятся в вашем проекте.

...