Версия против сборки в Xcode


660

У меня есть приложение, которое я разработал с Xcode 3 и недавно начал редактировать с помощью Xcode 4. В сводке целей у меня есть целевая форма приложения iOS с полями: идентификатор, версия, сборка, устройства и цель развертывания. Поле версии является пустым, а поле сборки - 3.4.0 (что соответствует версии приложения с того момента, когда я еще редактировал с помощью Xcode 3).

Мои вопросы:

  1. В чем разница между полями версии и сборки?

  2. Почему поле версии было пустым после обновления до Xcode 4?


Во-первых, я думаю, что это номер сборки, который отображается в списке архивов Xcode Organizer. Кроме этого, я не уверен, для чего это используется.
Даниэль Дикисон

Ответы:


1224

Apple вроде как переставила / переставила поля.

В дальнейшем, если вы посмотрите на вкладку «Информация» для своей цели приложения, вы должны использовать «Строка версий пакета, короткая» в качестве вашей версии (например, 3.4.0) и «Версия пакета» в качестве вашей сборки (например, 500 или 1A500). ). Если вы не видите их обоих, вы можете добавить их. Они будут отображаться в соответствующие текстовые поля Version и Build на вкладке Summary; они одинаковые значения.

При просмотре вкладки «Информация», если щелкнуть правой кнопкой мыши и выбрать « Показать необработанные ключи / значения» , вы увидите, что фактические имена CFBundleShortVersionString(Версия) иCFBundleVersion (Сборка).

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

Существуют всевозможные схемы, но популярной является:

{MajorVersion}. {MinorVersion}. {} Редакция

  • Основная версия - Основные изменения, изменения дизайна и функциональности
  • Незначительная версия - Незначительные улучшения, дополнения к функционалу
  • Revision - номер патча для исправления ошибок

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

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

  • Релиз 1.0.0 может быть сборкой 542. Чтобы получить релиз 1.0.0, потребовалось 542 билда.
  • Выпуск 1.0.1 может быть сборкой 578.
  • Выпуск 1.1.0 может быть сборкой 694.
  • Выпуск 2.0.0 может быть сборкой 949.

Другие разработчики, включая Apple, имеют номер сборки, состоящий из основной версии + вспомогательной версии + количества сборок для выпуска. Это фактические номера версий программного обеспечения, а не значения, используемые для маркетинга.

Если вы идете в меню XCode > О XCode , вы увидите номера версий и сборок. Если вы нажмете кнопку Подробнее ... , вы увидите множество разных версий. Поскольку кнопка « Подробнее» ... была удалена в Xcode 5, эта информация также доступна в разделе « Программное обеспечение»> «Разработчик » приложения « Информация о системе» , которое можно открыть, открыв меню « Apple» > « Об этом Mac» > « Системный отчет ...» .

Например, Xcode 4.2 (4C139). Маркетинговая версия 4.2 - это сборка основной версии 4, сборка вспомогательной версии C и сборка № 139. Следующим выпуском (предположительно 4.3), скорее всего, будет сборка выпуска 4D, и номер сборки начнется с 0 и будет увеличиваться оттуда.

Номера версий и сборок симулятора iPhone такие же, как и iPhone, Mac и т. Д.

  • 3.2: (7W367a)
  • 4.0: (8A400)
  • 4.1: (8B117)
  • 4.2: (8C134)
  • 4.3: (8H7)

Обновление : по запросу, вот шаги для создания сценария, который запускается каждый раз, когда вы строите свое приложение в XCode, чтобы прочитать номер сборки, увеличить его и записать его обратно в {App}-Info.plistфайл приложения . Есть дополнительные, дополнительные шаги, если вы хотите записать свои номера версий / сборок в ваши Settings.bundle/Root*.plistфайлы.

Это расширено из статьи с практическими рекомендациями здесь .

