113

I am attempting to gain access to the main NSBundle to retrieve version and build information. Thing is, I want to try it in Swift, I know how to retrieve it in Objective-C with:

text = [NSBundle.mainBundle.infoDictionary objectForKey:@"CFBundleVersion"];

Yet I don't know where to start with Swift, I have attempted to write it in the new syntax with no avail.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Ken-UbiDex
  • 1,213
  • 2
  • 8
  • 7
  • 2
    Show the attempts you've already made. It's very similar to the Objective-C implementation. – Mick MacCallum Jul 01 '14 at 01:38
  • Jan 2017 swift 2.3 : let sVer = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String let sBuild = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String self.myVersionLabel.text = String(format: "Version %@ Build %@", sVer!, sBuild!) – Matthew Ferguson Jan 15 '17 at 17:27

16 Answers16

185

What was wrong with the Swift syntax? This seems to work:

if let text = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
    print(text)
}
Marmoy
  • 8,009
  • 7
  • 46
  • 74
Connor Pearson
  • 63,902
  • 28
  • 145
  • 142
134

Swift 3/4 Version

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

Swift 2.x Version

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

as seen here.

mugx
  • 9,869
  • 3
  • 43
  • 55
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 1
    You get the same key twice, should use "CFBundleVersion" for version. I guess it is a copy/past typo :) – foOg Feb 25 '15 at 10:33
  • Thanks @foOg it was a typo. In fact it's backwards: the short one is the version, the regular one is the build. Weird, I know. – Dan Rosenstark Feb 25 '15 at 15:55
  • Swift 3 version . if let infoPath = Bundle.main.path(forResource: "Info.plist", ofType: nil), let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath), let infoDate = infoAttr[.creationDate] as? Date { return infoDate } return Date() – Ryan X Dec 06 '16 at 19:01
27

ab Swift 5.0

I created a wrapper to get some app related strings at one place in all my apps, called AppInfo.

/// Wrapper to get some app related strings at one place.
struct AppInfo {

   /// Returns the official app name, defined in your project data.
   var appName : String {
       return readFromInfoPlist(withKey: "CFBundleName") ?? "(unknown app name)"
   }

   /// Return the official app display name, eventually defined in your 'infoplist'.
   var displayName : String {
       return readFromInfoPlist(withKey: "CFBundleDisplayName") ?? "(unknown app display name)"
   }

   /// Returns the official version, defined in your project data.
   var version : String {
       return readFromInfoPlist(withKey: "CFBundleShortVersionString") ?? "(unknown app version)"
   }

   /// Returns the official 'build', defined in your project data.
   var build : String {
       return readFromInfoPlist(withKey: "CFBundleVersion") ?? "(unknown build number)"
   }

   /// Returns the minimum OS version defined in your project data.
   var minimumOSVersion : String {
    return readFromInfoPlist(withKey: "MinimumOSVersion") ?? "(unknown minimum OSVersion)"
   }

   /// Returns the copyright notice eventually defined in your project data.
   var copyrightNotice : String {
       return readFromInfoPlist(withKey: "NSHumanReadableCopyright") ?? "(unknown copyright notice)"
   }

   /// Returns the official bundle identifier defined in your project data.
   var bundleIdentifier : String {
       return readFromInfoPlist(withKey: "CFBundleIdentifier") ?? "(unknown bundle identifier)"
   }

   var developer : String { return "my awesome name" }

   // MARK: - Private stuff

   // lets hold a reference to the Info.plist of the app as Dictionary
   private let infoPlistDictionary = Bundle.main.infoDictionary

   /// Retrieves and returns associated values (of Type String) from info.Plist of the app.
   private func readFromInfoPlist(withKey key: String) -> String? {
    return infoPlistDictionary?[key] as? String
   }
}

Nutzung:

print("Name of the app: \(AppInfo().appName)")
LukeSideWalker
  • 7,399
  • 2
  • 37
  • 45
  • When in Swift a value is not available nil is used. IMO you should return nil instead of custom placeholder strings. – Luca Angeletti Feb 23 '20 at 15:05
  • 1
    Thats why it is a wrapper: To always get something back. The nil-situation is not really "destroyed",it is still there, but already pre-handled. Otherwise you would have to handle the "nil"-situation in another place in your app. – LukeSideWalker Feb 25 '20 at 20:39
  • 1
    thanks bud. also, you last curly brace is outside the code block. :) – Mark Perkins Apr 19 '20 at 22:39
  • 2
    app name can be also `CFBundleDisplayName` – gondo Apr 22 '20 at 15:17
18

For the final release of Xcode 6 use

NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String

The "?" character after infoDictionary is important here

JulianM
  • 2,540
  • 18
  • 13
16

Here is simple way to get Build and version.

For Swift 4.X

 if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
     print(version)
   }

 if let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
     print(build)
   }

