Як отримати версію програми та номер збірки за допомогою Swift?


386

У мене є додаток IOS із задньою версією Azure, і я хотів би реєструвати певні події, наприклад, входи в систему та версії користувачів користувачів програми.

Як я можу повернути версію та номер збірки за допомогою Swift?



6
Це Objective-C, а не Swift.
Øyvind Vik

10
Не забудьте переплутати CFBundleVersion& CFBundleShortVersionString`. Перша - ваша версія збірки . Інший - номер версії . Дивіться тут для отримання додаткової інформації
мед

1
@ ØyvindVik Більшість людей припускають, що ви можете перекласти об'єкт-C на Swift, не тримаючи руки.
gnasher729

Відповіді:


424

EDIT

Оновлено для Swift 4.2

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String

EDIT

Як вказував @azdev, у новій версії Xcode ви отримаєте помилку компіляції при спробі мого попереднього рішення, щоб вирішити це, просто відредагуйте його так, як пропонувалося розгортати словник пакету за допомогою!

let nsObject: AnyObject? = Bundle.main.infoDictionary!["CFBundleShortVersionString"]

Завершити редагування

Просто використовуйте ту ж логіку, що і в Objective-C, але з деякими невеликими змінами

//First get the nsObject by defining as an optional anyObject
let nsObject: AnyObject? = NSBundle.mainBundle().infoDictionary["CFBundleShortVersionString"]

//Then just cast the object as a String, but be careful, you may want to double check for nil
let version = nsObject as! String

Я сподіваюся, що це вам допоможе.

Девід


Коли я користуюсь цим, я отримую помилку компілятора "" [NSObject: AnyObject]? Не має члена з ім'ям "subcript" "
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
yosei

3
Вам слід уникати використання примусового розкручування "!" як вони будуть викликати додаток до аварії , коли один з цих значень дорівнює нуль
Julius

278

Я знаю, що на це вже відповіли, але особисто я думаю, що це трохи чистіше:

Swift 3.0:

 if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
    self.labelVersion.text = version
}

Швидкий <2.3

if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
    self.labelVersion.text = version
}

Таким чином, версія if let опікується умовною обробкою (встановленням тексту мітки в моєму випадку) і якщо infoDictionary або CFBundleShortVersionString є нульовим, необов'язкове розгортання призведе до пропуску коду.


6
self.labelVersion.textНеобов’язковий тип, тому ви можете безпосередньо призначитиNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
Йонауз

8
Чи є причина, яку б значення не було встановлено? Погодився, що, безумовно, обережніше let, просто цікаво, чому це може знадобитися. Дякую!
Crashalot

@Crashalot незважаючи на ваше ім'я;) ви не хочете, щоб ваш додаток вийшов з ладу, якщо, скажімо, ви робили помилку, швидше, щоб номер версії був "щось пішло не так".
Даніель Спрінгер

ОП: ви можете замінити? з! та видаліть "як String". Якщо це нуль, воно все одно не зірветься
Даніель Спрінгер

245

Оновлено для Swift 3.0

Тепер NS-префікси відсутній у Swift 3.0, і кілька властивостей / методів змінили імена, щоб вони були більш швидкими. Ось як це виглядає зараз:

extension Bundle {
    var releaseVersionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }
    var buildVersionNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }
}

Bundle.main.releaseVersionNumber
Bundle.main.buildVersionNumber

Стара оновлена ​​відповідь

Я багато працював з Frameworks з моєї оригінальної відповіді, тому хотів оновити своє рішення на те, що є і простішим, і набагато кориснішим у середовищі з декількома пакетами:

extension NSBundle {

    var releaseVersionNumber: String? {
        return self.infoDictionary?["CFBundleShortVersionString"] as? String
    }

    var buildVersionNumber: String? {
        return self.infoDictionary?["CFBundleVersion"] as? String
    }

}

Тепер це розширення буде корисним у додатках для виявлення як основного, так і будь-якого іншого включеного пакету (наприклад, спільного фреймворку для програмування розширень або третіх фреймворків, таких як AFNetworking), наприклад:

NSBundle.mainBundle().releaseVersionNumber
NSBundle.mainBundle().buildVersionNumber

// or...

NSBundle(URL: someURL)?.releaseVersionNumber
NSBundle(URL: someURL)?.buildVersionNumber

Оригінальний відповідь

Я хотів попрацювати над деякими з вже опублікованих відповідей. Я написав розширення класу, яке можна додати до ланцюжка інструментів, щоб вирішити цю проблему більш логічно.

extension NSBundle {

class var applicationVersionNumber: String {
    if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]

як? Рядок {return version} return "Номер версії недоступний"}

class var applicationBuildNumber: String {
    if let build = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String {
        return build
    }
    return "Build Number Not Available"
}

}

Тож тепер ви можете легко отримати доступ до цього:

let versionNumber = NSBundle.applicationVersionNumber

CFBundleVersionKey більше не працює в Swift 3, Xcode 8. Чи знаєте ви новий ключ, який потрібно використовувати?
Crashalot

71

Я також знаю, що на це вже відповіли, але я завершив попередні відповіді:

(*) Оновлено для розширень

extension Bundle {
    var releaseVersionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }
    var buildVersionNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }
    var releaseVersionNumberPretty: String {
        return "v\(releaseVersionNumber ?? "1.0.0")"
    }
}

Використання:

someLabel.text = Bundle.main.releaseVersionNumberPretty

@ Попередньо: старі відповіді

Швидкий 3.1 :

class func getVersion() -> String {
    guard let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
        return "no version info"
    }
    return version
}

Для старих версій :

class func getVersion() -> String {
    if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
        return version
    }
    return "no version info"
}

Тож якщо ви хочете встановити текст мітки або хочете використовувати десь ще;

self.labelVersion.text = getVersion()

1
або: class func getVersion () -> String {return NSBundle.mainBundle (). infoDictionary? ["CFBundleShortVersionString"] як? Рядок ?? "немає інформації про версію"}
tapmonkey

Я думаю, копіювати інші відповіді не має сенсу. Якщо ваша відповідь більше не відповідає дійсності, ви завжди маєте можливість видалити її та звільнити місце для інших відповідей :)
carmen_munich

1
@carmen_munich Оскільки ти наклепиш тут, я мушу відповісти тобі. Перш за все, ця відповідь розміщена у березні 2015 року, а ваша відповідь - у лютому 2017 року. Отже, ваше натхнення має виходити з попередніх відповідей. По-друге, я взагалі не бачив вашої відповіді, я оновив свою відповідь, тому що зараз її використовую. Використання розширення не є унікальним для когось із спільноти iOS, я думаю. Дійсно, будь ласка, намагайтеся бути зрілими та шанувати інших розробників. Я нічого не отримую тут. Я хотів би допомогти людям, це все. Будь ласка, намагайтеся не відмовляти людям, які намагаються допомогти на тему "SO".
Гуньхан

Я почув багато відгуків від новачків про те, що вони публікують відповідь і хочуть побачити, що хтось натискає "вгору", що дуже приємно бачити і мотивувати людей. Але якщо хтось скопіює відповіді у застарілій відповіді, той, хто доклав зусиль, щоб опублікувати її, не отримає такої мотивації, що хтось проголосував за неї. Тож новачки справді відчувають розчарування та відчувають, що вони не приносять цінності громаді та перестають публікувати публікації. І не зрозумійте це неправильно, я маю на увазі це загалом. Сподіваюся, ви не почуєтесь ображеним і краще зрозумієте, чому я зробив цю пропозицію.
carmen_munich

@carmen_munich Якщо ви хронологічно замовляєте відповіді на це питання, ви помітите, що хтось уже дав таку ж відповідь, як і ви перед вами! Отже, ви звинувачуєте мене в чомусь, що ви зробили самі. Оскільки я маю історію з цим питанням, я поділився своїми новими налаштуваннями використання в оновленнях. Це все.
Гуньхан


28

Я зробив розширення на пакет

extension Bundle {

    var appName: String {
        return infoDictionary?["CFBundleName"] as! String
    }

    var bundleId: String {
        return bundleIdentifier!
    }

    var versionNumber: String {
        return infoDictionary?["CFBundleShortVersionString"] as! String 
    }

    var buildNumber: String {
        return infoDictionary?["CFBundleVersion"] as! String
    }

}

а потім використовувати його

versionLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"

Насправді його трохи інакше. Я, наприклад, використовую силу розкручування. Ви можете подумати, що сила розгортання взагалі погана, це один з рідкісних випадків, коли це нормально. Щоб пояснити це трохи більше, ці значення повинні бути у словнику, інакше щось не так з файлом проекту. Ось чому цей підхід використовує силу розкручування :-)
carmen_munich

Перейменування та розгортання не є зміною для публікації як нової відповіді. Крім того, люди можуть навчитися розгортанню сили можна використовувати де завгодно, коли побачать вашу відповідь. Читачі, не вважайте, що ключ є, завжди краще обробляти необов'язкове розгортання вручну, а не примусово розгортати.
Гуньхан

Справедливості мають бути деякі рідкісні випадки, коли розгортання сили нормально. Це одне повідомлення лише показує один випадок, коли це може бути добре. Якщо ви хочете дізнатися більше про випадки розгортання сили, є кілька хороших пояснень та посібників від Пола Хадсона. Я дійсно можу порекомендувати усім новачкам
www.hackingwithswift.com

Це хороша рекомендація для новачків. Можливо, ви також можете прочитати більше та дізнатися більше. Також слід покращити ваше розуміння щодо коментарів та того, що вони мають на увазі. Наприклад, ніхто не сказав вам ніколи і ніколи не застосовувати розпакування. Але для інформаційного зображення ці клавіші можуть бути вилучені, і сила розгортання може призвести до аварії. Тут безпечніше впоратися з розгортанням.
Гуньхан

Можливо, ви можете пояснити, у якому випадку вони можуть бути видалені та бути нульовими? Те, що я дізнався з ресурсу, згадав, що це не в цьому конкретному випадку. Вони завжди повинні бути там, якщо файл проекту не буде порушений, в такому випадку проект, ймовірно, не
збирається

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 на Загальна-> Ідентичність.


15

Xcode 9.4.1 Swift 4.1

Зверніть увагу на використання localizedInfoDictionary для підбору правильної мовної версії відображуваного імені пакета.

var displayName: String?
var version: String?
var build: String?

override func viewDidLoad() {
    super.viewDidLoad()

    // Get display name, version and build

    if let displayName = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String {
        self.displayName = displayName
    }
    if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        self.version = version
    }
    if let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
        self.build = build
    }
}

14

Xcode 8, Swift 3:

let gAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let gAppBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"

12

Swift 4, корисне розширення для Bundle

import Foundation

public extension Bundle {

    public var shortVersion: String {
        if let result = infoDictionary?["CFBundleShortVersionString"] as? String {
            return result
        } else {
            assert(false)
            return ""
        }
    }

    public var buildVersion: String {
        if let result = infoDictionary?["CFBundleVersion"] as? String {
            return result
        } else {
            assert(false)
            return ""
        }
    }

    public var fullVersion: String {
        return "\(shortVersion)(\(buildVersion))"
    }
}

Для цього вам потрібно сказати, наприклад, Bundle.main.fullVersion
Джозеф Астрахан,

11

Комплект + розширення

import Foundation

extension Bundle {
    var versionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }

    var buildNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }

    var bundleName: String? {
        return infoDictionary?["CFBundleName"] as? String
    }
}

Використання:

someLabel.text = Bundle.main.versionNumber

11

ОП запитували і номер версії, і номер збірки. На жаль, більшість відповідей не передбачають обох цих варіантів. Крім того, інші додають непотрібні методи розширення. Ось це досить просто і вирішує проблему ОП:

// Example output: "1.0 (234)"
private func versionAndBuildNumber() -> String {
  let versionNumber = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
  let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
  if let versionNumber = versionNumber, let buildNumber = buildNumber {
    return "\(versionNumber) (\(buildNumber))"
  } else if let versionNumber = versionNumber {
    return versionNumber
  } else if let buildNumber = buildNumber {
    return buildNumber
  } else {
    return ""
  }
}

9

Моя відповідь (станом на серпень 2015 року), якщо Swift постійно розвивається:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String

8

Я створив розширення для UIApplication.

extension UIApplication {
    static var appVersion: String {
        let versionNumber = Bundle.main.infoDictionary?[IdentifierConstants.InfoPlist.versionNumber] as? String
        let buildNumber = Bundle.main.infoDictionary?[IdentifierConstants.InfoPlist.buildNumber] as? String

        let formattedBuildNumber = buildNumber.map {
            return "(\($0))"
        }

        return [versionNumber,formattedBuildNumber].compactMap { $0 }.joined(separator: " ")
    }
}

struct IdentifierConstants {
    struct InfoPlist {
        static let versionNumber = "CFBundleShortVersionString"
        static let buildNumber = "CFBundleVersion"
    }
}

6

Переглянувши документацію, я вважаю, що наступне є більш чистим:

let version = 
NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") 
as? String

Джерело : "Використання цього методу є кращим перед іншими методами доступу, оскільки він повертає локалізоване значення ключа, коли такий доступний."


1
це правильний Швидкий шлях, без сили розгортання, нікуди
Хуан Боро

5

Для Swift 1.2 це:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
let build = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String

1
ви могли б використовувати? також
Dan Rosenstark

4

Швидкий 3:

Номер версії

if let versionNumberString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { // do something }

Номер побудови

if let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { // do something }

Як щодо номера збірки? Дякую! CFBundleVersionKey не працює.
Crashalot

@Crashalot Я також оновив його з номером збірки. Ось також список усіх основних
фондових

3

Швидкий 4

func getAppVersion() -> String {
    return "\(Bundle.main.infoDictionary!["CFBundleShortVersionString"] ?? "")"
}

Bundle.main.infoDictionary! ["CFBundleShortVersionString"]

Швидкий старий синтаксис

let appVer: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]

2
extension UIApplication {

    static var appVersion: String {
        if let appVersion = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") {
            return "\(appVersion)"
        } else {
            return ""
        }
    }

    static var build: String {
        if let buildVersion = NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey as String) {
            return "\(buildVersion)"
        } else {
            return ""
        }
    }

    static var versionBuild: String {
        let version = UIApplication.appVersion
        let build = UIApplication.build

        var versionAndBuild = "v\(version)"

        if version != build {
            versionAndBuild = "v\(version)(\(build))"
        }

        return versionAndBuild
    }

}

Увага: Вам слід скористатись, якщо нехай тут, у випадку, якщо версія програми чи збірка не встановлена, що призведе до збоїв, якщо ви спробуєте використовувати! розмотувати.


2

Ось оновлена ​​версія Swift 3.2:

extension UIApplication
{
    static var appVersion:String
    {
        if let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
        {
            return "\(appVersion)"
        }
        return ""
    }

    static var buildNumber:String
    {
        if let buildNum = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String)
        {
            return "\(buildNum)"
        }
        return ""
    }

    static var versionString:String
    {
        return "\(appVersion).\(buildNumber)"
    }
}

2

Тепер ви можете використовувати константу для цього, а не використовувати строго набраний код, як раніше, що робить речі ще зручнішими.

var appVersion: String {
    return Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String
}


1

SWIFT 4

// Спочатку отримайте nsObject, визначивши його як необов'язковий AnyObject

let nsObject: AnyObject? = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as AnyObject

// Тоді просто киньте об'єкт як String, але будьте обережні, можливо, ви захочете подвійно перевірити наявність нуля

let version = nsObject as! String

1

Проста функція утиліти для повернення версії програми як Int

func getAppVersion() -> Int {

        if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {

            let appVersionClean = appVersion.replacingOccurrences(of: ".", with: "", options: NSString.CompareOptions.literal, range:nil)

            if let appVersionNum = Int(appVersionClean) {
                return appVersionNum
            }
        }
        return 0
    }

1
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            self.lblAppVersionValue.text = version
        }

0

Для всіх, хто цікавиться, є приємна і акуратна бібліотека, яка називається SwifterSwiftдоступною в github, а також повністю задокументована для кожної версії swift (див. swifterswift.com ).

за допомогою цієї бібліотеки читати версію програми та номер збірки буде так само просто:

import SwifterSwift

let buildNumber = SwifterSwift.appBuild
let version = SwifterSwift.appVersion

0
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        lblVersion.text = "Version \(version)"

    }

0

Оновлення для Swift 5

ось функція, яку я використовую, щоб вирішити, показувати сторінку "оновлений додаток" чи ні. Він повертає номер збірки, який я перетворюю на Int:

if let version: String = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
        guard let intVersion = Int(version) else { return }

        if UserDefaults.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, що нижче поточного номера збірки. Щоб не показувати такий екран новим користувачам, просто додайте номер збірки після першого входу або після завершення бортового входу.


0

Для Swift 5.0 :

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String

0

Swift 5 як розширення UIApplication

extension UIApplication {
    static var release: String {
        return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String? ?? "x.x"
    }
    static var build: String {
        return Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String? ?? "x"
    }
    static var version: String {
        return "\(release).\(build)"
    }
}

Приклад використання:

print("release: \(UIApplication.release)")
print("build: \(UIApplication.build)")
print("version: \(UIApplication.version)")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.