98

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 Build.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.

Shruti Thombre
  • 1,009
  • 3
  • 11
  • 27
Ken-UbiDex
  • 1,053
  • 1
  • 7
  • 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

15 Answers15

173

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

if let text = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
    print(text)
}
Marmoy
  • 7,684
  • 7
  • 41
  • 72
Connor
  • 60,945
  • 26
  • 140
  • 138
124

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.

Andrea Mugnaini
  • 8,880
  • 3
  • 34
  • 49
Dan Rosenstark
  • 64,546
  • 54
  • 267
  • 405
  • 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
18

For the final release of Xcode 6 use

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

The "?" character after infoDictionary is important here

JulianM
  • 2,440
  • 16
  • 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
  • 2,867
  • 29
  • 30
13

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
  • 2,927
  • 5
  • 33
  • 62
  • 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
  • 2
    `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
12

Swift 5.0

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

struct AppInfo {

var appName : String {
    return readFromInfoPlist(withKey: "CFBundleName") ?? "(unknown app name)"
}

var version : String {
    return readFromInfoPlist(withKey: "CFBundleShortVersionString") ?? "(unknown app version)"
}

var build : String {
    return readFromInfoPlist(withKey: "CFBundleVersion") ?? "(unknown build number)"
}

var minimumOSVersion : String {
    return readFromInfoPlist(withKey: "MinimumOSVersion") ?? "(unknown minimum OSVersion)"
}

var copyrightNotice : String {
    return readFromInfoPlist(withKey: "NSHumanReadableCopyright") ?? "(unknown copyright notice)"
}

var bundleIdentifier : String {
    return readFromInfoPlist(withKey: "CFBundleIdentifier") ?? "(unknown bundle identifier)"
}

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

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

You can use it like so:

print("The apps name = \(AppInfo.appname)")
LukeSideWalker
  • 5,686
  • 2
  • 25
  • 38
  • 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
  • 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
  • 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
7

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
  • 4,752
  • 23
  • 36
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
  • 633
  • 7
  • 14
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
  • 31,452
  • 56
  • 235
  • 393
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
  • 163
  • 9
1

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
  • 31
  • 3
0

Swift 3 :

let textVersion
 = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
Bhargav Rao
  • 41,091
  • 27
  • 112
  • 129
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
  • 515
  • 7
  • 5
0

To have result for framework you can use

let version = Bundle(for: type(of: self)).infoDictionary?["CFBundleShortVersionString"] as? String

or in tests

let version = Bundle(for: <SomeClass>.self).infoDictionary?["CFBundleShortVersionString"] as? String
yoAlex5
  • 13,571
  • 5
  • 105
  • 98