452

I have an IOS app with an Azure back-end, and would like to log certain events, like logins and which versions of the app users are running.

How can I return the version and build number using Swift?

Øyvind Vik
  • 4,829
  • 2
  • 11
  • 16
  • http://stackoverflow.com/questions/7608632/how-do-i-get-the-current-version-of-my-ios-project-in-code – Yibo Cai Sep 22 '14 at 00:42
  • 6
    That's Objective-C, not Swift. – Øyvind Vik Sep 22 '14 at 02:38
  • 11
    Be sure to not confuse `CFBundleVersion` & CFBundleShortVersionString`. The first is your **build** version. The other is **version** number. See [here](http://stackoverflow.com/questions/6851660/version-vs-build-in-xcode) for more info – Honey Nov 07 '16 at 22:24
  • 1
    @ØyvindVik Most people assume that you can translate an Objective-C solution to Swift without hand holding. – gnasher729 Oct 20 '19 at 13:19

33 Answers33

520

EDIT

Updated for Swift 4.2

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

EDIT

As pointed out by @azdev on the new version of Xcode you will get a compile error for trying my previous solution, to solve this just edit it as suggested to unwrap the bundle dictionary using a !

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

End Edit

Just use the same logic than in Objective-C but with some small changes

//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

I hope this helps you out.

David

Harcker
  • 131
  • 1
  • 13
David
  • 5,589
  • 1
  • 13
  • 15
  • When I use this, I get a compiler error "[NSObject : AnyObject]? does not have a member named 'subscript'" – andreas Nov 08 '14 at 13:38
  • You can try replacing the AnyObject? by AnyObject! without knowing exactly the code you are using is very difficult to guess what is wrong, also keep in mind that Swift can change from one Xcode release to another, so it will also be relevant to know your version of Xcode. – David Nov 10 '14 at 00:10
  • 19
    @andreas `infoDictionary` should be unwrapped using `!`. This is what I am using, placed into a Globals.swift file: `let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String` – azdev Nov 10 '14 at 16:25
  • For those getting the subscript error, andreas answer is what will fix it, it worked for me. Swift keeps tweaking what is an optional in their releases – Unome Dec 18 '14 at 21:16
  • 2
    I had to add one more "!" after "as". `let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String` – yosei May 03 '15 at 00:01
  • 1
    I'm confused. This is just the build number, correct? What about the app version? – Slaknation Apr 08 '19 at 21:21
  • 3
    You should avoid using a forced unwrap "!" as they will cause your app to crash whenever one of those values is nil – Julius Jul 12 '19 at 15:46
  • 2
    @Julius I would argue that the app should crash when one of these values is null - what else are you going to do? – Hannes Hertach Jul 09 '20 at 06:45
292

I know this has already been answered but personally I think this is a little cleaner:

Swift 3.0:

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

Swift <2.3

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

This way, the if let version takes care of the conditional processing (setting the label text in my case) and if infoDictionary or CFBundleShortVersionString are nil the optional unwrapping will cause the code to be skipped.

Zac
  • 403
  • 6
  • 16
Timothy Tripp
  • 3,129
  • 1
  • 12
  • 7
  • 7
    ```self.labelVersion.text``` is Optional type, so you can directly assign ```NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String``` – Jonauz Nov 25 '15 at 00:43
  • 10
    Is there a reason the value would not be set? Agreed it's definitely more cautious with `let`, just wondering why it might be needed. Thanks! – Crashalot Feb 08 '16 at 09:13
  • @Crashalot despite your name ;) you don't want your app to crash if, say, you make a typo, rather have the version number be "something went wrong". – Daniel Springer Jul 09 '18 at 06:18
  • OP: you can replace the ? with ! and remove "as String". If it's nil, it's anyways not gonna crash – Daniel Springer Jul 09 '18 at 06:22
281

Updated for Swift 3.0

The NS-prefixes are now gone in Swift 3.0 and several properties/methods have changed names to be more Swifty. Here's what this looks like now:

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

Bundle.main.releaseVersionNumber
Bundle.main.buildVersionNumber

Old Updated Answer

I've been working with Frameworks a lot since my original answer, so I wanted to update my solution to something that is both simpler and much more useful in a multi-bundle environment:

extension NSBundle {

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

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

}

Now this extension will be useful in apps to identify both the main bundle and any other included bundles (such as a shared framework for extension programming or third frameworks like AFNetworking), like so:

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

// or...

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

Original Answer

I wanted to improve on some of the answers already posted. I wrote a class extension that can be added to your tool chain to handle this in a more logical fashion.

extension NSBundle {

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

as? String { return version } return "Version Number Not Available" }

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

}

So now you can access this easily by:

let versionNumber = NSBundle.applicationVersionNumber
Blake Merryman
  • 3,525
  • 1
  • 14
  • 14
88

I also know this has already been answered but I wrapped up the previous answers:

(*)Updated for extensions

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")"
    }
}

Usage:

someLabel.text = Bundle.main.releaseVersionNumberPretty

@Deprecated: Old answers

Swift 3.1:

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

For older versions:

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

So if you want to set label text or want to use somewhere else;

self.labelVersion.text = getVersion()
Gunhan
  • 5,433
  • 2
  • 37
  • 33
  • 1
    or: class func getVersion() -> String { return NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String ?? "no version info" } – tapmonkey Jun 17 '15 at 10:39
  • I think copying other answers doesn't make sense. If your answer is not valid anymore then you always have the possibility to delete it and make room for the other answers :) – carmen_munich Apr 18 '19 at 13:14
  • 1
    @carmen_munich Since you slander here I have to answer to you. First of all, this answer is posted March 2015 and your answer is posted Feb 2017. Therefore, your inspiration must come from the earlier answers. Secondly, I have not seen your answer at all, I updated my answer because I use it this way nowadays. Using an extension is not unique to someone in the iOS community I guess. Really, please try to be mature and respect other developers. I don't gain anything posting here. I'd like to help people that's it. Please try not to discourage people trying to help on SO. – Gunhan Apr 18 '19 at 14:23
  • I heard a lot of feedback from newbies that they post an answer and want to see that someone clicks on "up" which is really nice to see and motivates people. But if someone copies answers in his outdated answer the one who made the effort to post it will not get that motivation that someone voted it up. So the newbies are really feel disappointment and have the feeling that they don't bring value to the community and stop posting. And don't get it wrong, I mean this in general. Hope you don't feel offended and understand now better why I made this suggestion. – carmen_munich Apr 23 '19 at 13:54
  • @carmen_munich If you chronologically order the answers on this question you’ll notice that someone else already given the same answer as you did before you! So you’re blaming me something that you’d done yourself. Since I’ve history for this question, I shared my new usage preferences in an update. That’s all. – Gunhan Apr 23 '19 at 16:22
  • Actually I don't see the same code above, that's why I added this code snippet and it went up because it wasn't there before I guess. But again that's not the point I wanted to make clear you can delete outdated answers instead of copying the answer from someone else into an update of your answer. I'm sorry that you feel offended and don't get the reasons why this is nicer to people who want to contribute – carmen_munich Apr 24 '19 at 07:07
  • @carmen_munich Why don't you understand I don't know but I have not copied any answer from anyone. I shared my updated usage in an update without seeing your super amazing cool patent-proof answer. You're blaming me but apparently you're the one posted after "Blake Merryman"'s answer. And it seems your answer is identical to his answer. And he posted before you if you check the dates. So you should delete your copied answer if you wanna follow your own recommendation. – Gunhan Apr 24 '19 at 08:37
  • I didn't update my answer, still the same as it was from beginning. But if it's outdated an not valid anymore I will delete it :-) – carmen_munich Apr 24 '19 at 09:17
  • And if I find another approach and both are valid I'll add another answer and people can upvote which one they better like. And then both approaches are separated and a reader can clearly see which one the community think is more valuable then the other. – carmen_munich Apr 24 '19 at 09:26
  • @carmen_munich Your answer is identical to "Blake Merryman"'s answer. The only difference is the property names and you force unwrap optionals which is actually not a good approach anyway. The point is your original answer(yes I never said you updated your answer) is identical to an existing answer when you first posted your answer. Therefore, It means you copied from him, so you better delete your answer. And copying from someone else really discourage others. – Gunhan Apr 24 '19 at 10:21
  • as you said it's not identical :-) And if you read my comment it's about outdated answers – carmen_munich Apr 24 '19 at 10:24
  • @carmen_munich There is no difference if you rename something so it is identical. – Gunhan Apr 24 '19 at 10:26
  • I don't want to repeat myself, and I think I made in comments above clear why I don't think this approach is good. You can ignore it or take it as feedback. Have a nice day. – carmen_munich Apr 24 '19 at 10:26
  • @carmen_munich I respect opinions but you started blaming me which invalidated your points. And if you're a regular SO user you should know that it's a common approach to update an existing answer with a new usage and/or version changes etc. I see your points but I don't agree with them. But you contradict yourself at the end. You shared an identical(yes you renamed variables good job) answer and claiming that I copied your not-so-original answer. This is wrong. And you can't just throw dirt on people like that. – Gunhan Apr 24 '19 at 10:33
  • I explained it my answer below which commented how it's different and why. Thanks for your feedback. Again it was not about my post and again sorry that you feel so offended – carmen_munich Apr 24 '19 at 11:03
  • By the way updating syntax is really good. Thumbs up. but updating to another approach isn't in my opinion – carmen_munich Apr 24 '19 at 11:13
  • Thanks for your comments @carmen_munich. It is your opinion I respect that. In my opinion, updating to a better approach in an existing answer is better because people who see this question first time usually sees the top answers. It is better to not lead them to an old fashion solution. And I don't think anyone deletes existing answers when they become irrelevant/obsolete because they still hold value and can be helpful to someone. – Gunhan Apr 24 '19 at 11:23
34

I made an Extension on Bundle

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
    }

}

and then use it

versionLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"
carmen_munich
  • 5,878
  • 1
  • 32
  • 39
  • Actually its bit different. I use force unwrapping for example. You might think force unwrapping in general is bad, this one of the rare cases where it is okay. To explain it a bit more, these values should be in the dictionary otherwise something is really wrong with the project file. That's why this approach is using force unwrapping :-) – carmen_munich Apr 24 '19 at 10:52
  • Renaming and force unwrapping is not a change to post as a new answer. Also, people might learn force unwrapping could be used anywhere when they see your answer. To the readers, don't assume the key is there, it's always better to handle optional unwrapping manually rather than force unwrapping. – Gunhan Apr 24 '19 at 11:41
  • To be fair there are some rare cases where force unwrapping is okay. This one post just shows one case where it can be okay. If you want to know more about the force unwrapping cases there are some good explanations and tutorials from Paul Hudson. I can really recommend to all newbies www.hackingwithswift.com – carmen_munich Apr 24 '19 at 11:46
  • It is a good recommendation for the newbies. Maybe you can also read more and learn more. Also you should improve your understanding about comments and what they imply. E.g. no one told you never/ever use force unwrapping. But for the info dict those keys can be removed and the force unwrap can result in a crash. It is safer to handle unwrapping here. – Gunhan Apr 24 '19 at 12:01
  • Maybe you can explain in which case they can get removed and be nil? What I learned from the resource mentioned it's not in this partiuclare case. They should always be there unless the project file is broken, in that case the project would probably not compile anyway – carmen_munich Apr 24 '19 at 12:07
  • Thanks for asking. First of all project definitely compiles. When you upload to AppStore there is a check for the build number. So it can be detected at that point. But if you're doing an internal enterprise deployment, there is actually no check for the info dictionary. As for your question, why it would not be there? Ideally it should be always there but unintentionally it could be removed. Since there is a possibility to not have that key in that dictionary file, I think it is better to not force unwrap it. Besides why would you? Probably you only need to use it for once. – Gunhan Apr 24 '19 at 12:19
  • sorry. but you haven't anwered why and who can the infoDictionary get nil? the value inside they key can be empty which doesn't mean it is nil. – carmen_munich Apr 24 '19 at 12:22
  • I doubt that you can compile an iOS Project without an infoDictionary. That the strings inside are empty maybe. but not without the dictionary – carmen_munich Apr 24 '19 at 12:23
  • To wrap it up: - There are some rare cases where force unwrapping is okay - without infoDictionary you can't compile it's okay to force unwrap it - BundleName, BundleId, versionNumber shouldn't never be deleted from info.plist so can't be nil - only buildNumber you could delete but this one is necessary for AppStore if decide to remove it, you might also remove buildNumber from this extension – carmen_munich Apr 24 '19 at 13:40
  • p.s. It seems only `CFBundleIdentifier` mandatory. You can compile and run without an issue if the other ones are removed. – Gunhan Apr 24 '19 at 15:18
  • yes as mentioned in wrap up "shouldn't delete them". I mean you could but ¯\_(ツ)_/¯ – carmen_munich Apr 25 '19 at 07:00
  • yeah it "shouldn't be" deleted but the point is bugs happen unintentionally. Anyway. – Gunhan Apr 25 '19 at 08:10
  • Then it's crashing and you can spot it this way very easily and early in develop phase that there is a bug/issue. Instead later when trying to upload to AppStore or testers reporting that app version is empty. What way you prefer is up to everyone, I don't force anyone to use this approach by posting it here. Up to everyone to make decision which solution at the end he or she picks. – carmen_munich Apr 25 '19 at 08:35
  • Also good resource for explanation why you sometimes want to force unwrap things https://www.swiftbysundell.com/posts/handling-non-optional-optionals-in-swift – carmen_munich Apr 29 '19 at 16:54
34

For Swift 4.0

let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"]!
let build = Bundle.main.infoDictionary!["CFBundleVersion"]!
Iryna Batvina
  • 1,338
  • 11
  • 7
23

Swift 5 as UIApplication extension

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)"
    }
}

example use:

print("release: \(UIApplication.release)")
print("build: \(UIApplication.build)")
print("version: \(UIApplication.version)")
ziligy
  • 1,177
  • 12
  • 9
17

For Swift 3.0 NSBundle doesn't work, Following code works perfectly.

let versionNumberString =
      Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
          as! String

and for just the build number, it is:

let buildNumberString =
      Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
          as! String

Confusingly 'CFBundleVersion' is the build number as entered in Xcode on General->Identity.

Tejas
  • 944
  • 11
  • 20
17

I created an extension for 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: " ")
    }
}

enum Constants {
    enum InfoPlist {
        static let versionNumber = "CFBundleShortVersionString"
        static let buildNumber = "CFBundleVersion"
    }
}
Sebastian Boldt
  • 4,947
  • 9
  • 46
  • 60
  • Great solution! Small tweaks possibly to help slower/newer developers. "enum Constants" should be "enum Identifier Constants" or vice versa. "import UIKit" was required on my project. Finally to call its just Application.appVersion – C. Skjerdal Feb 01 '21 at 23:32
16

Xcode 9.4.1 Swift 4.1

Note the use of localizedInfoDictionary to pick up the right language version of the bundle display name.

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
    }
}
Hugo F
  • 580
  • 4
  • 11
16

Bundle+Extension.swift (SwiftUI, Swift 5, Xcode 11)

I combined ideas from a few answers, and extended a bit:

  • a SwiftUI example
  • Displays a warning triangle emoticon (rather than crashing the app) if the key is missing from the Info.plist

import Foundation

extension Bundle {
    
    public var appVersionShort: String? {
        if let result = infoDictionary?["CFBundleShortVersionString"] as? String {
            return result
        } else {
            return "⚠️"
        }
    }
    public var appVersionLong: String? {
        if let result = infoDictionary?["CFBundleVersion"] as? String {
            return result
        } else {
            return "⚠️"
        }
    }
    public var appName: String? {
        if let result = infoDictionary?["CFBundleName"] as? String {
            return result
        } else {
            return "⚠️"
        }
    }
}

SwiftUI example use

VStack {

     Text("Version: \(Bundle.main.appVersionShort!) (\(Bundle.main.appVersionLong!))")
                    .font(.subheadline)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
}
Museer Ahamad Ansari
  • 4,939
  • 2
  • 35
  • 43
Gary W. Longsine
  • 537
  • 7
  • 12
  • 3
    I think it's unnecessary to return optional strings in the Bundle extension methods; regular ones work as well with the fallback. – Gyfis Oct 01 '20 at 08:04
15

Xcode 8, Swift 3:

let gAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let gAppBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"
Crashalot
  • 31,452
  • 56
  • 235
  • 393
13

Swift 4, useful Extension for 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))"
    }
}
maslovsa
  • 1,306
  • 11
  • 13
13

Bundle+Extensions.swift

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
    }
}

Usage:

someLabel.text = Bundle.main.versionNumber
zeeshan
  • 4,255
  • 1
  • 42
  • 53
Giang
  • 3,031
  • 26
  • 26
11

OP asked for both version number and build number. Unfortunately most of the answers don't provide both of those options. Additionally, others add unnecessary extension methods. Here's one that's pretty simple and solves OP's problem:

// 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 ""
  }
}
Senseful
  • 73,679
  • 56
  • 267
  • 405
9

My answer (as at Aug 2015), given Swift keeps evolving:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Charlie Seligman
  • 3,508
  • 4
  • 50
  • 84
6

Having looked at the documentation, I believe that the following is cleaner:

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

Source: "Use of this method is preferred over other access methods because it returns the localized value of a key when one is available."

Daniel Armyr
  • 61
  • 1
  • 3
5

For Swift 1.2 it's:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
let build = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Michael Samoylov
  • 2,396
  • 2
  • 22
  • 32
5

For Swift 5.0 :

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String
Délia
  • 81
  • 2
  • 5
5

Swift 5.3

let infoDictionaryKey = kCFBundleVersionKey as String
guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: infoDictionaryKey) as? String
else { fatalError("Expected to find a bundle version in the info dictionary") }
4

Swift 3:

Version Number

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

Build number

if let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { // do something }
jasonnoahchoi
  • 853
  • 5
  • 16
  • How about the build number? Thanks! CFBundleVersionKey does not work. – Crashalot Sep 25 '16 at 06:09
  • @Crashalot I updated it with the build number also. Here's also a list of all Core Foundation Keys: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html – jasonnoahchoi Sep 29 '16 at 17:05
3

Swift 4

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

Bundle.main.infoDictionary!["CFBundleShortVersionString"]

Swift old syntax

let appVer: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]
Harshil Kotecha
  • 2,518
  • 4
  • 24
  • 39
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
    }

}

Attention: You should use if let here in case that the app version or build is not set which will lead to crash if you try to use ! to unwrap.

futantan
  • 21
  • 2
2
public var appVersionNumberString: String {
    get {
        return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
    }
}
Olcay Ertaş
  • 5,374
  • 8
  • 71
  • 98
Mohammad Razipour
  • 3,324
  • 3
  • 26
  • 44
2

Here's an updated version for 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)"
    }
}
BadmintonCat
  • 9,002
  • 10
  • 64
  • 114
2

You can now use a constant for this, rather than having to use stringly-typed code like before, which makes things even more convenient.

var appVersion: String {
    return Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String
}
TheNeil
  • 1,985
  • 2
  • 17
  • 36
2
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            self.lblAppVersionValue.text = version
        }
Davender Verma
  • 399
  • 1
  • 10
1

SWIFT 4

//First get the nsObject by defining as an optional AnyObject

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

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

let version = nsObject as! String
user2807083
  • 2,606
  • 4
  • 25
  • 35
Prabhat Kasera
  • 1,111
  • 11
  • 28
1

for anyone interested, there's a nice and neat library called SwifterSwift available at github and also fully documented for every version of swift (see swifterswift.com).

using this library, reading app version and build number would be as easy as this:

import SwifterSwift

let buildNumber = SwifterSwift.appBuild
let version = SwifterSwift.appVersion
MFA
  • 417
  • 5
  • 14
  • In 2020, it's `let buildNumber = UIApplication.shared.buildNumber` and `let version = UIApplication.shared.version` – ddc Aug 14 '20 at 13:11
1

Update for Swift 5

here's a function i'm using to decide whether to show an "the app updated" page or not. It returns the build number, which i'm converting to an 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")
    }

If never used before it will return 0 which is lower than the current build number. To not show such a screen to new users, just add the build number after the first login or when the on-boarding is complete.

Community
  • 1
  • 1
Giovanni Palusa
  • 967
  • 1
  • 11
  • 31
1

Simple utility function to return App version as 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
    }
Tiago Mendes
  • 2,556
  • 1
  • 26
  • 29
0

For Swift 2.0

//First get the nsObject by defining as an optional anyObject

let nsObject: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]
let version = nsObject as! String
ham-sandwich
  • 3,714
  • 10
  • 29
  • 43
Aadi007
  • 237
  • 2
  • 5
0
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        lblVersion.text = "Version \(version)"

    }