xcodebuildconfigurationxcconfigxcode-workspace

Xcode Build Configurations in Workspace With Multiple Projects


Using Xcode 7.2 (7C68), OS X 10.11.2 (15C50)

tl;dr With multiple projects in same Xcode workspace, why do my user-defined build settings for a build configuration seem to not work? I set them correctly in the scheme, but when run on simulator the values are correct; when run on device, the values are wrong.

Hello. I am trying to leverage Xcode build configurations (.xcconfig files) to customize the behavior of our app based upon the environment. This is so that we can switch between integration and production URLs with automatically based upon the scheme's build configuration. However, I am having some difficulty getting it to work properly; I think my workspace layout may be to blame. Here is the layout/structure:

Now, I have the following .xcconfig files for each of those projects:

Additionally, the following schemes (mapping one-to-one to its respective configuration for each project):

For the framework, these files contain the information we would like to customize based upon debug or testing or release (e.g. URLs, API tokens/keys, etc.). Now, both the app and the framework each have their own copies of those files. This is because Xcode, when dealing with dependencies or multiple projects, implicitly tries to use configurations of the same name in this scenario. I guess part of the issue is I don't know how to explicitly tell Xcode to use X configuration for a dependency that isn't the configuration being set.

In other words, how do I tell both the app to use X configuration and the framework to use Y configuration?

Right now, when I run the app in the simulator, I know the scheme is using the correct info.plist values because the URLs and log settings appear correct. However, when I archive or run on device, the wrong build configuration is used. I haven't an idea of why this is happening.

The screenshots and code illustrate how this works right now:

Figure 1: Info.plist

Figure 2: Framework build settings

Figure 3 (the partial body of some method):

if let infoDict = NSBundle(identifier: Constants.uniformTypeIdentifier)?.infoDictionary,
        let apiKey = infoDict[Configuration.SerializationKeys.pusherAPIKey] as? String {
            return apiKey
    }

Inside of the framework, user-defined build settings contain settings that need to change for debug vs release vs whatever (Fig. 1). The Info.plist file extracts variable values for a given scheme ideally (Fig. 2). Then in code I retrieve the values from the info plist (Fig. 3).

Any device just refuses to use the production values when told to do so, including when I switch it manually on my scheme's Run action as well as the Archive action - the archive uses returns the wrong build settings on device.

Sorry this is long and thank you for reading.


Solution

  • Ultimately, I decided with a similar approach as seen here:

    How to compile a project with app and library in the same workspace with different configuration names?

    It adds build settings inside the parent project to direct it on how to find what it needs in the child project. Additionally, I needed to take the embedded .framework file and set it relative to the build path and using the configuration setting. I did leave out the variants and just used $(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME) for all values instead of leaving off the platform name to finally achieve success.

    Will update this post as I learn and discover more.


    Update: 2016-2-29:

    I removed the .xcconfig files; they were not necessary.

    But, I've run into difficulty when trying to actually use the third scheme in the embedded framework. I tried toggling DEFAULT_CONFIGURATION but the settings did not hold. Omitting some details, basically even if the right build directory is specified, Xcode ignores this when using a parent's build config setting and builds all products in the same directory, which I also believe is a result of "Build Implicit Dependencies" as well as the "Embed Frameworks" build phase. But if you were to remove these and then install to device, the app crashes at launch because it cannot find the framework file.

    To be continued...