Как заставить Xcode перестраивать файл Info.plist в моем проекте каждый раз, когда я строю проект? - PullRequest
25 голосов
/ 16 сентября 2010

Очевидно, что файл кэшируется, поэтому он создается только при изменении.У меня есть переменные окружения, чтобы увеличить мой номер версии, и тому подобное, и обновлять их независимо от plist (на самом деле в настройках сборки проекта).Есть ли скрипт, который я могу использовать в качестве фазы сборки скрипта, который заставит Info.plist обновиться?Какой-то другой удобный способ?

Ответы [ 10 ]

17 голосов
/ 05 сентября 2013

Выберите «Редактировать схему», затем выберите «Построить» в элементе управления слева.

Затем добавьте шаг «Предварительные действия», убедитесь, что рассматриваемая схема выбрана в раскрывающемся меню «Обеспечить параметры сборки из», а затем добавьте это в окно редактирования ниже:

rm "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"

Это удалит кэшированную версию Info.plist, в результате чего XCode будет перестраивать ее каждый раз, когда вы нажимаете build.

В качестве альтернативы, если вы разрешите Xcode предварительно обработать файл шаблона Info.plist, просто коснитесь шаблона с помощью

touch ${PROJECT_DIR}/${INFOPLIST_FILE}

тоже работает.

Отладка сценариев перед действием

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

echo "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" > ~/debug.txt

Затем проверьте содержимое ~/debug.txt, чтобы убедиться, что сценарий предварительного действия был запущен, и посмотреть, правильно ли вы указали путь.

15 голосов
/ 02 мая 2013

У меня тоже есть автоматическая установка номеров версий. Я создал Run Script Фаза сборки. Ключ заключается в том, чтобы обновить целевую копию каталога сборки каталога Info.plist, а не сборки один. Вы также должны иметь свой скрипт запуска после фазы пакета копирования. Это нормально, чтобы редактировать связать файл напрямую, потому что это до подписания кода. Вы не хотите создавать файл, который заново изобретает колесо.

Вот мой сценарий:

# ---------------------------- IMPORTANT ----------------------------
# You must set GITHash to something like 'Set by build script' in the file
# file '<Project Name>-Info.plist' in the 'Supporting Files' group
# -------------------------------------------------------------------
#
# Get the version number from the tag in git and the number of commits as the build number
#
appVersion=$(git describe --long | cut -f 1 -d "-") 
appBuild=$(git describe --long | cut -f 2 -d "-") 
gitHash=$(git describe --long | cut -f 3 -d "-")
echo "From GIT Version = $appVersion Build = $appBuild"

#
# Set the version info in plist file
#
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $appVersion" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Set :GITHash $gitHash" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
echo "Updated ${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"

FYI Я также автоматически устанавливаю версию и строю на вкладке About следующий код

NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appDisplayName = infoDictionary[@"CFBundleDisplayName"];
NSString *majorVersion = infoDictionary[@"CFBundleShortVersionString"];
NSString *minorVersion = infoDictionary[@"CFBundleVersion"];

self.appDescription.text = [NSString stringWithFormat:@"Dirty Dog Software\n%@\nVersion: %@(%@)",
                       appDisplayName, majorVersion, minorVersion];                           
11 голосов
/ 16 сентября 2010

Вы можете попробовать использовать команду touch для обновления отметки времени, которая, как я полагаю, и есть то, что Xcode использует для определения необходимости ее восстановления, например,

$ touch Info.plist
9 голосов
/ 01 марта 2011

Один из способов сделать это состоит в том, чтобы иметь фазу сборки Run Script для генерации Info.plist из файла Info.plist.template, а затем rm Info.plist после создания пакета. Идея из комментария Dave DeLong , размещенного в его блоге здесь .

Если он довольно сильно кэшируется (т.е. кэшируется, даже если у вас нет Info.plist, открытого в истории файлов), вы можете rm также кэшировать версию в этом сценарии.

5 голосов
/ 18 июля 2012

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

