Is there a way to read the app's bundled plist file, I am wanting to pull the value for Bundle version.
See Getting the Bundle’s Info.plist Data.
[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
should get you the bundle version.
In Swift you can use:
let bundleVersion = Bundle.main.object(forInfoDictionaryKeykCFBundleVersionKey as String) as! String
or:
let bundleVersion = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as! String
If you want the short bundle versions string, you can use:
let shortBundleVersion = Bundle.main.object(forInfoDictionaryKey:"CFBundleShortVersionString") as! String
#define APP_VERSION [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString*)kCFBundleVersionKey]
Related
I need to add some "default" file during the installation or the first launch of my app in the "Document" directory to let user access to "demo" files or presets. Is there a way to do it properly ?
It's mostly for iOS Apps.
It's very straightforward to get to the app's Documents directory:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
Using the above function, you would be able to easily refer to the Documents folder to install files (or a folder containing your demo files) into the Documents directory and then read them out of there.
To copy a default file from your iOS application bundle, you could do something like:
let sourceURL = Bundle.main.url(forResource: "defaultfile", withExtension: ".png") // whatever kind of file it is
let destinationFolderURL = self.getDocumentsDirectory()
let fullDestURL = destinationFolderURL.appendingPathComponent("defaultfile.png")
let fileManager = FileManager.default
do{
try fileManager.copyItem(at: sourceURL, to: destURL)
} catch {
print(error)
}
Hopefully I didn't make any typos in the above example. :-)
Obj-C solution for anyone interested
If you want user to just read/view those files, all you need to do is to drag&drop them to your project files in Xcode, and then you can access them programmatically like this:
[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"relative/path/to/your/files"]
Alternatively, if you want your users to modify/re-save those files, you'll need to copy-paste them from your NSBundle to Documents directory on the first launch.
- (void)copyDemoFilesToDocumentsFolder {
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *demoFilesPath = [DOCUMENTS_DIR stringByAppendingPathComponent:#"path/to/your/demo/files"];
if (![fileManager fileExistsAtPath:demoFilesPath]) {
NSString *sourceFolderPath = [[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:#"path/to/your/demo/files"];
[fileManager copyItemAtPath:sourceFolderPath
toPath:demoFilesPath
error:&error];
}
}
I want to read the bundle version info from Info.plist into my code, preferably as a string. How can I do this?
You can read your Info.plist as a dictionary with
[[NSBundle mainBundle] infoDictionary]
And you can easily get the version at the CFBundleVersion key that way.
Finally, you can get the version with
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
NSString* version = [infoDict objectForKey:#"CFBundleVersion"];
for Swift users:
if let version = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") {
print("version is : \(version)")
}
for Swift3 users:
if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") {
print("version is : \(version)")
}
I know that some time has passed since the quest and the answer.
Since iOS8 the accepted answer might not work.
This is the new way to do it now:
NSString *version = (__bridge id)CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), kCFBundleVersionKey);
Now in iOS 8 both fields are necessary. Earlier it works without the CFBundleShortVersionString. But now it is a required plist field to submit any app in app store. And kCFBundleVersionKey is compared for uploading every new build, which must be in incremental order. Specially for TestFlight builds. I do it this way,
NSString * version = nil;
version = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleShortVersionString"];
if (!version) {
version = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
}
Swift 3:
let appBuildNumber = Bundle.main.infoDictionary!["CFBundleVersion"] as! String
let appVersion = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
I am trying to access google maps' forward geocoding service from my iphone app.
When i try to make an NSURL from a string with a pipe in it I just get a nil pointer.
NSURL *searchURL = [NSURL URLWithString:#"http://maps.google.com/maps/api/geocode/json?address=6th+and+pine&bounds=37.331689,-122.030731|37.331689,-122.030731&sensor=false"];
I dont see any other way in the google api to send bounds coordinates with out a pipe.
Any ideas about how I can do this?
Have you tried replacing the pipe with %7C (the URL encoded value for the char |)?
As stringByAddingPercentEscapesUsingEncoding is deprecated, you should use stringByAddingPercentEncodingWithAllowedCharacters.
Swift answer:
let rawUrlStr = "http://maps.google.com/maps/api/geocode/json?address=6th+and+pine&bounds=37.331689,-122.030731|37.331689,-122.030731&sensor=false";
let urlEncoded = rawUrlStr.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
let url = NSURL(string: urlEncoded)
Edit: Swift 3 answer:
let rawUrlStr = "http://maps.google.com/maps/api/geocode/json?address=6th+and+pine&bounds=37.331689,-122.030731|37.331689,-122.030731&sensor=false";
if let urlEncoded = rawUrlStr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
let url = NSURL(string: urlEncoded)
}
If you want to be safe for whatever weird characters you will put in the future, use stringByAddingPercentEscapesUsingEncoding method to make the string "URL-Friendly"...
NSString *rawUrlStr = #"http://maps.google.com/maps/api/geocode/json?address=6th+and+pine&bounds=37.331689,-122.030731|37.331689,-122.030731&sensor=false";
NSString *urlStr = [rawUrlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *searchURL = [NSURL URLWithString:urlStr];
I'm having some troubles with the bundle and somehow I can't save images from bundle to docs directory any more. Now I've got this error before building:
The document NSBundle.h could no be
saved
It apparently compiles well.
This is the kind of code I'm using:
//Get every name from plist array and append it to the full path
for( NSString *aName in namesPackage ) {
bundlePath = [[NSBundle mainBundle] pathForResource:aName ofType:#"png"];
if([fileManager fileExistsAtPath:bundlePath])NSLog(#"it exists in bundle: %#",bundlePath);
imagePath = [NSString stringWithFormat:#"%#/%#/%#",DOCUMENTS_FOLDER,package,aName];
[fileManager copyItemAtPath:bundlePath toPath:imagePath error:&anError];
if(anError) NSLog([anError description]);
}
Thanks for your help in advance.
You should use NSString's file extensions category:
-stringByAppendingPathComponent:
-stringByAppendingPathExtension:
That will take care of any potential issues with trailing slashes, etc.
Also, you should never pass any unknown string as the format argument to any variable length function, as they could contain format specifiers. Use NSLog(#"%#", anError) instead.
I'm writing an iPhone app. It's already been published, but I would like to add a feature where its version number is displayed.
I'd rather not have to do this manually with each version I release...
Is there a way in objective-C to find out what the version is of my app?
As I describe here, I use a script to rewrite a header file with my current Subversion revision number. That revision number is stored in the kRevisionNumber constant. I can then access the version and revision number using something similar to the following:
[NSString stringWithFormat:#"Version %# (%#)", [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"], kRevisionNumber]
which will create a string of the format "Version 1.0 (51)".
Building on Brad Larson's answer, if you have major and minor version info stored in the info plist (as I did on a particular project), this worked well for me:
- (NSString *)appNameAndVersionNumberDisplayString {
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appDisplayName = [infoDictionary objectForKey:#"CFBundleDisplayName"];
NSString *majorVersion = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *minorVersion = [infoDictionary objectForKey:#"CFBundleVersion"];
return [NSString stringWithFormat:#"%#, Version %# (%#)",
appDisplayName, majorVersion, minorVersion];
}
Now revving a minor version manually can be a pain, and so using a source repository revision number trick is ideal. If you've not tied that in (as I hadn't), the above snippet can be useful. It also pulls out the app's display name.
Swift version for both separately:
Swift 3
let versionNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String
Swift 2
let versionNumber = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") as! String
let buildNumber = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleVersion") as! String
Its included in this repo, check it out:
https://github.com/goktugyil/EZSwiftExtensions
This is what I did in my application
NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
Hopefully this simple answer will help somebody...
You can specify the CFBundleShortVersionString string in your plist.info and read that programmatically using the provided API.
There are two things - build version and app version.
To get App version:
NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
To get Build version:
NSString *buildVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
A succinct way to obtain a version string in X.Y.Z format is:
[NSBundle mainBundle].infoDictionary[#"CFBundleVersion"]
Or, for just X.Y:
[NSBundle mainBundle].infoDictionary[#"CFBundleShortVersionString"]
Both of these snippets returns strings that you would assign to your label object's text property, e.g.
myLabel.text = [NSBundle mainBundle].infoDictionary[#"CFBundleVersion"];
// Syncs with App Store and Xcode Project Settings Input
NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
You can try using dictionary as:-
NSDictionary *infoDictionary = [[NSBundle mainBundle]infoDictionary];
NSString *buildVersion = infoDictionary[(NSString*)kCFBundleVersionKey];
NSString *bundleName = infoDictionary[(NSString *)kCFBundleNameKey]
Swift 5:
There are two things - App version and build version
To get App version:
if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
// present appVersion
}
To get Build version:
if let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
// present buildVersion
}
Thanks #Brad Larson♦ a lot
Read the info.plist file of your app and get the value for key CFBundleShortVersionString. Reading info.plist will give you an NSDictionary object
You can use the infoDictionary which gets the version details from info.plist of you app. This code works for swift 3. Just call this method and display the version in any preferred UI element.
Swift-3
func getVersion() -> String {
let dictionary = Bundle.main.infoDictionary!
let version = dictionary["CFBundleShortVersionString"] as! String
let build = dictionary["CFBundleVersion"] as! String
return "v\(version).\(build)"
}
If you need a combination of both version and build num, here's a short way using Swift 3:
let appVersion = Bundle.main.infoDictionary!["CFBundleShortVersionString"]!
let buildNum = Bundle.main.infoDictionary!["CFBundleVersion"]!
let versionInfo = "\(appVersion) (build \(buildNum))"
// versionInfo is now something like "2.3.0 (build 17)"
Add an as! String to the end of either the appVersion or buildNum line to get only that portion as a String object. No need for that though if you're looking for the full versionInfo.
I hope this helps!
func getAppVersion() -> String {
let dictionary = Bundle.main.infoDictionary!
let versionValue = dictionary["CFBundleShortVersionString"] ?? "0"
let buildValue = dictionary["CFBundleVersion"] ?? "0"
return "\(versionValue) (build \(buildValue))"
}
Based on #rajat chauhan answer without forced cast to String.
This is a good thing to handle with a revision control system. That way when you get a bug report from a user, you can check out that revision of code and (hopefully) reproduce the bug running the exact same code as the user.
The idea is that every time you do a build, you will run a script that gets the current revision number of your code and updates a file within your project (usually with some form of token replacement). You can then write an error handling routine that always includes the revision number in the error output, or you can display it on an "About" page.
You can try this method:
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];