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.
![](../../users/profiles/5620447.webp)
- 1,009
- 3
- 11
- 27
![](../../users/profiles/3792194.webp)
- 1,053
- 1
- 7
- 7
-
2Show 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 Answers
What was wrong with the Swift syntax? This seems to work:
if let text = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
print(text)
}
-
2Why was this downvoted? I guess it might be more natural as a `let` but it otherwise looks correct. – Tommy Jul 01 '14 at 01:45
-
Ah, I forgot the "as String" so the variable would accept it as a string. Thank you. – Ken-UbiDex Jul 01 '14 at 01:53
-
3
-
2This worked for me in Xcode 6 beta 5: `let text = NSBundle.mainBundle().infoDictionary["CFBundleVersion"]! as String` – E. Barnes Aug 05 '14 at 17:13
-
@Dean It looks like they changed infoDictionary to return an optional. I've edited the answer – Connor Oct 26 '14 at 15:16
-
Is it safe to force unwrap the returned value? Could it ever be nil? – Maduranga E Jun 05 '19 at 02:18
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.
![](../../users/profiles/2450755.webp)
- 8,880
- 3
- 34
- 49
![](../../users/profiles/8047.webp)
- 64,546
- 54
- 267
- 405
-
1You 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
For the final release of Xcode 6 use
NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String
The "?" character after infoDictionary is important here
![](../../users/profiles/1406389.webp)
- 2,440
- 16
- 13
-
1Damn. I sure do love this whole "optional?, unwrap!" system, it is crystal clear and so easy to read! – Jeroen Bouma Oct 09 '15 at 09:12
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.
![](../../users/profiles/1400319.webp)
- 2,867
- 29
- 30
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))."
}
}
![](../../users/profiles/1174532.webp)
- 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
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)")
![](../../users/profiles/3143890.webp)
- 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
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)
![](../../users/profiles/2753625.webp)
- 4,752
- 23
- 36
//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
}
![](../../users/profiles/5857254.webp)
- 633
- 7
- 14
This code works for Swift 3, Xcode 8:
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"
![](../../users/profiles/144088.webp)
- 31,452
- 56
- 235
- 393
For Swift 3,Replace NSBundle with Bundle and mainBundle is replaced simply by main.
let AppVersion = Bundle.main.infoDictionary!["CFBundleVersion"] as! String
![](../../users/profiles/5848526.webp)
- 123
- 7
[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)!
![](../../users/profiles/1241153.webp)
- 163
- 9
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
![](../../users/profiles/3620768.webp)
- 31
- 3
Swift 3 :
let textVersion
= Bundle.main.infoDictionary?["CFBundleVersion"] as? String
![](../../users/profiles/4099593.webp)
- 41,091
- 27
- 112
- 129
![](../../users/profiles/6527807.webp)
- 1
- 1
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()
![](../../users/profiles/2731303.webp)
- 515
- 7
- 5
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
![](../../users/profiles/4770877.webp)
- 13,571
- 5
- 105
- 98