iPhone - Switching between local and production environment settings - iphone

I am developing an iPhone app which uses a server somewhere to fetch its data. Somewhere in the app's source code I hardcoded the URL to use to connect to. This is fine, except that I don't always want to test using a production server! I don't want to mess with live data, just to test something locally. So I set up a local version of that same server. But in order to make the iPhone app use that server is to change the hardcoded URL in the source code.
This is a little bit of a pain in the ass to do if you're often switching between the two servers. Also, I might accidentally release the app which still uses the local URL!
I was thinking that maybe XCode can help me with this since it has the notion of a "Debug" and a "Release" configuration option to build with. So my question is: can I somehow change the Debug configuration in a way that it points to local server URL? Maybe through pointing to a properties or plist file which contains the environment specific URL. I could then make two versions of this properties file and make the debug configuration point to one, while make the release configuration point to the other.
Does anyone know how I can accomplish this?

Put this code where you need to use the configuration based on the mode (debug/release) = (development/production).
The best place to put it is on the "ProjectName"_Prefix.pch file.
#ifndef __OPTIMIZE__ // __OPTIMIZE__ is not enabled, it means that the active config is Debug, so here you have to put your code for development mode
// For example
#define SERVER_URL #"http://my.test.server/something"
#else //__OPTIMIZE__ is defined, so put here your production code
// For example
#define SERVER_URL #"http://my.production.server/something"
#endif // __OPTIMIZE__
Cheers,
VFN

In one of your header files (such as the pre-compiled header file) define macros with the URL. Take a look at this article and use a similar approach.
Incidentally, I'm using the logging approach from this article in all my apps - it works like a charm, I strongly recommend it!

You can define pre-proccessor macros in xcode by simply editing the gcc language settings:
Go to the Project menu and select "Edit Project Settings". Go to the "Build" tab .
Go to the section labeled "GCC 4.0 - Language". There is a setting named "Other C Flags". Add all the "-Dwhatever" macros you want there.

Related

How to change the optimization level?

I have the project which uses my second project as a lib. I see that them two has optimization level for debug none -o0 and for the release fast -0s
but in spite of this in the log, I see such a message
... was compiled with optimization - stepping may behave oddly; variables may not be available.
What are possible ways to fix it?
P.S. should be mentioned that debug doesn't work. It stops on the breakpoint, but I don't see the values of variables.
UPD
my second project - it is a lib. The structure looks like this
Demo - is a project
Lib - is lib
Let me know if I missed something
The build settings are tied to configurations. In your build settings for optimization, the Debug configuration is set to nonoptimized, and the Release configuration is set to optimized.
So far, so good.
But which configuration are you actually using when you build? That is determined by the scheme. Use the Scheme Editor to look at the schemes for your different targets. (You will have to look at them one at a time.) In each, look in the Run action. It says which configuration to use. If the pop-up says Release, change it to Debug.

Is there a way to know if the ipa was archived vs just run directly in xCode?

I like to create slightly different code when running the app from within xCode vs when archiving in xCode.
is that possible somehow with a compiler setting that one cann access?
Just like BuildConfig.DEBUG on Android?
The recommended way to do this in Xcode is to use Schemes. They are already setup and you will see them under Edit Schemes. When you are running normally in Xcode, you are typically running the Debug Scheme, there is also a Scheme set up for "Archive" (basically a release build). Xcode supports setting up as many schemes as you like and to set one up takes only minutes.
In the example illustrated in the picture I've set a pre-processor flag "DEBUG" to be set to 1 when running the "Debug" Scheme, or debug mode in Xcode. It is NOT set in other schemes. This makes it possible to have code that is only included in Debug builds, and not included in Archive builds.
That's pretty much all it takes, then you simply do something like this in your code:
#ifdef DEBUG
<Some code that is included and executed when running the Debug Scheme>
#else
<Some other code that executes at other times in other Schemes>
#endif

How to configure independent sets of runtime settings in Xcode

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.
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:
Settings.bundle
Additionally, in older versions of Xcode without asset catalog support, you cannot change the following items:
Icon.png
Default.png
These cannot be explicitly defined in the Info.plist file or anywhere else, which means you need different targets to change them.
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.
It is probably very low tech but I just have a method called apiURL() that returns the URL of the API I want. I have localhost, stage, and production and I simply uncomment the one I want. It's worked well for me so far. I've only forgotten to switch it back a few times. Oops.

