I have couple of applications alive in Apple store and we have just released updated version of these applications with incremented version numbers. I found that all resources are getting updated correctly(updated splash screen, background image etc) but newly added features are not getting updated. For example, I have included a feature so that iPhone app takes new contents from my website. It doesn't happen when I update the application from Appstore updates list.
...but the other strange thing is if I delete the application from my iPhone and download it again from Apple store then everything works fine!! I am not able to understand what has been going on. Anyone could please help me to debug this?
From this I got following code and added in my AppDelegate. For me it always print Version (null). I could see version number correctly set in my Application-info.plist file though!
#if DDEBUG // debugging/testing
NSString *versionString = [NSString stringWithFormat:#"v%#",[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]];
#else
NSString *versionString = [NSString stringWithFormat:#"Version %#",[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleShortVersionString"]];
#endif // DDEBUG
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:versionString forKey:#"version"];
printf("Version: = %s\n", [versionString cStringUsingEncoding:NSMacOSRomanStringEncoding]);
[defaults synchronize]; // force immediate saving of defaults.
Following code works though! I mean it prints the correct version available in application-info.plist file! Got it from here
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"Version: %#", version);
[defaults setObject:version forKey:#"version_preference"];
[defaults synchronize];
I can confirm if this fixes the issue after resubmitting the application.
Thanks.
This worked:
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"Version: %#", version);
[defaults setObject:version forKey:#"version_preference"];
[defaults synchronize];
Related
Hi everybody I have an issue in my app. I need to determine if my app has has been updated to some point. I found out with this method how I can get the current version
NSString *first = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
NSString *second = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
If the app is updated from itunes, Who var is changed to determine my app has been updated because I prove by modification from xcode in the Targets>Summary>Version to prove .The first var changes but the second does not change.
What I have to select the first or the second, and how I can prove this?
I'm not sure if this is what you are looking for but this code can tell you if your app has been updated by storing version information in NSUserDefaults.
- (BOOL)wasUpdated {
// access NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// get previous version number from defaults
NSString *previousVersion = [defaults stringForKey:#"previousVersion"];
// get current version number from info plist
NSString *currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
// check against previousVersion being nil
if (!previousVersion) {
// set current version to previous version
[defaults setObject:currentVersion forKey:#"previousVersion"];
// previousVersion didn't exist and can't be checked, return NO
return NO;
}
// return YES if the versions are not the same
if (NSOrderedSame != [previousVersion compare:currentVersion]) return YES;
// return NO if they are the same
return NO;
}
Hopefully that's what you needed. Tell me if I didn't understand what you meant.
I have some settings in a plist, but when I kill my app I lose all the data stored there.
This is the code that I'm using:
.h
#property (retain, nonatomic) NSString *plistFilePath;
-(IBAction)setHomepage:(id)sender;
.m
#syntehzise plistFilePath;
-(IBAction)setHomepage:(id)sender{
plistFilePath = [NSString stringWithString:[[NSBundle mainBundle] pathForResource:#"settings" ofType:#"plist"]];
NSMutableDictionary *data= [[NSMutableDictionary alloc] initWithContentsOfFile:plistFilePath];
[data setObject:#"http://www.google.com" forKey:#"Homepage"];
[data writeToFile:plistFilePath atomically:YES];
[data release];
}
Am I doing something wrong? Should I use a different class or differents methods? Please help me because I don't know why I store well the information but then when I kill the app I lose it.
As already mentioned the bundle is read only.
Try to avoid setting 'settings' in an a copied plist, as plists are just one more thing to managed. Instead, why not use NSUserDefaults and import your defaults from a defaults plist. For example, add a new plist to your project, and add this to your delegate:
// Get the shared defaults object
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// Register the defaults each time the app loads
NSString *defaultsFile = [[NSBundle mainBundle] pathForResource:#"Defaults" ofType:#"plist"];
NSDictionary *defaultsDict = [NSDictionary dictionaryWithContentsOfFile:defaultsFile];
[defaults registerDefaults:defaultsDict];
Now you can save data like this:
// Store the data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"http://mattmelton.co.uk" forKey:#"HomePage"];
[defaults synchronize];
And retrieve it like this:
// Retrieve data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *homePage = [defaults objectForKey:#"HomePage"];
And you don't have to worry about external files. Naturally your defaults plist can be platform, user or device specific!
Hope this helps!
The application bundle is readonly. If you want to distribute a file and then update it, move it from the bundle to the documents folder the first time your application runs.
Just a quick question. I am bit unsure about this.
When I add a Settings.plist to my Objective C iPhone project and read the settings from it. Is it possible to update settings in this file? Or is this file only readable and should I create a copy at another location like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
and check for its existence at launch?
You can't edit the files you included in your app through Xcode, so you could copy it to the user's document folder.
However, as you're interested in a settings plist file, I advise you to save the settings using NSUserDefaults, which automatically saves a .plist file: In the app's delegate on applicationDidFinishLoading write
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults boolForKey:#"firstRunComplete"]) {
[defaults setObject:optionOne forKey:#"optionOne"]; //replace
[defaults setObject:optionTwo forKey:#"optionTwo"]; //replace
[defaults setBool:YES forKey:#"firstRunComplete"];
[defaults synchronize];
}
And when you want to change one of the options
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:optionOne forKey:#"optionOne"]; //replace
[defaults setObject:optionTwo forKey:#"optionTwo"]; //replace
[defaults synchronize];
Alternatively you can use this method for editing plist files:
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict writeToFile:filePath atomically: YES];
I see in many apps that you only need to login to an app once and then the next time you open the app, you don't need to input the username and password again. How can I do this with the help of SFHFKeychainUtils?
You pretty much answered your question already. You can store credentials in the application's Keychain using the SFHFKeychainUtils wrapper. When the application loads, it checks to see if there is a password. If not, prompt the user to login and store the username & password accordingly.
// Application Loads...
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSString *username = [standardDefaults stringForKey:#"kApplicationUserNameKey"];
if (username) {
NSError *error = nil;
NSString *password = [SFHFKeychainUtils getPasswordForUsername:username andServiceName:#"com.company.app" error:&error];
// Check password...
} else {
// No username. Prompt the user to enter username & password and store it
username = #"userEnteredUsername";
NSString *password = #"userEnteredPassword";
[standardDefaults setString:username forKey:#"kApplicationUserName"];
NSError *error = nil;
BOOL storeResult = [SFHFKeychainUtils storeUsername:username andPassword:password forServiceName:#"com.company.app" updateExisting:YES error:&error];
}
This is obviously incomplete and not organized in the appropriate fashion but you should be able to understand the basic flow.
You can use NSUserDefaults for that purpose.
[[NSUserDefaults standardUserDefaults] setObject:username forKey:#"username"];
[[NSUserDefaults standardUserDefaults] setObject:password forKey:#"password"];
[[NSUserDefaults standardUserDefaults] synchronize];
Next time user opens your app, you can simply get this info:
NSString *username = [[NSUserDefaults standardUserDefaults] stringForKey:#"username"];
NSString *password = [[NSUserDefaults standardUserDefaults] stringForKey:#"password"];
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I display the application version revision in my application's settings bundle?
I have an iPhone application that displays the current version as a Settings constant (just like Skype does).
When I released the first version of the application, I use this code to set the app Settings:
- (void)registerDefaultsFromSettingsBundle {
NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"bundle"];
if(!settingsBundle) {
NSLog(#"Could not find Settings.bundle");
return;
}
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:#"Root.plist"]];
NSArray *preferences = [settings objectForKey:#"PreferenceSpecifiers"];
NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
for(NSDictionary *prefSpecification in preferences) {
NSString *key = [prefSpecification objectForKey:#"Key"];
if(key) {
[defaultsToRegister setObject:[prefSpecification objectForKey:#"DefaultValue"] forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
[defaultsToRegister release];
}
And this worked fine and dandy.
The problem I face now is that if you update the application, these defaults (Settings) are nor re-written, so the application version is not updated.
How can I force that an specific Settings is set on every install?
Thanks
Gonso
You can use the following 'Run Script' Build Phase:
CFBundleShortVersionString=`/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" ${SRCROOT}/YourApp/YourApp-Info.plist`
CFBundleVersion=`/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" ${SRCROOT}/YourApp/YourApp-Info.plist`
/usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:3:DefaultValue '${CFBundleShortVersionString} (${CFBundleVersion})'" ${SRCROOT}/YourApp/Settings.bundle/Root.plist
All you need to do, is to replace YourApp with your app's name and set the appropriate keypath.
In my case, I have 4 items in the PreferenceSpecifiers array, and I need to set the value for the last item from the array and that's why I used ':PreferenceSpecifiers:3:DefaultValue'
I have this code in my application delegate's -applicationDidFinishLaunching:
#if DDEBUG // debugging/testing
NSString *versionString = [NSString stringWithFormat:#"v%#",[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]];
#else
NSString *versionString = [NSString stringWithFormat:#"Version %#",[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleShortVersionString"]];
#endif // DDEBUG
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:versionString forKey:#"version"];
printf("Version: = %s\n", [versionString cStringUsingEncoding:NSMacOSRomanStringEncoding]);
[defaults synchronize]; // force immediate saving of defaults.
But app has to be run before Settings 'version' updates to reflect the change.
Why wouldn't you set the version number from the mainBundle?
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]];
This way you don't have to update the settings file for every version. If you want to compare existing versus new install version. You could write out the version number to a file on launch and compare the directory version with the launch version.