I'm writing an iOS SDK using Objective-C programming language. I would like to know if there is a field in Xcode where i can set version number for SDK
Is there a way in objective-C to set version and build number the way we do it for iOS apps (EX: Version: 2.5.1 Build: 2.5.1.12) ?
Also need a way to detect this version number so i can expose an API something like
- (NSString *)getSDKVersion {
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *majorVersion = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *minorVersion = [infoDictionary objectForKey:#"CFBundleVersion"];
return [NSString stringWithFormat:#"SDK Version %# (%#)", majorVersion, minorVersion];
}
-(NSString*)getSDKBuildVersion;
Which returns the SDK version and build number.
Using:
Xcode - 7.0 (Beta 3 version)
Thanks in advance.
You can set version and build number clicking in the Project(left side) -> General tab(right side) -> Identity section. You will find the fields: Bundle Identifier, Version and Build.
For get the values programmatically:
NSDictionary *infoDictionary = [[NSBundle mainBundle]infoDictionary];
NSString *version = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *build = [infoDictionary objectForKey:kCFBundleVersionKey];
Related
This is likely not limited to iOS Universal Frameworks but all xxx.framework files. However I can't seem to find documentation on how to get the current version and build of a framework within the client application. Within an app you'd use something like:
NSString *name = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleDisplayName"];
NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
That would give you the current information stored in the Info.plist for the app. But how to we find that information for a framework. And in my case, specifically an embedded framework.
Here's a solution that does work with Universal Frameworks. Just replace SomeFrameworkClass with a class from the desired framework.
if let sdkVersion = Bundle(for: SomeFrameworkClass.self).infoDictionary?["CFBundleShortVersionString"] {
// sdkVersion is available here
}
I have found that Apple's new Cocoa Touch frameworks supported in Xcode 6, offer an easy answer to this problem. In the default header file created for you, something like Framework.h, you'll see two constants declared for you. These are defined later presumably at runtime by internal framework logic. But I have confirmed they're pulled from the plist for the framework.
//! Project version number for LocalSearch.
FOUNDATION_EXPORT double FrameworkVersionNumber;
//! Project version string for LocalSearch.
FOUNDATION_EXPORT const unsigned char FrameworkVersionString[];
Let's say Foo is a class from the given framework, you can use something like :
NSDictionary *infoDictionary = [[NSBundle bundleForClass: [Foo class]] infoDictionary];
NSString *name = [infoDictionary valueForKey:(__bridge NSString*)kCFBundleNameKey];
NSString *version = [infoDictionary valueForKey:(__bridge NSString*)kCFBundleVersionKey];
NSLog(#"%# version %#", name, version);
In Swift :
// `Foo` is a type defined in the framework
if let infos = Bundle(for: Foo.self).infoDictionary,
let name = infos[kCFBundleNameKey as String],
let version = infos[kCFBundleVersionKey as String] {
print("Using \(name) version \(version)")
if let shortVersion = infos["CFBundleShortVersionString"] as? String {
print("Short version : " + shortVersion)
}
}
Note : For some reason, "CFBundleShortVersionString" is not defined in a constant, cf Is there a constant defined for CFBundleShortVersionString in iOS/MacOS framework
This is for who may want to have a function on your framework that returns or print on the console it's version with build number. Just make sure you are using the class you are sharing on your Framework.h when declaring the *infoDictionary. In my example I'm using a class named cloud
+(NSString *)frameWorkVersion {
NSDictionary *infoDictionary = [[NSBundle bundleForClass: [cloud class]] infoDictionary];
NSString *version = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *build = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey];
NSString *fVersion = [NSString stringWithFormat:#"%#.%#",version,build];
NSLog(#"Framework Version %#",fVersion);
return fVersion; }
I have an app with version 1.0 on app store which uses sqlite database for reading the data.Now I want to update my version to 1.1 with update in database file.While using developer certificate when I install app on device it did not update the database as the database file already exist in documents folder so i have to manually delete the app and install it again.My question is, when any user update the app, will the database also get updated according the current version.Any suggestions are welcome.Thanks
I am sure there are many ways to do this (and many ways better then mine as well), but the way that I handle such problems is as follows:
First I define a constant in the first .h file of the app (the one that will load first) to indicate First Time load and set it to 0:
#define FirstTime 0
Now you have to know that I have the intention to save the value of this constant in the Documents folder for future references, therefore I use a Shared Data Instance. In the viewDidLoad I do the following test:
//if first time run of this version
if( [MyDataModel sharedInstance].count < (FirstTime + 1) )
{
//do what you need to do as the first time load for this version
[MyDataModel sharedInstance].count++
//save the count value to disk so on next run you are not first time
//this means count = 1
}
Now the trick is on your new app version (say 1.1). I change the FirstTime to 2:
#define FirstTime 2
Since the saved First Time value on disc is 1 this means you will be caught by the if statement above, therefore inside it you can do anything you want like delete the old tables and recreate them again with the new formation.
Again not that brilliant, but solves the case!
This approach relies on NSUserDefaults. The idea is to get the previous app version number(if exists) from NSUserDefaults and compare it with the current version.
The code performs db upgrade if the previous app version < than current version or if the previous version is nil. It means that this approach can be used even though the app was already published on the AppStore. It will upgrade database to the new version during the app update.
This is a plist file:
There is an array which is composed of the version number and a set of sql queries for the corresponding upgrade version.
Suppose that a previous version is 1.2 and the actual version is 1.4 the code perform the upgrade only from the version 1.2 to 1.4. If the previous version is 1.3 and the current 1.4 the code performs upgrade only from 1.3 to 1.4.
If the previous version is nil the code performs upgrade to 1.1 then to 1.2 then to 1.3 and finally to 1.4.
NSString * const VERSION_KEY = #"version";
-(void)upgradeDatabaseIfRequired{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *previousVersion=[defaults objectForKey:VERSION_KEY];
NSString *currentVersion=[self versionNumberString];
if (previousVersion==nil || [previousVersion compare: currentVersion options: NSNumericSearch] == NSOrderedAscending) {
// previous < current
//read upgrade sqls from file
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"UpgradeDatabase" ofType:#"plist"];
NSArray *plist = [NSArray arrayWithContentsOfFile:plistPath];
if (previousVersion==nil) {//perform all upgrades
for (NSDictionary *dictionary in plist) {
NSString *version=[dictionary objectForKey:#"version"];
NSLog(#"Upgrading to v. %#", version);
NSArray *sqlQueries=[dictionary objectForKey:#"sql"];
while (![DB executeMultipleSql:sqlQueries]) {
NSLog(#"Failed to upgrade database to v. %#, Retrying...", version);
};
}
}else{
for (NSDictionary *dictionary in plist) {
NSString *version=[dictionary objectForKey:#"version"];
if ([previousVersion compare: version options: NSNumericSearch] == NSOrderedAscending) {
//previous < version
NSLog(#"Upgrading to v. %#", version);
NSArray *sqlQueries=[dictionary objectForKey:#"sql"];
while (![DB executeMultipleSql:sqlQueries]) {
NSLog(#"Failed to upgrade database to v. %#, Retrying...", version);
};
}
}
}
[defaults setObject:currentVersion forKey:VERSION_KEY];
[defaults synchronize];
}
}
- (NSString *)versionNumberString {
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *majorVersion = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
return majorVersion;
}
You can use .plist as well:
- (void)isItTheFirstTimeAfterUpdate {
NSString *versionnum;
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"yourplist.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:path]) {
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"yourplist" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:path error:&error];
}
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
versionnum = #"";
//it can be installed by user (for ex. it is 1.3 but first installed), no plist value is set before
if(([savedStock objectForKey:#"versionnum"]) && (![[savedStock objectForKey:#"versionnum"] isEqualToString:#""])){
versionnum = [savedStock objectForKey:#"versionnum"];
}
//to get the version of installed/updated-current app
NSString *myversion = [NSString stringWithFormat:#"%#",[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"]];
//if no version has been set-first install- or my version is the latest version no need to do sth.
if ([versionnum isEqualToString:myversion] || [versionnum isEqualToString:#""]) {
NSLog(#"Nothing has to be done");
}
else {
[self cleanDB];//i have clean tables and create my new db tables maybe logout the user etc.
[savedStock setObject:[NSString stringWithString:myversion] forKey:#"versionnum"];//setting the new version
[savedStock writeToFile:path atomically:YES];
}
}
And you can call the function in application launch or in your main view controller's view controller.. your choice.
hope it helps.
I have created a custom plist named as test.plist in Supporting Files folder. In that i stored App product name and App version number.
Now, how could i get product name from test.plist for PRODUCT NAME in Build Settings in Target.
I can get values from user defined build settings. But i don't want that.
Note: I need to store product name in test.plist only. And others can access the value from this file.
Thanks in Advance..
you can read the values from the plist in main bundle, put below code in viewDidLoad , method, Please note that all files in main bundle are read only if you want to write any data to plist then you have to copy it to app's document directory
NSString *bundle = [[NSBundle mainBundle] pathForResource:#”test” ofType:#”plist”];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:bundle];
NSString *productName = [dict objectForKey:#"ProductName"];
NSString * appVersion = [dict objectForKey:#"AppVersion"];
Another way is to read app properties
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleDisplayName"];
NSString appVersion = [NSString stringWithFormat:#"Version %# (%#)", [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"], kRevisionNumber];
Hope it helps!
I am trying to get my version number of my app using:
NSString * version = [[NSBundle mainBundle] objectForInfoDictionaryKey: #"CFBundleShortVersionString"];
but it crashes with this error:
[NSString stringWithUTF8String:]: NULL cString
What am I doing wrong?
Check your info.plist to make sure short version (CFBundleShortVersionString) or (Bundle versions string, short) is set.
Your code is fine. But you can also call it this way:
NSString * version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
I am getting my app's version like this:
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"]
And then trying to convert it to a float like this:
[version floatValue]
Now that all works great, but when I have a minor version like "1.1.1" everything behind the second decimal point is truncated.
What is the best way to keep everything behind the second decimal point?
To keep it in sync with how you started...
int major, minor, bug;
NSArray *versionItems = [version componentsSeparatedByString:#"."];
major = [[versionItems objectAtIndex:0] intValue];
minor = [[versionItems objectAtIndex:1] intValue];
bug = [[versionItems objectAtIndex:2] intValue];
But I'd recommend looking at this..
How do I determine the OS version at runtime in OS X or iOS (without using Gestalt)?