Distinguishing development iPhone app versions

I like to keep a store-bought version of my iPhone apps on my phone so that I can reproduce any customer issues that come up, but I obviously also want to run the most current development version. I can install both (one from iTunes, one from xCode) but I'm interested in ways that I'm better able to tell the two apart. I could just change the name or icon temporarily, but that doesn't seem very failsafe, i.e. I might forget and ship it with the wrong icon.
Is there a happy funtime developer way to do this?
I was inspired by Eric's idea of adding a user-defined setting to the project but I didn't want to run a script every time I built the project.
We know that the iPhone looks for icon files named "Icon.png" by default. It turns out that the "Icon File" setting in the project plist isn't necessary at all if you've named your icon properly. However, if there is no file named "Icon.png" in the project, xCode looks at the value of the "Icon File" setting.
I set a user-defined setting in "Debug" called "Icon_Name" to a non-standard icon name, "DevIcon.png" and "ReleaseIcon.png" for the "Release" config. The "Icon File" setting in the project plist can now be set to ${ICON_NAME} and will take on the value of whatever config file we're using. Now building under two different configurations does use two different icons.
Edit: For multiple icons (high res, small, ipad, etc) I made a slightly different approach. The user-defined setting is now "IconPrepend" which is "Dev" for debug and "Release" for release config. I'm now using "Icon Files" (rather than "Icon File") in the info plist which takes an array of strings. Each string is prepended with ${ICONPREPEND} so that debug configurations look for "DevIcon.png" or "DevIcon#2x.png" and release configurations look for "ReleaseIcon.png" or "ReleaseIcon#2x.png".
Here's an idea - if you set a User-Defined Setting in your Project Build properties for Debug only along the lines of USE_DEV_ICON=YES (or something). Then, using the "Run Script" option in your Build Target you could copy different icons based on which Active Configuration you called.
Something along the lines of (pseudo-code):
if ($USE_DEV_ICON == YES)
cp DevIcon.png Icon.png
else
cp RealIcon.png Icon.png
Then every time you build, depending on the active configuration, it will copy the correct icon.
Most probably there is no other way. Your app store version and development version is completely different to the OS. If you want to distinguish, you need to change the icon or name. You can also include some debugging label (e.g. version number) in your development version, but you may also forget to remove this.
Maybe you'd just buy a second iPhone? Seriously. On your place I'd ask the same question as you do, but I will definitely take such a solution in mind. If I was an iPhone (or whatever other specific platform) developer, I'd most probably have more than one.
Couldn't you make a new target which has a different Bundle name in the Info.plist file, and use this target whenever you want to build the app to run on your iPhone?

xcode build configurations search paths

my iphone app builds fine in debug configuration, but when i change it to release, i get hundreds of errors, starting with "CoreServices/CoreServices.h: No such file or directory" in AudioFileComponent.h - part of the AudioToolbox framework.
i can't find where in the project/build settings is responsible for this.. thanks for any help.
I would recommend the following:
Open up your debug target's build settings by right-clicking on the target, hitting "Get Info", and selecting the Build tab.
Select All (Command-A) so the entire contents of the Build setting panel is selected, then copy it to the clipboard.
Paste the contents of the clipboard to an empty text document
Repeat steps 1-3 for the release target of the same project
From there you can use a diff utility or some other method to compare the contents of the two files, which will show you the settings that differ between the two configurations. Some of them will make sense (e.g., optimization settings) whereas others will not. Most likely there is a setting that differs between the two that will resolve your problem.
Another thing you can do is build one of your source files in debug mode, and in the Build Results window copy the contents of the command line to a text editor. Repeat for release mode. Then, replace each space in the command line with a newline (\r). From there you should be able to do a rough side-by-side evaluation of the differences between the two compile instructions, and may be able to figure out what's missing from that.
In general this helps you get a better feel for exactly what XCode is doing under the hood to build your project, which is a good strategy to practice no matter what tool you are using for development.
i think the problem was because i had the audiotoolbox package in the wrong place, it wasnt in system/library/frameworks like it should have been. (this doesnt explain why it built ok in debug though)