В Xcode 4.2 - 5.0:

  1. Загрузите ваш проект Xcode.
  2. На левой панели щелкните ваш проект в самом верху иерархии. Это загрузит редактор настроек проекта.
  3. В левой части центральной панели окна щелкните свое приложение под ЦЕЛЯМИ. заголовком . Вам нужно будет настроить эту настройку для каждой цели проекта.
  4. Выберите вкладку Build Phases .
    • В Xcode 4 в правом нижнем углу нажмите кнопку Add Build Phase и выберите Add Run Script .
    • В Xcode 5 выберите меню « Редактор» > « Добавить этап сборки» > « Добавить этап построения сценария запуска» .
  5. Перетащите новую фазу « Выполнить сценарий», чтобы переместить ее непосредственно перед копированием ресурсов комплекта. фазой (когда файл app-info.plist будет связан с вашим приложением).
  6. В новом Run Script фазы, набор Shell : /bin/bash.
  7. Скопируйте и вставьте следующее в область скрипта для целых чисел сборки:

    buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
    buildNumber=$(($buildNumber + 1))
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

    Как отметил @Bdebeez, также доступен инструмент Apple Generic Versioning Tool ( agvtool). Если вы предпочитаете использовать его вместо этого, то сначала нужно изменить пару вещей:

    • Выберите настройки сборки вкладку « ».
    • В разделе «Управление версиями » установите для текущей версии проекта начальный номер сборки, который вы хотите использовать, например 1 .
    • Вернувшись на вкладку « Фазы сборки », перетащите фазу « Выполнить сценарий» после фазы « Копировать ресурсы комплекта», чтобы избежать условия гонки при попытке создать и обновить исходный файл, содержащий ваш номер сборки.

    Обратите внимание, что с помощью этого agvtoolметода вы все равно можете периодически получать неудачные / отмененные сборки без ошибок. По этой причине я не рекомендую использовать agvtoolэтот скрипт.

    Тем не менее, на этапе Run Script вы можете использовать следующий скрипт:

    "${DEVELOPER_BIN_DIR}/agvtool" next-version -all

    next-versionПриращения аргумента номер сборки ( bumpтакже псевдоним для одного и того же), и -allобновления Info.plistс новым номером сборки.

  8. И если у вас есть пакет настроек, в котором вы показываете версию и сборку, вы можете добавить следующее в конец скрипта, чтобы обновить версию и сборку. Примечание. Измените PreferenceSpecifiersзначения в соответствии с вашими настройками. PreferenceSpecifiers:2означает посмотреть на элемент в индексе 2 под PreferenceSpecifiersмассивом в вашем файле plist, так что для индекса на основе 0 это 3-я настройка предпочтений в массиве.

    productVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$INFOPLIST_FILE")
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:2:DefaultValue $buildNumber" Settings.bundle/Root.plist
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $productVersion" Settings.bundle/Root.plist

    Если вы используете agvtoolвместо чтения Info.plistнепосредственно, вместо этого вы можете добавить следующее в ваш скрипт:

    buildNumber=$("${DEVELOPER_BIN_DIR}/agvtool" what-version -terse)
    productVersion=$("${DEVELOPER_BIN_DIR}/agvtool" what-marketing-version -terse1)
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:2:DefaultValue $buildNumber" Settings.bundle/Root.plist
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $productVersion" Settings.bundle/Root.plist
  9. А если у вас есть универсальное приложение для iPad и iPhone, вы также можете установить настройки для файла iPhone:

    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:2:DefaultValue $buildNumber" Settings.bundle/Root~iphone.plist    
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $productVersion" Settings.bundle/Root~iphone.plist

17
«В моих проектах у меня есть скрипт, который автоматически увеличивает номер сборки при каждой сборке» - можете ли вы поделиться, как вы это делаете? спасибо за детали ответы и за оригинальный вопрос.
Жолт

2
@Andrews - я обновил свой ответ подробностями сценария сборки.
Некно

9
Для увеличения в шестнадцатеричных числах вы можете использоватьbuildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE") dec=$((0x$buildNumber)) buildNumber=$(($dec + 1)) hex=$(printf "%X" $buildNumber) /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $hex" "$INFOPLIST_FILE"
Алон Амир

8
Вкратце: HEX не допускается в AppStore.
Николас Миари

3
(Пользователи Xcode 5) Вам может потребоваться изменить шаг 5 следующим образом: «В
строке

72

(Просто оставьте это здесь для моей собственной справки.) Это покажет версию и сборку для полей «версия» и «сборка», которые вы видите в цели XCode:

- (NSString*) version {
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    return [NSString stringWithFormat:@"%@ build %@", version, build];
}

В Свифте

func version() -> String {
    let dictionary = NSBundle.mainBundle().infoDictionary!
    let version = dictionary["CFBundleShortVersionString"] as? String
    let build = dictionary["CFBundleVersion"] as? String
    return "\(version) build \(build)"
}

2
ОТ: У вас есть утечка в вашем методе - вы alloc/ initстрока, которая сохраняет строку, но вы не освобождаете ее. Для объекта, который вы возвращаете из метода, вы обычно должны использовать вспомогательный метод, чтобы строка автоматически выдавалась, или вызывать autorelease. Либо: return [NSString stringWithFormat:@"%@ build %@", version, build]; ИЛИ return [[[NSString alloc] initWithFormat:@"%@ build %@", version, build] autorelease];
nekno

1
Спасибо @nekno, изменил ответ, чтобы он был ARC или дружественным к ARC.
Дэн Розенстарк

2
Вероятно, лучше использовать константы, если они доступны (например, kCFBundleVersionKey), чтобы избежать опечаток. Хотя я не смог найти один для "CFBundleShortVersionString" :)
DannyA

