73

I have an xcconfig file which contains a configuration for which server my app should hit. In debug mode, this will be a different server than for release builds.

The problem I have is that a URL of the form http://www.stackoverflow.com is treated as a comment after the double slash. So the string I get in code is 'http:'

I have read that I can put a -traditional build flag on Info.plist, I was wondering if someone else has had a similar issue and has solved it?

Thanks.

atreat
  • 4,243
  • 1
  • 30
  • 34
  • Have you tried to enclose the URL in quotation marks: `"http://bla.com"` ? – Martin R Jan 23 '14 at 19:55
  • 3
    yes, quotation marks and the standard \/\/ escaping does not seem to make a difference. In the \/ case the string becomes http:\/\/stackoverflow.com – atreat Jan 23 '14 at 19:56

6 Answers6

124

Here's a simple workaround:

WEBSITE_URL = https:/$()/www.example.com
David H
  • 2,901
  • 1
  • 26
  • 21
  • 4
    Unless you do a substitution into your plist file as `$(WEBSITE_URL)`. Ask me how I know. – Robert Atkins Aug 08 '16 at 09:53
  • @RobertAtkins if you're taking about your Info.plist you should think about using two separate plist files for debug/release. you can configure this in your project's Build Settings->Packaging->Info.plist File configuration (expand to show debug/release). A little annoying I know, but it may do the job for you. – atreat Aug 08 '16 at 19:21
  • 1
    @RobertAtkins I don't understand your comment. Are you saying that the workaround doesn't work for the scenario you described? If that's what you meant then I'm puzzled, because that's exactly how I'm using it. – David H Aug 09 '16 at 18:41
  • 9
    If you use the `$()` trick in your `.xcconfig` file but have the substitution for `$(WEBSITE_URL)` in your `Info.plist`, it doesn't work. If you say `${WEBSITE_URL}` (note curly braces) it works. – Robert Atkins Aug 09 '16 at 20:23
  • @RobertAtkins Ah— thanks for the clarification. I used curly braces in my info.plist so I didn't experience the problem you originally pointed out. Good catch. – David H Aug 09 '16 at 22:24
  • @RobertAtkins so am I right to say (1) curly braces needs to be used in the plist (say `${PUBLIC_KEY}`, and (2) the corresponding xcconfig needs to have `$()` before each of the backlash `\n` for it to not escape the character? I am trying to get a public key into the xcconfig to no avail - it's taking the `\n` character literally. Pasting it into the build settings directly has no issues. – CyberMew Nov 10 '20 at 18:53
  • 1
    Looks like we can use `$(WEBSITE_URL)` directly nowadays at least in Xcode 13.2.1 – xi.lin Feb 08 '22 at 08:56
47

I also could not figure out how to use a double slash in a xcconfig file. But I found a workaround in

from the Xcode-users mailing list: In the xcconfigfile, save the URL without the http scheme:

MYURL = stackoverflow.com

In the Info.plist, set the property value to

http://${MYURL}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
23

Just declare

SIMPLE_SLASH=/

Then your URL becomes

http:$(SIMPLE_SLASH)/www.stackoverflow.com
MohG
  • 351
  • 4
  • 11
10
SLASH=/

API_URL=http:$(SLASH)/endpoint.com
Badre
  • 710
  • 9
  • 17
3

Another approach that improves readability could be:

PROTOCOL = http:/
API_URL = $(PROTOCOL)/www.stackoverflow.com

This way protocol can be used elsewhere

all.herranz
  • 115
  • 7
-4

You shouldn't use a xcconfig file for this setting.

A xcconfig file is not a "normal" header or module file which is the input of the preprocessor and eventually the input for the compiler. It's nowhere specified how the xcconfig file parser treats character encoding, whether it recognizes escape sequences, whether it expands macros, and how character literals are defined and much more.

It's far better in this case, to have a "config.h" header file and use a conditional based on a preprocessor definition:

#if defined (DEBUG)
    NSURL* url = ...
#else
    NSURL* url = ...
#endif

Here, DEBUG is defined for Debug configuration by default. You may #define any other definition in the build settings under "Preprocessor Macros".

CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67
  • This is the way to go if you aren't forced to use build settings (Unfortunately I am). I'm going to try and sway the opinion of my teammates. – atreat Jan 23 '14 at 20:58
  • Sometimes you want to inject preprocessor defines in during the build phase, not in the code, example compiling in a private key. – John Twigg Jul 25 '14 at 20:54
  • @JohnTwigg For performing any actions before, during or after building, the preferred way is to define a "Run Script Build Phase" which runs at specific points in the build process. For example, you might set the build version strings in the Info.plist, search and replace a certain source file, convert it to an http file (or any other kind of document using command line tools) and place it into the bundle resources, and virtually any other kind of task that comes to mind :) You can then streamline that process using a "rake file" which customized rake tasks, e.g. "generateKey" or what ever. ;) – CouchDeveloper Jul 26 '14 at 07:03
  • Sometimes you don't want to hard code a url in your project's version control system, for example my server running on localhost is at 192.168.1.27, and that may be a totally different ip for another team member. I would not want to has #if defined (DEBUG) in my code. I would want to use something like debug.xcconfig as a file that is not checked into version control so that different team mates can configure it for their own machine. – patrick Dec 29 '15 at 04:28
  • @patrick Alternatively, you can set such variables as a shell environment variable. Unfortunately, in Mac OS X environment variables for GUI apps are read differently than those for console apps. But there's an easy solution: for GUI apps we need to set the environment variables in `launchd`. See here, accepted answer on SO: http://stackoverflow.com/questions/603785/environment-variables-in-mac-os-x – CouchDeveloper Dec 29 '15 at 10:12