Примечание. Это не то же самое, что фаза сборки сценария запуска. Действие перед сборкой происходит до того, как Xcode проверит информационный список, этап сборки сценария запуска, по-видимому, наступает после того, как Xcode уже проверил информационный список (поэтому он работает только каждый раз).

  1. Перейдите в «Редактировать схему»> «Построить»> «Предварительные действия»
  2. Нажмите кнопку «+» и выберите «Действие запуска нового сценария»
  3. Выберите цель в раскрывающемся списке «Предоставить параметры сборки из»
  4. Добавить touch "${SRCROOT}/${INFOPLIST_FILE}" в поле скрипта
1 голос
/ 17 сентября 2010

На вкладке «Сборка» окна «Информация о цели» внизу в «Упаковке» с пометкой «Файл предварительной обработки Info.plist» есть опция, которую вы можете проверить. Я верю, что обновлю файл при каждой сборке.

0 голосов
/ 24 августа 2017

Работа с Xcode 8.3.2

Вдохновленный ответом @LeeH от 2013 года, я предложил два решения для перестройки Info.plist.

Решение 1: Большинствопростой и элегантный

Самое простое решение - заставить XCode читать ваши пользовательские переменные путем касания ваших целей Info.plist.

Добавление фазы сборки, см. скриншот ниже(изначально снимок экрана для Solution 2 ), и просто добавьте эту строку:

touch $INFOPLIST_FILE

Вот и все!Теперь XCode должен принудительно перезагрузить ваши пользовательские переменные в файл Info.plist.

Это решение аналогично предложенному @lukelutman, но с использованием фазы сборки.Сценарий предварительного действия у меня не работал.

Решение 2. Более сложное и хакерское

Другое решение заключается в удалении кэшированного Info.plist вbuild dir .

Я написал этот супер простой маленький bash-скрипт

#!/bin/bash
info_plist="$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME.app/Info.plist"
echo "Removing Info.plist from build dir in order to force rebuild of it and reading of correct xcconfig variables, plist path $info_plist"
rm "$info_plist"

Затем я сохранил его и вызвал его из фаз сборки для цели.Я поставил его как первый этап сборки.

enter image description here

Справочная информация:

У меня есть три различные конфигурации: Config, Alpha, AppStore и я использую Universal Links, Push-уведомления и другие материалы, которые требуют использования файла Entitlements.Но я не хотел иметь три файла прав, по одному на каждую конфигурацию.

Мой проект уже сильно зависит от файлов конфигурации (.xcconfig).Я на самом деле настроил файл Entitlement (MyAppsProductName.entitlements) с помощью пользовательских переменных конфигурации.

Но я хотел прочитать те же переменные времени выполнения переменных конфигурации, я решил, что смогу это сделать, если они будут добавлены в мои целевые объекты Info.plist.Это сработало!

Но я заметил, что когда я изменил значения в моем файле .xcconfig, то файл Info.plist не изменил значения.Я заметил, что если я выполнил чистую сборку, то значения в Info.plist получили обновления в соответствии со значениями в файле .xcconfig.Xcode действительно кэширует файл Info.plist.

Так что эти решения выше решают эту проблему.Надеюсь, поможет!:)

Обсуждение

Понятия не имею, если Решение 2 имеет какое-либо преимущество перед Решение 1 ... Возможно, нет?Любой вход кто-нибудь?

0 голосов
/ 07 января 2017

Для тех, кто изо всех сил пытался заставить проект выполнить автоматическое управление версиями, я создал проект macOS GitHub , который демонстрирует, как реализовать его очень простым и понятным способом, благодаря идеям @GayleDDS.и Дэниел Фаррелли и его блог о версионировании и моей собственной реализации.Я думаю, что вы можете перевести его в свои проекты на других платформах без каких-либо хлопот.

