Как отобразить версию версии приложения в наборе параметров приложения?

Я хотел бы включить версию приложения и внутреннюю ревизию, например, 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 во время сборки.

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

Ответ 1

Мне удалось сделать то, что я хотел, используя pListcompiler (http://sourceforge.net/projects/plistcompiler) с открытым исходным кодом.

  • Используя этот компилятор, вы можете записать файл свойств в .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
                    ]
                }
            ]
        }
    }
    
  • У меня была фаза сборки script с пользовательским запуском, которая извлекала мою версию репозитория в файл .h, как описано в brad-larson здесь.

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

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

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

И это все!

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

  • Добавьте в приложение набор настроек. Не переименовывайте его.
  • Откройте файл 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>
  • Создайте фазу запуска Script, перейдите к разделу "Ресурсы копирования Bundle". Добавьте этот код:

    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.

Ответ 5

Использование пластинки Бена Клейтона fooobar.com/questions/28713/...

Добавьте 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. Он выпускает версию следующим образом:

mfZLl.png

Записывая $CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist а не один в $SRCROOT имеют некоторые преимущества.

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

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

Ответ 6

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

#! /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>

Ответ 7

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

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

    versionString = $(/usr/libexec/PlistBuddy -c "Печать CFBundleVersion" "$ {PROJECT_DIR}/${INFOPLIST_FILE}" )

    /usr/libexec/PlistBuddy "$ SRCROOT/Settings.bundle/Root.plist" -c "set PreferenceSpecifiers: 0: DefaultValue $versionString"

Это правильно запустит script ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ, когда пакет настроек упакован во время процесса сборки/архивирования. Если вы откроете набор настроек Root.plist и закроете/заархивируете свой проект, теперь вы увидите, что номер версии обновлен в начале процесса сборки, а ваш комплект настроек отобразит правильную версию.

Ответ 8

Мой рабочий пример на основе ответа @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. Построить и запустить текущую схему

Ответ 9

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

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

Наконец, перейдите к своей цели и создайте фазу запуска Script. Проверьте, что выполните команду "Выполнить" Script и введите Script в текстовое поле 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

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

Ответ 10

Приведенные выше ответы не помогли мне, поэтому я создал свой собственный скрипт.

Это динамически обновляет запись из Root.plist

Используйте скрипт запуска ниже. W плохая работа наверняка проверена в xcode 10.3.

"var buildVersion" - версия, отображаемая в заголовке.

И имя идентификатора "var version" ниже для заголовка в settings.bundle Root.plist

cd "${BUILT_PRODUCTS_DIR}"

#set version name to your title identifier string from settings.bundle
var version = "Version"

#this will be the text displayed in title
longVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_PATH}")
shortVersion=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" ${TARGET_BUILD_DIR}/${INFOPLIST_PATH})
buildVersion="$shortVersion.$longVersion"

path="${WRAPPER_NAME}/Settings.bundle/Root.plist"

settingsCnt='/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:" ${path} | grep "Dict"|wc -l'

for (( idx=0; idx<$settingsCnt; idx++ ))
do
#echo "Welcome $idx times"
val='/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${idx}:Key" ${path}'
#echo $val

#if ( "$val" == "Version" )
if [ $val == "Version" ]
then
#echo "the index of the entry whose 'Key' is 'version' is $idx."

# now set it
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:${idx}:DefaultValue $buildVersion" $path

# just to be sure that it worked
ver='/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${idx}:DefaultValue" $path'
#echo 'PreferenceSpecifiers:$idx:DefaultValue set to: ' $ver

fi

done

Пример записи в Root.plist

    <dict>
        <key>Type</key>
        <string>PSTitleValueSpecifier</string>
        <key>Title</key>
        <string>Version</string>
        <key>DefaultValue</key>
        <string>We Rock</string>
        <key>Key</key>
        <string>Version</string>
    </dict>

Working sample Root.plist entry