Reputation: 6451
I have some App-Info.plist entries that need to change based on my environment. When I'm doing developmental work, they need to be one set of values, vs QA vs Production.
What would be nice is if I could simply have a script or something that runs based on the Scheme used to do the compilation.
Is this possible?
Upvotes: 8
Views: 5981
Reputation: 785
You can add a User-Defined-Setting in Xcode>Build-Settings, add its values according to all the schemes listed there. And then simply use that as a variable in Info plist file. That should work just fine. This way you can avoid creating duplicate plist files, just for the sake of one or two different properties.
Upvotes: 2
Reputation: 299345
I think msmq's answer is valid, but you should be a little careful about using the main info.plist this way. Doing that suggests that all your versions of info.plist are almost identical, except for a couple of differences. That's a recipe for divergence, and then hard-to-debug issues when you want to add a new URI handler or background mode or any of the other things that might modify info.plist.
Instead, I recommend you take the keys that vary out of the main info.plist. Create another plist (say "Config.plist") to store them. Add a Run Script build phase to copy the correct one over. See the Build Settings Reference for a list of variables you can substitute. An example script might be:
cp ${SOURCE_ROOT}/Resources/Config-${CONFIGURATION}.plist ${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Config.plist
Then you can read the file using something like this (based on Read in the Property List):
NSString *baseURL;
NSString *path = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSDictionary *dict = (NSDictionary *)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListImmutable
format:NULL
errorDescription:&errorDesc];
if (dict != nil) {
baseUrl = dict[@"baseURL"];
} else {
NSAssert(@"Could not read plist: %@", errorDesc); // FIXME: Return error
}
There are other solutions of course. I personally generally use the preprocessor for this kind of problem. In my build configuration, I would set GCC_PREPROCESSOR_DEFINITIONS
to include BaseURL=...
for each build configuration and then in some header I would have:
#ifndef BaseURL
#define BaseURL @"http://default.example.com"
#endif
The plist way is probably clearer and easier if you have several things to set, especially if they're long or complicated (and definitely if they would need quoting). The preprocessor solution takes less code to process and has fewer failure modes (since the strings are embedded in the binary at compile time rather than read at runtime). But both are good solutions.
Upvotes: 5
Reputation: 1328
You can do it by performing some extra steps:
Upvotes: 7