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

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

Ответ 1

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

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

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 чтобы убедиться, что сценарий предварительного действия был запущен, и проверьте, правильно ли вы ~/debug.txt путь.

Ответ 2

Я тоже автоматизировал установку своих номеров версий. Я создал Запуск Script Фаза сборки. Ключ должен обновить копию каталога целевой сборки каталога Info.plist not build один. Вам также нужно выполнить свой запуск script после фазы пакета. Хорошо отредактировать связать файл напрямую, потому что перед подписыванием кода. Вы не хотите генерировать файл, который изобретает колесо.

Здесь мой script:

# ---------------------------- 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];                           

Ответ 3

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

$ touch Info.plist

Ответ 4

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

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

Ответ 5

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

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

  • Перейдите в раздел "Редактировать схему" > "Сборка" > "Предварительные действия"
  • Нажмите кнопку "+" и выберите "Новый запуск script Действие"
  • Выберите свою цель в раскрывающемся меню "Предоставить параметры сборки из"
  • Добавить touch "${SRCROOT}/${INFOPLIST_FILE}" в поле script

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

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

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

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 с наложенным значением, затем сохранит конфигурационный файл с новым номером сборки; остальные строки должны сохранить маркетинговую версию и номер сборки в plist:

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.

Ответ 10

Работа с Xcode 8.3.2

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

Решение 1: самое простое и элегантное

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

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

touch $INFOPLIST_FILE

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

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

Решение 2: более сложный и хакерский

Другим решением является удаление кэшированного Info.plist в Info.plist сборки.

Я написал этот супер простой маленький скрипт 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... Возможно, нет? Любой вклад кого-нибудь?