For Objective C

NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];

NSString * currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];

Let me know if any issue. This is working for me.

Ashu
  • 3,373
  • 38
  • 34
14

Swifty way for AppName, AppVersion and BuildNumber...

if let dict = NSBundle.mainBundle().infoDictionary {
   if let version = dict["CFBundleShortVersionString"] as? String,
       let bundleVersion = dict["CFBundleVersion"] as? String,
       let appName = dict["CFBundleName"] as? String {
           return "You're using \(appName) v\(version) (Build \(bundleVersion))."
   }
}
Chris
  • 3,057
  • 5
  • 37
  • 63
  • Why would you need to unwrap the values? To my knowledge, it's impossible for any of those values to be nil – Michael Jun 08 '16 at 13:48
  • @Michael some people ALWAYS unwrap optional values. Some people say you're right. – Dan Rosenstark Dec 07 '16 at 19:28
  • 3
    `Bundle.main` had an empty `infoDictionary` for me; maybe because I'm doing it from within a framework, not an executable or app? `Bundle(for: MyClass.self)` contains the expected values. – Raphael May 17 '17 at 14:46
8

In swift, I would make it as extension for UIApplication, like this:

extension UIApplication {

    func applicationVersion() -> String {

        return NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") as! String
    }

    func applicationBuild() -> String {

        return NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey as String) as! String
    }

    func versionBuild() -> String {

        let version = self.applicationVersion()
        let build = self.applicationBuild()

        return "v\(version)(\(build))"
    }
}

Then you can just use following to get everything you need:

let version = UIApplication.sharedApplication.applicationVersion() // 1
let build = UIApplication.sharedApplication.applicationBuild() // 80
let both = UIApplication.sharedApplication.versionBuild() // 1(80)
Jiri Trecak
  • 5,092
  • 26
  • 37
7

//Returns app's version number

public static var appVersion: String? {
    return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
}

//Return app's build number

public static var appBuild: String? {
    return Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String
}
Pratyush Pratik
  • 683
  • 7
  • 14
2

Another option is to define in the AppDelegate the variables:

var applicationVersion:String {
    return NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") as! String
}
var applicationBuild:String  {
    return NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey as String) as! String
}
var versionBuild:String  {
    let version = self.applicationVersion
    let build = self.applicationBuild
    return "version:\(version) build:(\(build))"
}

that can be referenced as variables in the AppDelegate

Oprisk
  • 41
  • 3
2

This code works for Swift 3, Xcode 8:

let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"
Crashalot
  • 33,605
  • 61
  • 269
  • 439
2

For Swift 3,Replace NSBundle with Bundle and mainBundle is replaced simply by main.

let AppVersion = Bundle.main.infoDictionary!["CFBundleVersion"] as! String
1

[Update: Xcode 6.3.1] I tried all of the above and none of these work in Xcode 6.3.1 but I found that this does:

(NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String)!
SunburstEnzo
  • 173
  • 11
0

Swift 3 :

let textVersion
 = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
0

SWIFT 3 Version

if let infoPath = Bundle.main.path(forResource: "Info.plist", ofType: nil),
        let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath),
        let infoDate = infoAttr[.creationDate] as? Date
{
    return infoDate
}
return Date()
Ryan X
  • 575
  • 7
  • 5
0

Get version from Framework's bundle

To have result for framework you can use

[Access to Framework bundle]

//inside framework
let version = bundle.infoDictionary?["CFBundleShortVersionString"] as? String
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
0

Swift 100% working tested

You can get that easily by using single variable and make it public. You can use it everywhere you want.

(I am getting here User Agent for API header)

public let userAgent: String = {
    if let info = Bundle.main.infoDictionary {
        let executable = info[kCFBundleExecutableKey as String] as? String ?? "Unknown"
        let bundle = info[kCFBundleIdentifierKey as String] as? String ?? "Unknown"
        let appVersion = info["CFBundleShortVersionString"] as? String ?? "Unknown"
        let appBuild = info[kCFBundleVersionKey as String] as? String ?? "Unknown"

        let osNameVersion: String = {
            let version = ProcessInfo.processInfo.operatingSystemVersion
            let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"

            let osName: String = {
                #if os(iOS)
                    return "iOS"
                #elseif os(watchOS)
                    return "watchOS"
                #elseif os(tvOS)
                    return "tvOS"
                #elseif os(macOS)
                    return "OS X"
                #elseif os(Linux)
                    return "Linux"
                #else
                    return "Unknown"
                #endif
            }()

            return "\(osName) \(versionString)"
        }()


        return "\(executable)/\(appVersion) (\(bundle); build:\(appBuild); \(osNameVersion)) "
    }

    return "MyApp"
}()

Output:

"User-Agent": "MyApp/4.6.0 (com.app.myapp; build:4.6.0.0; iOS 15.2.0) "
Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52