Change an App Setting when updating the iPhone application to a new Version - iphone

I want to change the URL that my application connects to, to a new sever. The problem is, the URL value is saved in a settings file. When I update the application to the new version, the old file is read from the device, and overwrites my settings. What I want is to use the new URL the first time the updated version is launched. After that, I am happy to read the URL from the file.
Is there any way I can determine this is the first time after an update when I lauch the application?
Thanks!

As another user, you can get the current version by reading the CFBundleVersion of your app's bundle. The problem with this approach is that a user might not install "version 1" of your app. Instead, I suggest putting something like the following in your app's didFinishLaunching method:
#define kSettings [NSUserDefaults standardUserDefaults];
if(![kSettings objectforKey:#"isFirstRun"]){
// You could check the version here
// and do some initial setting up.
[kSettings setBool:NO forKey:#"isFirstRun"];
}
Then, for each subsequent version, you can add another if block with another flag to check for that version, like so:
if(![kSettings objectForKey:#"isFirstRunForVersionX"]){
// Do some version specific set up here.
[kSettings setBool:NO forKey:#"isFirstRunForVersionX"];
}
I've successfully used this approach in several of my apps.

To determine it it's the first launch after the update, you could retrieve the version number with this piece of code:
NSString* v = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
And compare it to a previous value you have saved.

You can store flag in NSUSerDefault. So You need to check first time if isFirstTime==0 then do your code and make isFirstTime=1; So it only runs first time.

Related

Path of the ios application on device

Well, I would just like to know is it possible to know the path of the app? I used the following code
[NSBundle mainBundle] executablePath];
It retrieved the below value. That is correct.
/var/mobile/Applications/FBE187F1-256D-495D-852B-53AECD4F4C23/Test_Data_Fetch.app
And I would like to know, is it possible to check the existence of other app? The problem is FBE187F1-256D-495D-852B-53AECD4F4C23 this particular directory value changes for every app. I would really like to know if it is possible!!
Your application cannot access anything outside sandbox so you can't search file system directly for a given application.
One possible solution is if application you are interested in handles custom url scheme, then you can check if that url scheme can be opened:
NSURL *url = [NSURL URLWithString:customScheme];
BOOL appProbablyExists = [[UIApplication sharedApplication] canOpenURL:url];
Update: This article describes several possible approaches, but it seems there's no definite way to get list of installed applications using public API
Finally, using the Mac program iExplorer we can look at any App’s data. This is not related to my question, though it is quiet useful!! Was able to achieve my goal!! :]

Build configuration for Lite/Full apps in Xcode

I'm developing a Lite version of an existing iPhone app and I'm trying to figure out the best way to conditionally compile the full and lite versions. Ideally I'd like to use a LITE preprocessor define but is there a good way to set this so I can choose a different item from the scheme menu and just compile whichever version I want?
I don't want to duplicate my "full" target because I'm concerned I'll change a setting in one version and not copy it to the other one. I looked at using an aggregate target but it doesn't run when I press Command-R.
What's the best way to achieve this without duplication?
Sounds like your using xcode4? You could do this by defining a new configuration (beyond the standard ones of Debug & Release).
Then, add your own preprocessor macro for the additional configuration.
Finally, add a new scheme to select the new configuration.
In the end I decided it was best to resolve this without using build configurations. My app uses in-app-purchase to support upgrading to the full, non-lite, version. As such, I want to have every feature compiled and ready to go.
I now manually update the bundle identifier if I want to switch between full and lite versions, and check this when the app runs. I have to change the bundle identifier anyway when I submit either version, so this way I change one file and there's no duplication. Within the app I call the method below to enable/disable lite features.
+ (BOOL)isLiteVersion {
static BOOL haveCheckedLiteStatus = NO;
if (haveCheckedLiteStatus == NO) {
BOOL isLiteApp = [[[NSBundle mainBundle] bundleIdentifier] rangeOfString:#"lite"].location != NSNotFound;
isLite = isLiteApp && [[NSUserDefaults standardUserDefaults] boolForKey:kUpgraded] == NO;
haveCheckedLiteStatus = YES;
}
return isLite;
}

How to migrate NSUserDefaults in new release?

I have an iPhone app that stores some settings using NSUserDefault standardUserDefaults.
When I add new features to the app I need to add new default settings and so I have to migrate/upgrade the NSUserDefaults. For now, I just store the version number and check this when the app is launched. It has quickly become very messy as I have to add lots of if statements. I cannot assume that the user is just upgrading from the previous version but perhaps even a couple of versions before.
I like the way that CoreData seems to handle migrating table changes but I want to provide 2.2.1 SDK compatibility and of course CoreData is not the same thing as NSUserDefaults.
Any suggestions or best practices?
Hmm… I wouldn't "upgrade" the user defaults in this way, but instead query NSUserDefaults as usual, only if the default isn't set (objectForKey will return nil in that case), use a default value (which may then be written back to the user defaults to save time the next time). Since you'll have to do this every time a "new" default (i.e. one that didn't exist in 1.0) is read, I advise doing a wrapper class/file that does this, this way the code is written only once for each "new" default.
Also, while the question/problem is different, this answer works just as well in your case.

Creating a localized iPhone app but allowing the user to change language for the application

I'm working on a localized app and everything is working fine. The problem is I want to allow the user to specifically select the lenguage for the specific app, in the app settings folder. This should users that their phone is set to one language (e.g. french) to set the app to work in English.
I'm currently using NSLocalizedString to get localized string but looking through all variation of the macro I can't find one that will let me specify the language.
Any ideas on how to do it?
There are three issues here:
Strings
Other resources (including NIBs)
System messages
The last is almost certainly not fixable, so we will leave it be. They're going to show up in the device language.
The other two are solvable, but you will need to do more things by hand. For strings, instead of creating a single Localizable.strings and then localizing it, create completely separate tables (English.strings, French.strings, etc.) Then, use NSLocalizedStringFromTable(), passing the language as the table.
For NIBs, there are two approaches. You can put each set of localized NIBs into its own Bundle and then pass that Bundle rather than nil to -initWithNibName:bundle:. Alternately, you can hand-load the NIBs after finding them with [NSBundle -pathForResource:ofType:inDirectory:forLocalization:].
There is a better way to do this. You can force the language like so:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
And undo this setting by:
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"AppleLanguages"];
NB. you will normally have to restart the app for this to take affect.
Consider if you need to call [[NSUserDefaults standardUserDefaults] synchronize];
I agree there is little need to allow the user to specify a language. However the one exception is being able to override the language and set it to the developer's native language. If the user can speak the developer's language (e.g. English for me) then they may wish to use the App in that language, if the translations are incorrect.
I reference this answer: How to force NSLocalizedString to use a specific language (the answer doesn't actually work for me, but following the ideas in the comments did. The undo stuff I worked out.
The trick to use specific language by selecting it from the app is to force the NSLocalizedString to use specific bundle depending on the selected language ,
here is the post i have written for this http://learning-ios.blogspot.com/2011/04/advance-localization-in-ios-apps.html
and here is the code of one sample app https://github.com/object2dot0/Advance-Localization-in-ios-apps
The correct "User experience" is for the user to select their language via the system preference panel; not your app (or your app's settings panel, etc.). There is no way to override this per-app and we wouldn't want any app changing the system wide setting.

String value in Settings.bundle empty after update

For QA purposes I display our app's build version in the application' settings view as a PSTitleValueSpecifier. I set our app's current build number as the DefaultValue and I update it for every new build.
My problem is, whenever I deploy a new build of our application on a dev phone via Xcode, the version value doesn't update but remains with the previous build. The only way to update the version's value is to delete the app from the dev phone and then deploy the new build. Obviously, this approach does not please our QA department since they then loose all of their persisted data.
I have tried, cleaning the project, re-compiling and deploying but I get the same behavior.
Has anyone else experienced this issue? Any idea on how to work around it/fix it?
It is because this value is stored using NSUserDefaults which is stored on the disk and only removed when the app is removed. You can explicitly set it in code the same way you would any other user default. You could just create a field in your Info.plist that you change when you want to send a new build. Read that value from the plist on startup and then write it to your user defaults with:
NSString *value = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"build_version"];
[[NSUserDefaults standardDefaults] setObject:value forKey#"build_version"];
[[NSUserDefaults standardDefaults] synchronize];
Of course, you replace "build_version" with whatever your key name is in your settings file. It's a hack, but it might satisfy your QA people.
For argument sake, it is actually reasonable to expect that you have to completely remove the previous version before seeing the version number update, however I realize not all QA people are reasonable. ;-)