Как получить версию приложения и номер сборки с помощью Swift?
389
У меня есть приложение IOS с серверной частью Azure, и я хотел бы регистрировать определенные события, например, имена входа и какие версии пользователей приложения работают.
Как я могу вернуть версию и номер сборки, используя Swift?
Обязательно не путайте CFBundleVersion& CFBundleShortVersionString`. Первая - это ваша версия сборки . Другой номер версии . Смотрите здесь для получения дополнительной информации
Мед
1
@ ØyvindVik Большинство людей предполагают, что вы можете перевести решение Objective-C на Swift, не взявшись за руки.
gnasher729
Ответы:
425
РЕДАКТИРОВАТЬ
Обновлено для Swift 4.2
let appVersion =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String
РЕДАКТИРОВАТЬ
Как указал @azdev в новой версии Xcode, вы получите ошибку компиляции при попытке использовать мое предыдущее решение, чтобы решить эту проблему, просто отредактируйте его, как предложено, чтобы развернуть словарь пакета, используя!
let nsObject:AnyObject?=Bundle.main.infoDictionary!["CFBundleShortVersionString"]
Конец Править
Просто используйте ту же логику, что и в Objective-C, но с небольшими изменениями
//First get the nsObject by defining as an optional anyObjectlet nsObject:AnyObject?=NSBundle.mainBundle().infoDictionary["CFBundleShortVersionString"]//Then just cast the object as a String, but be careful, you may want to double check for nillet version = nsObject as!String
Когда я использую это, я получаю ошибку компилятора «[NSObject: AnyObject]? Не имеет члена с именем« subscript »»
andreas
Вы можете попробовать заменить AnyObject? AnyObject! не зная точно, какой код вы используете, очень трудно угадать, что не так, также имейте в виду, что Swift может переходить с одного релиза Xcode на другой, поэтому также важно знать вашу версию Xcode.
Дэвид
18
@andreas infoDictionaryдолжен быть развернут с помощью !. Это то, что я использую, помещено в файл Globals.swift:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
azdev
1
Я должен был добавить еще один "!" после "как". let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Йосей
3
Вы должны избегать использования принудительной развертки "!" так как они приведут к сбою вашего приложения всякий раз, когда одно из этих значений будет равно нулю
Julius
279
Я знаю, что на это уже ответили, но лично я думаю, что это немного чище:
Swift 3.0:
iflet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String{self.labelVersion.text = version}
Свифт <2.3
iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]as?String{self.labelVersion.text = version}
Таким образом, версия if let заботится об условной обработке (в моем случае задает текст метки), и если infoDictionary или CFBundleShortVersionString равны нулю, необязательное развертывание приведет к пропуску кода.
self.labelVersion.textявляется необязательным типом, так что вы можете напрямую назначитьNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
Jonauz
8
Есть ли причина, по которой значение не будет установлено? Согласитесь, с ним определенно более осторожно let, просто интересно, зачем это нужно. Спасибо!
Crashalot
@Crashalot несмотря на ваше имя;) вы не хотите, чтобы ваше приложение зависало, если, скажем, вы сделали опечатку, а номер версии должен быть «что-то пошло не так».
Даниэль Спрингер
ОП: вы можете заменить? с ! и удалите "как строку". Если это ноль, это в любом случае не будет терпеть крах
Даниэль Спрингер
245
Обновлено для Swift 3.0
В NS-prefixes теперь ушли в Swift 3.0 и некоторые свойства / методы изменились имена более Swifty. Вот как это выглядит сейчас:
Со времени моего первоначального ответа я много работал с Frameworks, поэтому я хотел обновить свое решение до чего-то более простого и гораздо более полезного в среде с несколькими пакетами:
Теперь это расширение будет полезно в приложениях для идентификации как основного пакета, так и любых других включенных пакетов (таких как общая платформа для программирования расширений или третьи платформы, такие как AFNetworking), например, так:
Я хотел бы улучшить некоторые из ответов, уже опубликованных. Я написал расширение класса, которое может быть добавлено в вашу цепочку инструментов для более логичной обработки.
extensionNSBundle{classvar applicationVersionNumber:String{iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]
в виде? String {return version} return "Номер версии недоступен"}
classvar applicationBuildNumber:String{iflet build =NSBundle.mainBundle().infoDictionary?["CFBundleVersion"]as?String{return build
}return"Build Number Not Available"}}
Так что теперь вы можете легко получить к нему доступ:
let versionNumber =NSBundle.applicationVersionNumber
classfunc getVersion()->String{guardlet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?Stringelse{return"no version info"}return version
}
Для более старых версий :
classfunc getVersion()->String{iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]as?String{return version
}return"no version info"}
Так что если вы хотите установить текст метки или хотите использовать где-то еще;
или: класс func getVersion () -> String {return NSBundle.mainBundle (). infoDictionary? ["CFBundleShortVersionString"] как? Строка ?? "нет информации о версии"}
tapmonkey
Я думаю, копирование других ответов не имеет смысла. Если ваш ответ больше не действителен, тогда у вас всегда есть возможность удалить его и освободить место для других ответов :)
carmen_munich
1
@carmen_munich Так как ты клевещешь здесь, я должен ответить тебе. Прежде всего, этот ответ опубликован в марте 2015 года, а ваш ответ опубликован в феврале 2017 года. Поэтому ваше вдохновение должно исходить из предыдущих ответов. Во-вторых, я не видел ваш ответ вообще, я обновил свой ответ, потому что я использую его таким образом в настоящее время. Полагаю, использование расширения не является уникальным для кого-то из сообщества iOS. На самом деле, пожалуйста, постарайтесь быть зрелыми и уважать других разработчиков. Я ничего не пишу здесь. Я хотел бы помочь людям, вот и все. Пожалуйста, постарайтесь не отговаривать людей, пытающихся помочь на SO.
Ганхан
Я слышал множество отзывов от новичков о том, что они публикуют ответ и хотят видеть, что кто-то нажимает «вверх», что действительно приятно видеть и мотивирует людей. Но если кто-то скопирует ответы в своем устаревшем ответе, тот, кто попытался опубликовать его, не получит мотивацию, что кто-то проголосовал за него. Таким образом, новички действительно испытывают разочарование и чувствуют, что не приносят пользы сообществу и не прекращают публикацию. И не поймите неправильно, я имею в виду это в целом. Надеюсь, вы не обижаетесь и теперь не понимаете, почему я сделал это предложение.
carmen_munich
@carmen_munich Если вы упорядочите ответы на этот вопрос в хронологическом порядке, вы заметите, что кто-то уже дал тот же ответ, что и вы раньше! Так ты обвиняешь меня в том, что сделал сам. Поскольку у меня есть история для этого вопроса, я поделился своими новыми предпочтениями использования в обновлении. Это все.
Ганхан,
33
Для Swift 4.0
let version =Bundle.main.infoDictionary!["CFBundleShortVersionString"]!let build =Bundle.main.infoDictionary!["CFBundleVersion"]!
На самом деле это немного по-другому. Я использую распаковку, например. Вы можете подумать, что принудительное распаковывание вообще плохо, это один из редких случаев, когда это нормально. Чтобы объяснить это немного, эти значения должны быть в словаре, иначе что-то действительно не так с файлом проекта. Вот почему этот подход использует
распаковку
Переименование и принудительное развертывание - это не изменение в качестве нового ответа. Кроме того, люди могут узнать, что распаковка может быть использована где угодно, когда они увидят ваш ответ. Для читателей, не думайте, что ключ есть, всегда лучше обрабатывать необязательное развертывание вручную, чем принудительное развертывание.
Ганхан
Чтобы быть справедливым, есть несколько редких случаев, когда принудительное развертывание в порядке. Этот пост только показывает один случай, когда это может быть хорошо. Если вы хотите больше узнать о случаях распаковки, есть несколько хороших объяснений и учебных пособий от Пола Хадсона. Я действительно могу порекомендовать всем новичкам www.hackingwithswift.com
carmen_munich
Это хорошая рекомендация для новичков. Может быть, вы также можете прочитать больше и узнать больше. Также вы должны улучшить свое понимание комментариев и того, что они подразумевают. Например, никто не говорил вам никогда / никогда не использовать распаковку силой. Но для информации, эти ключи могут быть удалены, а принудительное развертывание может привести к сбою. Развертывание здесь безопаснее.
Ганхан
Может быть, вы можете объяснить, в каком случае они могут быть удалены и ноль? То, что я узнал из упомянутого ресурса, не в этом особом случае. Они всегда должны быть там, если файл проекта не поврежден, в этом случае проект, вероятно, не будет компилироваться в любом случае
carmen_munich
16
Для Swift 3.0 NSBundle не работает, следующий код работает отлично.
let versionNumberString =Bundle.main.object(forInfoDictionaryKey:"CFBundleShortVersionString")as!String
и только для номера сборки это:
let buildNumberString =Bundle.main.object(forInfoDictionaryKey:"CFBundleVersion")as!String
Смущает, что 'CFBundleVersion' - это номер сборки, введенный в Xcode в General-> Identity.
Обратите внимание на использование localizedInfoDictionary для выбора правильной языковой версии отображаемого имени пакета.
var displayName:String?var version:String?var build:String?overridefunc viewDidLoad(){super.viewDidLoad()// Get display name, version and build
iflet displayName =Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"]as?String{self.displayName = displayName
}iflet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String{self.version = version
}iflet build =Bundle.main.infoDictionary?["CFBundleVersion"]as?String{self.build = build
}}
let gAppVersion =Bundle.main.object(forInfoDictionaryKey:"CFBundleShortVersionString")??"0"let gAppBuild =Bundle.main.object(forInfoDictionaryKey:"CFBundleVersion")??"0"
importFoundationpublicextensionBundle{publicvar shortVersion:String{iflet result = infoDictionary?["CFBundleShortVersionString"]as?String{return result
}else{
assert(false)return""}}publicvar buildVersion:String{iflet result = infoDictionary?["CFBundleVersion"]as?String{return result
}else{
assert(false)return""}}publicvar fullVersion:String{return"\(shortVersion)(\(buildVersion))"}}
ОП запросил как номер версии, так и номер сборки. К сожалению, большинство ответов не предоставляют оба этих варианта. Кроме того, другие добавляют ненужные методы расширения. Вот тот, который довольно прост и решает проблему ОП:
Посмотрев на документацию, я считаю, что следующее чище:
let version =NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString")as?String
Источник : «Использование этого метода предпочтительнее других методов доступа, потому что он возвращает локализованное значение ключа, когда он доступен».
это верный путь Свифта, без поворота силы, где угодно
Хуан Боэро,
5
Для Swift 1.2 это:
let version =NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]as!Stringlet build =NSBundle.mainBundle().infoDictionary!["CFBundleVersion"]as!String
extensionUIApplication{staticvar appVersion:String{iflet appVersion =NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString"){return"\(appVersion)"}else{return""}}staticvar build:String{iflet buildVersion =NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey asString){return"\(buildVersion)"}else{return""}}staticvar versionBuild:String{let version =UIApplication.appVersion
let build =UIApplication.build
var versionAndBuild ="v\(version)"if version != build {
versionAndBuild ="v\(version)(\(build))"}return versionAndBuild
}}
Внимание: вы должны использовать if let здесь, если не установлена версия или сборка приложения, что приведет к падению, если вы попытаетесь использовать! развернуть.
для всех, кто интересуется, есть хорошая и аккуратная библиотека, SwifterSwiftдоступная на github, а также полностью документированная для каждой версии swift (см. swifterswift.com ).
Используя эту библиотеку, читать версию приложения и номер сборки так же просто, как это:
importSwifterSwiftlet buildNumber =SwifterSwift.appBuild
let version =SwifterSwift.appVersion
вот функция, которую я использую, чтобы решить, показывать ли страницу "приложение обновлено" или нет. Он возвращает номер сборки, который я преобразую в Int:
iflet version:String=Bundle.main.infoDictionary?["CFBundleVersion"]as?String{guardlet intVersion =Int(version)else{return}ifUserDefaults.standard.integer(forKey:"lastVersion")< intVersion {
print("need to show popup")}else{
print("Don't need to show popup")}UserDefaults.standard.set(intVersion, forKey:"lastVersion")}
Если никогда не использовался раньше, он вернет 0, который меньше текущего номера сборки. Чтобы не показывать такой экран новым пользователям, просто добавьте номер сборки после первого входа в систему или после завершения регистрации.
Bundle + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Я объединил идеи из нескольких ответов и немного расширил:
пример SwiftUI
Отображает смайлик с предупреждающим треугольником (а не сбой приложения), если ключ отсутствует в Info.plist
Фонд импорта
Bundle extension {
publicvar appVersionShort:String?{iflet result = infoDictionary?["CFBundleShortVersionString"]as?String{return result
}else{return"⚠️"}}publicvar appVersionLong:String?{iflet result = infoDictionary?["CFBundleVersion"]as?String{return result
}else{return"⚠️"}}publicvar appName:String?{iflet result = infoDictionary?["CFBundleName"]as?String{return result
}else{return"⚠️"}}
CFBundleVersion
& CFBundleShortVersionString`. Первая - это ваша версия сборки . Другой номер версии . Смотрите здесь для получения дополнительной информацииОтветы:
РЕДАКТИРОВАТЬ
Обновлено для Swift 4.2
РЕДАКТИРОВАТЬ
Как указал @azdev в новой версии Xcode, вы получите ошибку компиляции при попытке использовать мое предыдущее решение, чтобы решить эту проблему, просто отредактируйте его, как предложено, чтобы развернуть словарь пакета, используя!
Конец Править
Просто используйте ту же логику, что и в Objective-C, но с небольшими изменениями
Я надеюсь, что это помогает вам.
Дэвид
источник
infoDictionary
должен быть развернут с помощью!
. Это то, что я использую, помещено в файл Globals.swift:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Я знаю, что на это уже ответили, но лично я думаю, что это немного чище:
Swift 3.0:
Свифт <2.3
Таким образом, версия if let заботится об условной обработке (в моем случае задает текст метки), и если infoDictionary или CFBundleShortVersionString равны нулю, необязательное развертывание приведет к пропуску кода.
источник
self.labelVersion.text
является необязательным типом, так что вы можете напрямую назначитьNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
let
, просто интересно, зачем это нужно. Спасибо!Обновлено для Swift 3.0
В
NS
-prefixes теперь ушли в Swift 3.0 и некоторые свойства / методы изменились имена более Swifty. Вот как это выглядит сейчас:Старый обновленный ответ
Оригинальный ответ
источник
Я также знаю, что на это уже ответили, но я обернул предыдущие ответы:
(*) Обновлено для расширений
Применение:
@ Устарел: старые ответы
Swift 3.1 :
Для более старых версий :
Так что если вы хотите установить текст метки или хотите использовать где-то еще;
источник
Для Swift 4.0
источник
Я сделал расширение на Bundle
а затем использовать его
источник
Для Swift 3.0 NSBundle не работает, следующий код работает отлично.
и только для номера сборки это:
Смущает, что 'CFBundleVersion' - это номер сборки, введенный в Xcode в General-> Identity.
источник
Xcode 9.4.1 Swift 4.1
Обратите внимание на использование localizedInfoDictionary для выбора правильной языковой версии отображаемого имени пакета.
источник
Xcode 8, Swift 3:
источник
Swift 4, полезное расширение для Bundle
источник
Bundle + Extensions.swift
Применение:
источник
ОП запросил как номер версии, так и номер сборки. К сожалению, большинство ответов не предоставляют оба этих варианта. Кроме того, другие добавляют ненужные методы расширения. Вот тот, который довольно прост и решает проблему ОП:
источник
Мой ответ (по состоянию на август 2015 года), учитывая, что Свифт продолжает развиваться:
источник
Я создал расширение для UIApplication.
источник
Посмотрев на документацию, я считаю, что следующее чище:
Источник : «Использование этого метода предпочтительнее других методов доступа, потому что он возвращает локализованное значение ключа, когда он доступен».
источник
Для Swift 1.2 это:
источник
Свифт 3:
Номер версии
Номер сборки
источник
Swift 4
Быстрый старый синтаксис
источник
Внимание: вы должны использовать if let здесь, если не установлена версия или сборка приложения, что приведет к падению, если вы попытаетесь использовать! развернуть.
источник
Вот обновленная версия для Swift 3.2:
источник
Теперь вы можете использовать константу для этого, вместо того, чтобы использовать строковый код, как раньше, что делает вещи еще более удобными.
источник
источник
SWIFT 4
// Сначала получаем nsObject, определяя как необязательный AnyObject
// Затем просто приведем объект в виде String, но будьте осторожны, вы можете перепроверить ноль
источник
для всех, кто интересуется, есть хорошая и аккуратная библиотека,
SwifterSwift
доступная на github, а также полностью документированная для каждой версии swift (см. swifterswift.com ).Используя эту библиотеку, читать версию приложения и номер сборки так же просто, как это:
источник
Обновление для Swift 5
вот функция, которую я использую, чтобы решить, показывать ли страницу "приложение обновлено" или нет. Он возвращает номер сборки, который я преобразую в Int:
Если никогда не использовался раньше, он вернет 0, который меньше текущего номера сборки. Чтобы не показывать такой экран новым пользователям, просто добавьте номер сборки после первого входа в систему или после завершения регистрации.
источник
Для Swift 5.0 :
источник
Простая служебная функция для возврата версии приложения как Int
источник
источник
Bundle + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Я объединил идеи из нескольких ответов и немного расширил:
Фонд импорта
Bundle extension {
}
SwiftUI пример использования
источник
источник