Вот небольшое руководство о том, как вы можете воспроизвести его в своих проектах (Xcode 8).

  1. Чтобы уменьшить вероятность того, что вы поймете это неправильно, убедитесь, что вы уже добавили все свои цели в свой проект заранее.
  2. Перейдите в меню Файл> Новый файл ... и затем выполните прокрутку.вниз и выберите Файл настроек конфигурации
  3. Назовите его BuildNumber и не забудьте добавить этот файл конфигурации ко всем целям , которые вы хотите синхронизировать;сделайте это, установив соответствующие флажки перед сохранением этого файла
  4. В вашем проекте должен появиться файл с именем BuildNumber.xcconfig
  5. Добавьте к этому файлу следующий текст: CURRENT_PROJECT_VERSION = 1.Если вы хотите, вы можете начать с другого номера.Это будет ваш номер сборки, который будет увеличиваться при каждом построении. Пожалуйста, не меняйте имя переменной, хотя .
  6. Если у вас более одной цели, добавьте следующий скрипт к первой построенной цели, перейдя к Проект> Цель> Фазы сборки
  7. Перейдите в меню Редактор> Добавить фазу сборки> Добавить фазу сценария выполнения
  8. A Выполнить сценарий фаза должна была быть добавлена ​​к вашей цели;поэтому перетаскивайте его, пока не достигнете Целевые зависимости (эта деталь важна!).
  9. Теперь перейдем к интересной части, и я объясню сценарий почти построчно:

Начните с создания пути к PlistBuddy в первой строке скрипта:

plistbuddy="/usr/libexec/PlistBuddy"

Добавьте строку 2, чтобы прочитать файл конфигурации, а затем прочитайте переменную CURRENT_PROJECT_VERSION, которую вы установили в шаге 5.

OLD_VERSION=`cat "$SRCROOT/BuildNumber.xcconfig" | awk '/CURRENT_PROJECT_VERSION/ { print $3 }'`

В строке 3-11 установите NEW_VERSION с увеличенным значением, затем сохраните файл конфигурации с новым номером сборки;остальные строки предназначены для сохранения маркетинговой версии и номера сборки в списке:

NEW_VERSION=`cat "$SRCROOT/BuildNumber.xcconfig" | awk '/CURRENT_PROJECT_VERSION/ { print $3 + 1 }'`
sed -i '' "s/CURRENT_PROJECT_VERSION = .*/CURRENT_PROJECT_VERSION = $NEW_VERSION/" "$SRCROOT/BuildNumber.xcconfig"
CURRENT_PROJECT_VERSION=$NEW_VERSION
BUILD_STR="Build $NEW_VERSION"
COPYRIGHT_STR="© 2017 MyCompany.net"
APP_VERSION_STR="1.3.5"
$plistbuddy -c "Set :CFBundleShortVersionString $APP_VERSION_STR" "${SRCROOT}/$TARGETNAME/Info.plist"
$plistbuddy -c "Set :CFBundleVersion $BUILD_STR" "${SRCROOT}/$EXECUTABLE_NAME/Info.plist"
$plistbuddy -c "Set :NSHumanReadableCopyright $COPYRIGHT_STR" "$INFOPLIST_FILE"

В строках 8-11 я также показываю, как использовать различные переменные среды, которые Xcode устанавливает для своих сценариев.Вы можете добавить дополнительные строки, чтобы редактировать список info.plist для других целей, а затем синхронизировать версию вашего основного приложения и его помощников.Перейдите на GitHub , загрузите проект и поиграйте с ним, а затем адаптируйте его под свои нужды.Счастливое автоматическое управление версиями с Xcode.

0 голосов
/ 29 апреля 2013

Другой подход заключается в создании «совокупной» цели, которая имеет только фазу сборки. Используйте это, чтобы коснуться файла Info.plist. Сделайте эту цель зависимой от цели, которая создает ваше приложение.

Поскольку это отдельная цель и зависимость от цели вашего приложения, она будет создана до того, как файлы Info.plist цели вашего приложения будут даже проверены. (Как уже было отмечено, этапы сборки самой цели приложения происходят слишком поздно, после того как время модификации файлов Info.plist уже было проверено.)

0 голосов
/ 17 июля 2011

Убедитесь, что вы также обновили свой вид списка.
При просмотре списка в XCode просто нажмите треугольник раскрытия рядом с корневым элементом в списке (Information Property List). А затем щелкните по нему еще раз, чтобы развернуть.
Вы увидите, что значения были обновлены. Я запускал похожий сценарий и думал, что он работает только с перерывами, пока не понял, что представление plist просто не обновляет.

...