How to switch the build for iOS app - ios

My application support 20 languages such as: English, German, French, Danish ...
Now I want to build 2 version:
1. English only
2. Full 20 languages.
Must I have to create 2 separate projects in order to build 2 IPA file?
I am using Xcode Version 6.4 (6E35b)

Duplicate your target then add a key (YOUR_KEY=1) in Target > Build Settings > Preprocessor Macros.
Now you can use #if #else #endif to define url for 2 targets.
#if English
#define kUrl #"https://english.example.com"
#else
#define kUrl #"https://world.example.com"
#endif

Related

Swift: Multiple targets handling: macros not working [duplicate]

This question already has answers here:
#ifdef replacement in the Swift language
(18 answers)
Closed last month.
from the reference How to handle multiple targets in XCode using swift language? and https://www.appcoda.com/using-xcode-targets/
I have created three targets, each target having different bundle ids and app icons. I have also added different flag to the "Other swift flags" - > Custom swift flag section
like
for first target I added "-DGOLD" ,
for second target I added "-DSILVER" and for
third target I added "-DPLATINUM".
In the AppDelegate I wrote a code
#if GOLD
print ("Gold")
#elseif SILVER
print ("Silver")
#else
print ("Platinum")
#endif
FYI, I am using Xcode 8.3
I tried to run the first target, I always getting "Platinum". Please provide me how to get the flags correctly
I am working with Xcode 9.
I am having same problem and looked for an answer for a few hours and finally found the solution.
At each Target, Build Settings -> Other Swift Flags, I added the wanted flag like this:
Target1 -> -DTARGET1
Target2 -> -DTARGET2
Then in my code used:
#if TARGET1
//
#elseif TARGET2
//
#endif

Preprocessor macro for Apple Watch?

I was looking at Apple's Lister (for Apple Watch, iOS, and OS X) sample. The sample performs a test for iOS and OS X:
#import <TargetConditionals.h>
#if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
#import ListerKit;
#elif TARGET_OS_MAC
#import ListerKitOSX;
#endif
However, there is no test for TARGET_OS_WATCH or similar. Grepping for watch in TargetConditionals.h delivers no hits:
$ cat /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer
/SDKs/iPhoneOS7.1.sdk/usr/include/TargetConditionals.h | grep -i watch
$
From TargetConditionals.h, I know there are:
These conditionals specify in which Operating System the generated code will
run. The MAC/WIN32/UNIX conditionals are mutually exclusive. The EMBEDDED/IPHONE
conditionals are variants of TARGET_OS_MAC.
TARGET_OS_MAC - Generate code will run under Mac OS
TARGET_OS_WIN32 - Generate code will run under 32-bit Windows
TARGET_OS_UNIX - Generate code will run under some non Mac OS X unix
TARGET_OS_EMBEDDED - Generate code will run under an embedded OS variant
of TARGET_OS_MAC
TARGET_OS_IPHONE - Generate code will run under iPhone OS which
is a variant of TARGET_OS_MAC.
TARGET_IPHONE_SIMULATOR - Generate code for running under iPhone Simulator
Question: Is there a preprocessor for Apple's watch?
I'm tagging with ios, but I'm not sure that's the correct OS for this question.
The list below was compiled from iPhone's TargetConditionals.h. The Simulator and OS X are similar (they just have different bits set to 1):
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_EMBEDDED 1
#define TARGET_OS_IPHONE 1
#define TARGET_IPHONE_SIMULATOR 0
Questions: Does the watch use TARGET_OS_EMBEDDED? Does the watch omit TARGET_OS_IPHONE?
You can find all kind of target conditionals in the TargetConditionals.h (cmd + shift + o and type TargetConditionals.h).
In this list you can find a list like this and many more useful defines.
Currently it does contain TARGET_OS_WATCH since WatchOS 2. For WatchOS 1 it was not possible to run custom code on the watch so it was not needed back then since everything ran on the phone itself.
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_IPHONE 1
#define TARGET_OS_IOS 0
#define TARGET_OS_WATCH 1
#define TARGET_OS_TV 0
#define TARGET_OS_SIMULATOR 0
#define TARGET_OS_EMBEDDED 1
Swift Addition
#if os(watchOS)
[Watch code]
#else
[Code for iOS, appleTV, or any else clause]
#endif
Some other valid values: iOS, OSX, tvOS
A small explanation about this and more http://nshipster.com/swift-system-version-checking/
At the bottom of this document
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_15#Build Configurations
Under the section 'Build Configurations' you can find a (hopefully) up to date list with all these values that are currently available
As of watchOS 2.0, you can run native code on the watch, so this is a more relevant question.
I'm using the first early beta of watchOS 2, so this may change, but right now, TARGET_OS_WATCH is set to 1 on watchOS.
(Also, be careful: TARGET_OS_IPHONE is also set to 1 on watchOS, though TARGET_OS_IOS is 0.)
There is no WatchKit or app extension target conditional. But you can create your own per-target conditionals that you use in the same way.
If you look in the "Build Settings" section for any target, there's a section called "Other C Flags". Add an entry for the WatchKit target. If you add something like -DMY_WATCHKIT_FLAG=1, you can then do #if MY_WATCHKIT_FLAG in code.
Make your custom flag, well, custom. It's not impossible that Apple might add a flag in the future called something like TARGET_WATCH_APP or whatever. Use a prefix on the flag name to make it specific to you.
With the current WatchKit SDK, all code in a Watch application runs on the phone it’s paired with, so there’s no point at which your preprocessor is going to encounter code that’s going to run on the Watch and thus not much use for a macro to tell it what to do when it does. The code in the ListerWatch target of the sample you linked to will run as an extension on the iPhone and talk to its watch UI via WatchKit.

XCode: Check destination platform with define

