My iPhone application connects to three different servers, say: production, staging and testing. There is a bunch of configuration values that the application uses depending on to which server it connects to, e.g. Facebook App ID, TestFlight team key, etc.
I'd like to have all the settings in GIT and only select which configuration the application supposed to use when compiling or releasing. For example, when testing is selected, Product -> Run in Xcode runs the debug version of the app connecting to testing, and Product -> Archive creates the IPA file with the release version that also connects to testing.
I don't want to create more build configurations than debug and release (because that would mean 6 different combinations of build configurations/run-time configurations). The ideal solution, as I see it, would be that I have three schemes: production, testing and staging, and each scheme selects one of three Info.plist files to use with the application. That would allow me to not only define different run-time settings, but also different application versions or bundle identifiers depending on the back-end server. But it doesn't look like I can configure the Archive action in any other way apart from selecting a different build configuration. Any ideas if that could be achieved in any way?
Edit: To make it a bit more clear, production/staging/testing is the back-end server, not the version of the iOS application. The iOS app comes in two versions: debug/release. In other words I may want to run a debug version of the application connecting to the production server for example to debug a crash caused by JSON returned from that server. I could have named the servers as A, B and C for the sake of clarity.
Deep dive — Xcode Build Settings. With Xcode build settings we can… | by Prasanna Aithal | Mac O’Clock | Medium With Xcode build settings we can control the build phases in order to generate a product i.e application or custom frameworks. Knowing on these settings will helps us to gain knowledge on how specific task will be performed.
The only difference is that it has an Xcode Default radio button, if you choose this radio button, the Xcode workspace will use Xcode default build location settings. 1.3 How To Set Xcode Project Build Directory.
1.1 How To Set Xcode Default Build Directory Location. Click Xcode —> Preferences… menu item at Xcode top menu bar. Then click the Locations tab in the popup dialog. In the Derived Data drop-down list, you can choose one of the Default, Relative, Custom drop-down items.
The configurations that we just created now need to be associated with an XCode scheme. For more information on what a scheme is, check out the apple documentation reference here. To do so, we need to manage the schemes of the project. Open the scheme manager. Select Product -> Scheme -> Manage Schemes … from the toolbar. 2.
A good way to do this would be with build configurations and C macros. This avoids having to create a separate target for every configuration which is not really the correct use of targets.
First you want to set up the configurations at the project level:
You can create different configurations for debugging, enterprise distribution, and any other type of special build you want.
Next you can define some macro flags for each configuration which will be passed to the compiler. You can then check for these flags at compile time. Find the "Preprocessor flags" build setting at the target level:
If you expand the triangle you can define different values for each of your configurations. You can define KEY=VALUE
or just KEY
macros here.
In your code, you can check for the existance of these macros, or their value (if there is one). For example:
#ifdef DISABLE_FEATURE_X
featureXButton.hidden = YES;
#endif
// ...
#if FOOBAR_VISIBLE == 0
foobarView.hidden = YES;
#elif FOOBAR_VISIBLE == 1
foorbarView.hidden = NO;
#else
#error Invalid value for FOOBAR_VISIBLE
#endif
You can pass in string values as well, which must be wrapped with single quotes in the build setting, e.g. DEFAULT_LOCALIZATION_NAME='@"en"'
.
You can also configure which configuration is used during Debug and Archive time using the Schemes editor. If you choose "Run" or "Archive" in the Schemes editor you can select the appropriate configuration.
If you need to parameterize entries in the Info.plist file, you can define their value using a custom build setting. Add a custom build setting for your target:
And then give it an appropriate value for your different configurations:
Then in the Info.plist file you can reference this setting:
Note that the one limitation of this approach is that you cannot change the following items:
Additionally, in older versions of Xcode without asset catalog support, you cannot change the following items:
These cannot be explicitly defined in the Info.plist file or anywhere else, which means you need different targets to change them.
Hope this helps.
I would suggest using different build targets for each environment. I successfully used this model before. In your project's settings you can duplicate the current target and change the build settings as needed. There's an Info.plist File
property that will let you change the default plist for that target.
After that, you can create a scheme for each environment that will use the according target.
You can get a step further and use different bundle id for each target and different names. That will allow you to install both the staging and the production builds on the same device for example.
The only downside in this is that you have more work when you want to update provisioning profiles.
Here's a much easier solution if the concerned libs allow to set the keys in code, meaning that you can have production value in your plist file, but change them in your AppDelegate (or whichever file they are first used in).
Works with facebook, twitter and google sdk at the moment.
Ex:
#ifdef DEBUG
// Facebook
[FBSettings setDefaultAppID:@"SandboxID"];
// Fabric / TwitterKit - must be called above [Fabric with:@[TwitterKit]];
[[Twitter sharedInstance] startWithConsumerKey:@"SandboxKey" consumerSecret:@"SandboxIDSecret"];
#endif
Same in Swift, just use #if instead of #ifdef.
Note about Facebook This worked with version 3 of their SDK, I'm not sure it's possible with later versions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With