У вас есть ошибка в быстром коде - вы дважды вызываете CFBundleShortVersionString
Ярив Ниссим

Спасибо @ yar1vn, я исправил это и НЕТ, это не назад.
Дэн Розенстарк

53

Номер сборки - это внутренний номер, который указывает текущее состояние приложения. Он отличается от номера версии тем, что, как правило, он не предназначен для пользователя и не обозначает никаких различий / функций / обновлений, как это обычно бывает с номером версии.

Думайте об этом так:

  • Построить (CFBundleVersion ): номер сборки. Обычно вы начинаете с 1 и увеличиваете на 1 с каждой сборкой приложения. Он быстро позволяет сравнивать, какая сборка более поздняя, ​​и обозначает смысл прогресса кодовой базы. Они могут быть чрезвычайно полезны при работе с QA, и необходимо убедиться, что ошибки регистрируются в правильных сборках.
  • Маркетинговая версия ( CFBundleShortVersionString): номер пользователя, который вы используете для обозначения этой версии вашего приложения. Обычно это происходит по схеме версий Major.minor (например, MyAwesomeApp 1.2), чтобы пользователи знали, какие выпуски являются небольшими обновлениями обслуживания, а какие - новыми важными функциями.

Чтобы эффективно использовать это в своих проектах, Apple предоставляет отличный инструмент под названием agvtool. Я настоятельно рекомендую использовать это, поскольку это НАМНОГО проще, чем написание сценариев изменений. Это позволяет легко установить как номер сборки, так и маркетинговую версию. Это особенно полезно при создании сценариев (например, простое обновление номера сборки для каждой сборки или даже запрос текущего номера сборки). Он может даже делать более экзотические вещи, такие как пометка вашего SVN, когда вы обновляете номер сборки.

Чтобы использовать это:

  • Установите свой проект в XCode, под управлением версий, чтобы использовать «Apple Generic».
  • В терминале
    • agvtool new-version 1 (установите номер сборки на 1)
    • agvtool new-marketing-version 1.0 (установите маркетинговую версию на 1.0)

Смотрите man-страницу agvtoolдля тонны полезной информации


еще одна статья про agvtool Easy iPhone Application Versioning с помощью agvtool
Gon

25

Скрипт для автоинкрементации номера сборки в ответе выше не работал для меня, если номер сборки является значением с плавающей запятой, поэтому я немного его изменил:

#!/bin/bash    
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=`echo $buildNumber +1|bc`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

21

Номер маркетинговой версии для клиентов называется номером версии . Он начинается с 1.0 и подходит для основных обновлений до 2.0 , 3.0 , для небольших обновлений до 1.1 , 1.2 и для исправлений ошибок до 1.0.1 , 1.0.2 . Этот номер ориентирован на релизы и новые функции.

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

Как видите, номер сборки не нужен, и вам решать, какой номер сборки вы хотите использовать. Так что, если вы обновите свою Xcodeверсию до основной, поле сборки будет пустым. Поле версии не может быть пустым!


Чтобы получить номер сборки в виде NSStringпеременной:

NSString * appBuildString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];

Чтобы получить номер версии в качестве NSStringпеременной:

NSString * appVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];

Если вы хотите оба в одном NSString:

NSString * versionBuildString = [NSString stringWithFormat:@"Version: %@ (%@)", appVersionString, appBuildString];

Это проверено с версией Xcode 4.6.3 (4H1503) . Номер сборки часто пишется в скобках / скобках. Номер сборки в шестнадцатеричном или десятичном виде.

buildandversion


В XCode вы можете автоматически увеличивать номер сборки как десятичное число , помещая следующее в Run scriptфазу сборки в настройках проекта

#!/bin/bash    
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

Для шестнадцатеричного номера сборки используйте этот скрипт

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$((0x$buildNumber)) 
buildNumber=$(($buildNumber + 1)) 
buildNumber=$(printf "%X" $buildNumber)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

project_settings


6

Спасибо @nekno и @ ale84 за отличные ответы.

Тем не менее, я немного изменил скрипт @ ale84, чтобы увеличить число сборок для чисел с плавающей запятой.

значение incl может быть изменено в соответствии с вашими требованиями к плавающему формату. Например: если incl = .01, выходной формат будет ... 1.19, 1.20, 1.21 ...

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
incl=.01
buildNumber=`echo $buildNumber + $incl|bc`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

1

Другой способ - установить номер версии в appDelegate didFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     NSString * ver = [self myVersion];
     NSLog(@"version: %@",ver);

     NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
     [userDefaults setObject:ver forKey:@"version"];
     return YES;
}

- (NSString *) myVersion {
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    return [NSString stringWithFormat:@"%@ build %@", version, build];
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.