Do exist some standard defines, that specify destination platform, e.g. DEST_IOS or DEST_OSX? Or must I add its in project's settings?
I need this for using same library on Mac and iPad.
Yes. Include TargetConditionals.h, and I use the following to make them a bit easier to use:
#import <TargetConditionals.h>
#if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
#define TARGET_OSX 1
#else
#define TARGET_IOS 1
#endif
(this is in a common project header file).
And then to use the macros:
#if TARGET_OSX
// OSX-specific thing here
#else
// iOS-specific thing here
#endif

In absence of preprocessor macros, is there a way to define practical scheme specific flags at project level in Xcode project

Before swift I would define a set of schemes for alpha, beta, and distribution builds. Each of these schemes would have a set of macros that were defined to gate certain behaviors at the project level. The simplest example is the DEBUG=1 macro that is defined by default for all Xcode projects in the default scheme for the Run build. One could query #ifdef DEBUG ... and make decisions in the code accordingly, even compiling out non-necessary code.
It seems that this type of configurational gating is not as easy using swift, as macros are not supported. Can someone suggest a comparable approach, I don't care if the code is compiled out, per se. I would like to gate features based on build scheme, though.
In Swift you can still use the "#if/#else/#endif" preprocessor macros (although more constrained), as per Apple docs. Here's an example:
#if DEBUG
let a = 2
#else
let a = 3
#endif
Now, you must set the "DEBUG" symbol elsewhere, though. Set it in the "Swift Compiler - Custom Flags" section, "Other Swift Flags" line. You add the DEBUG symbol with the -D DEBUG entry.
(Build Settings -> Swift Compiler - Custom Flags)
As usual, you can set a different value when in Debug or when in Release.
I tested it in real code; it doesn't seem to be recognized in a playground.
We ran into an issue with not wanting to set swift compiler flags because we didn't want to have to set them and keep them up to date for different targets etc. Also, in our mixed codebase, we didn't want to make remember to set our flags appropriately all the time for each language.
For ours, we declared a file in ObjC
PreProcessorMacros.h
extern BOOL const DEBUG_BUILD;
In the .m
PreProcessorMacros.m
#ifdef DEBUG
BOOL const DEBUG_BUILD = YES;
#else
BOOL const DEBUG_BUILD = NO;
#endif
Then, in your Objective-C Bridging Header
#import "PreProcessorMacros.h"
Now, use this in your Swift codebase
if DEBUG_BUILD {
println("debug")
} else {
println("release")
}
This is definitely a workaround, but it solved our problem so I posted it here in the hopes that it will help. It is not meant to suggest that the existing answers are invalid.
More swifty solution to Logans method. Set -D DEBUG in Other Swift Flags of Swift Compiler - Custom Flags section in build settings of your target.
Then declare following method in global scope:
#if DEBUG
let isDebugMode = true
#else
let isDebugMode = false
#endif
Now use it as
if isDebugMode {
// Do debug stuff
}
For me, set the debug item of "Active Compilation Condition" to "DEBUG" worked.
Then using DEBGU key work in #IF DEBUG works in debug mode and #ELSE in release mode:
Select your target,
In Build Setting tab search for "Active Compilation Condition",
Set the value of its "Debug" item to "YourKeyWord",
Use simply as follow:
#if DEBUG
print("You'r running in DEBUG mode!")
#else
print("You'r running in RELEASE mode!")
#endif
Swift compiler directives
You can use next compiler directive
#if <some_key>
//logic 1
#else
//logic 2
#endif
//pre Xcode v8
Other Swift Flags(OTHER_SWIFT_FLAGS) = -D <some_key>
-D DEBUG
//from Xcode v8
Active Compilation Conditions(SWIFT_ACTIVE_COMPILATION_CONDITIONS) = <some_key>
DEBUG
I'm working in a mixed language code base where the obj-c code uses a macro to send debug messages to the console (and that macro relies on our debug preprocessor flag). I wanted to be able to call that same macro in the swift code...
I created a class method on one of my obj-c classes that is a wrapper around that macro.
I added that obj-c header to our bridge header file.
Now my swift code calls that class method as a "proxy" to the obj-c macro.
It's mildly annoying that I can't just call the macro straight up in the swift code, but at least now I only have one place in the project to worry about turning my debug flag on/off.

Assign a static constant at build time ios xcode

I should built and archive my application with Prod_URL and Stage_URL for our test team.
now i am using an Constant.h file and there is a code like;
//for stage
#define SERVICE_URL #"myStageUrl.com"
/*
//for prod
#define SERVICE_URL #"myProdUrl.com"
*/
And I always changing comment out lines to be able to build two different version of my app.
So now I wanna do it automatically.
I create two target like MyAppStage and MyAppProd. And I think I should write a Run Script for that to switch between these two #define lines. But I don't know how to write script.
Or are there any better way for that situation?
Thx,
If you have two separate targets you can place these defines in the project properties its self. To do that you go to your project properties. Click on the target you want to edit, click on the "Build Settings" tab and search for Preprocessor Macros. Define anything you want there and it will be visible for every class in that target.
Another option is to use the same Preprocessor Macros build setting and set a macro for STAGE. then in your Constant.h you can have something like:
//for stage
#ifdef STAGE
#define SERVICE_URL #"myStageUrl.com"
#else
//for prod
#define SERVICE_URL #"myProdUrl.com"
#endif
In your target for staging, add a preprocessor macro, something like STAGING_BUILD will do. Don't change the production target.
Now, in your code:
#ifdef STAGING_BUILD
//for stage
#define SERVICE_URL #"myStageUrl.com"
#else
//for prod
#define SERVICE_URL #"myProdUrl.com"
#endif
then only the required line will be compiled in based on the target selected to be built.

Resources