Can an App Extension be conditionally included in a build? - xcode

I'm starting work on 2 app extensions, and I'd like to set up my builds as follows:
Builds intended for the App Store should not include either extension
Builds intended for TestFlight should include the extension that is almost ready
Local builds should include both extensions
Currently, I have a different build configuration for each of these to show and hide other aspects of the app (and compiler flags in some cases too). I use fastlane to make my builds.
As far as I can tell, the only ways to add or remove an app extension would be:
Duplicate the main target twice and use one for each of the above builds (drawback - must maintain 3 copies of the target until the extensions are fully complete)
Manually add/remove the extension before building (drawback - impossible to make both TestFlight and App Store builds from a given branch in a CI environment because manual intervention is required)
Can anyone think of a better solution for conditionally including the app extensions?

Related

Why does CocoaPods target have build settings?

Why do our CocoaPods targets have different build settings than our actual project target settings? Shouldn't it just have project target settings? How does it work when our project is being compiled; does the compiler look at the CocoaPods settings or just our project target settings? If so, then what is the purpose of CocoaPods having its own build settings?
CocoaPods generally are built as a framework in iOS, and frameworks can have different settings than the main application, and are built as a separate bundle. Every compile-unit (more or less "source file") can also have its own settings (at least in ObjC; I've never tried that in Swift).
There are lots of reasons to have different compile settings for different parts of the program, and specifically for third-party code. For example, you might want to compile third-party code with a higher optimization level and debug stripping if you don't plan to debug that portion. I personally turn off all warnings in third-party code.
It's not as common anymore, but during the ARC transition it was very common to compile some of the program with ARC and some without. As Swift evolves, you should expect it become more common for libraries to be written in source-incompatible versions of Swift that require different settings.

Shared scheme for Carthage

I'm trying to understand shared schemes in Xcode. For Carthage we should set scheme to shared option - iOS target for example. But what about test target? (iOS Tests). Should I check it as shared for Carthage or nor?
Thanks!
Marking a scheme shared in Xcode makes the Scheme available outside of your user.
Effectively what it does is to move the Xcode auto-generated build scheme out of your user specific xcode folder (xcuserdata/), to the shared data folder (xcshareddata).
This is normally done if you want to build your project elsewhere and you don't want to rely on auto-generated schemes or you might have modified the auto-generated schemes (e.g. when building on a CI server).
Carthage: no shared framework schemes for iOS platform (for my own framework) shows what I mentioned as well, the scheme is moved and shared outside from your user settings.
Carthage requires this to be able to detect and build your project properly with the dependencies that you've added through Carthage.
For the second part of the question regarding test schemes: Usually you don't have extra schemes for testing and such, but rather you've configured your main scheme for the test action. If you have a separate scheme for your testing purposes (for whatever reason), they will have a build dependency on the main target/scheme that you're testing and therefore they should be linked already. You can make those schemes shared, but I doubt you'll have to.

In an Xcode 4 workspace, how do I cascade build settings & configs to subprojects

Overview
I'm using static libraries and Xcode 4 workspaces to effect modularity in iOS development, an increasingly common technique. For example, I might have a workspace which contains an App project, and a Library project, like so1:
You would then have a scheme to build these that looked something like this:
What I would like to do is have the "App build" control the "Library build" it initiates, in at least a couple of ways:
Map App configurations (e.g. Debug, AdHoc) to arbitrary Library configurations
Passing through some subset of -D defines, and/or specifying these for the library build.
I'll deal with each of these in their own section, but it's worth making a few clarifications.
Clarifications
I'm using App/Library here as an easy proxy for any Superproject/Subproject relationship you may have.
From what I've seen, Xcode 3 style embedded subprojects don't seem to work any differently in Xcode 4 than workspace "peers". I'd love to be wrong about this.
I know I could do almost anything with a "Run Build Script" build phase, and xcodebuild. But I'm trying to work within the system here, where the dependencies are specified in the scheme, and otherwise somewhat loosely coupled.
The Library exists to be used in more than just this project, and so you cannot arbitrarily load it up with junk specific to this App's build, or reference anything particular to the App or Workspace. For the general case, this rules out including static .xcconfig from the App project as a way to convey build information from the App to the Library.
Building the Library outside the workspace sacrifices too much, not an option.
Configuration Mapping
As I understand it, building a particular App configuration will:
If a configuration exists in the Library of the same name, it will build the Library using that.
Otherwise, it will build the active configuration of the Library, as specified in the Library's project file.
To my knowledge, without resorting to the aforementioned run-build-script hack, that is the extent of the control one has over subproject build configurations. Please tell me different.
Ideally, I would be able to specify (in the scheme, presumably):
AppConfigA -> LibConfig1
AppConfigB -> LibConfig2
While Debug, AdHoc, & Release may be the only configurations some ever use, complex projects often outgrow that.
Defines
I've not yet found way to pass -D defines from the App build to the Library, without resorting to xcodebuild, which can take, e.g., an .xcconfig file.
The App's build settings can be accessed in Library build run-build-script phase. However, doing that introduces a dependency in the Library on the App project, which for good reason is verboten (cf. Clarifications). But even then, I haven't found a way to use those settings to directly control the Library's build (much2).
So crazy it just might...
One scheme I came up with while writing this would be:
The Library bases it's build configurations on an empty (dummy) LibraryExternals.xcconfig file within it's own project.
A clean of Library deletes that file. A standalone build of the Library will create an empty one if it does not already exist.
That file is overwritten by an App Build run-build-script phase, and contains anything the app wants to communicate to the Library build.
Seems kind of complicated, but I'm looking for anything right now. I'll push this to an answer if nothing better comes along.
1 Apps shown are Max OS X. I find command line apps make for simpler tests. Same applies.
2 Cf. Info.plist preprocessing, which I learned about during this investigation.
If you modify your project structure to use a single project with multiple targets then each target's build settings will automatically inherit from the project. From there, you can modify ones that you want to be different, or select an individual setting and press the delete key to set it to the default specified by the project.

How to work on a Cocoa app and plugins in parallel?

I have a relatively simple goal: I want to create a Cocoa application which doesn't have much functionality itself, but is extendable through plugins. In addition I want to work on a few plugins to supply users with real functionality (and working examples).
As I am planning to make the application and each plugin separate open-source projects (and Git repositories), I'm now searching for the best way to organize my files and the Xcode projects. I'm not very experienced with Xcode and right now I don't see a simple way to get it working without copying files after building.
This is the simple monolithic setup I used for development up until now:
There's only one Xcode project with multiple products:
The main application
A framework for plugin development
Several plugin bundles
What I'm searching for is a comfortable way to split these into several Xcode projects (one for the application and framework) and one for each plugin. As my application is still in an early stage of development, I'm still changing lots of things in both the application and the plugins. So what I mean by "comfortable" is, that I don't want to copy files manually or similar inconvenience.
What I need is that the plugin projects know where they can find the current development framework and the application needs to know where it can find the development plugins. The best would be something like a inter-project dependency, but I couldn't find a way to setup something like that in Xcode.
One possible solution I have in mind is to copy both (the plugins and the framework) in a "Copy Files Build Phase" to a known location, e.g. /tmp/development, so production and development files aren't mixed up.
I think that my solution would be enough, but I'm curious if there's a better way to achieve what I want. So any suggestions are welcome.
First, don't use a static "known location" like you mention. I've worked in this kind of project; it's a royal pain. As soon as you get to the point of needing a couple of different copies of the project around (for fixing bugs in parallel, for testing a "clean" build versus your latest changes, for working on multiple branches), the builds start trashing each other and you find yourself having to do completely clean/builds much more often than you'd want.
You can create inter-project dependencies by adding the dependent project (Add File), right click the Target and choose "Get Info," and then add a Direct Dependency on the General pane.
In terms of structure, you can either put the main app and framework together, or put them in separate projects. In either case, I recommend a directory tree like:
/MyProject
/Framework
/Application
/Plugins
/Plugin1
/Plugin2
Projects should then refer to each other by relative paths. This means you can easily work on multiple copies of the project in parallel.
You can also look at a top-level build script that changes into each directory and runs "xcodebuild". I dislike complex build scripts (we have one; it's called Xcode), but if all it does is call "xcodebuild" with parameters if needed, then a simple build script is useful.

Xcode: project settings vs. target settings

I'm creating a static lib on Mac OS X for one of our customers, as well as a small cmd line app to test the static lib. The cmd line project has 2 extra library search paths, which meant I was linking to the Debug version in Release mode and just about went crazy, so I tried to get rid of these two paths, but I couldn't find where they were specified. I was looking in the project info, but it turns out they were specified in the target info.
I don't understand the distinction?! Why there are 2 sets of settings, which are essentially the same?! Can someone please enlighten me?
A project can contain multiple targets. For example, an app I write has four - the app itself, a Quick Look plugin, a framework and a bundle that contains Mac OS 10.6-specific functionality that can be dynamically loaded in.
Project settings apply to every single target in the project. Each target can then override individual settings if they need to - for instance, my project's Target SDK is set to 10.5, but the 10.6-specific bundle has it's Target SDK set to 10.6.
In some instances, some settings don't make sense to be in Project Settings - one of these, I guess, is search paths.
You often have multiple targets in a single project - for instance, you might have a framework project with a target for building as a dynamic .framework bundle, and a target for building a static lib. Or your app might have a target for building the app itself, and a target for building some helper command-line tool that it needs to install.
Wherever possible, I'd suggest changing settings at the highest level (in the project settings, and simultaneously changing debug & release configurations), and only customizing the target settings when necessary. Even better, move as many settings as possible into xcconfig files, which seem a much more explicit way of specifying your build setup.
Preface: you ship targets. Your end products are targets. Not projects. Think of a project as the umbrella above multiple targets.
For a more realistic example assume both Uber and Lyft were being developed by the your (umbrella) company.
The company has the following three environments:
Debug
QA
Release
The Debug and Release configs come out of the box with every new project you create. You can create as many additional configs as you want
This would require 3 configurations. To add a QA configuration follow the tutorial here
Did I apply this to the target or project?
I applied it to the project.
Ok so configs are only for projects and not for targets. Right?
Incorrect! It's confusing I know. You have to think of the project as a big container where you create your configs in there.
Then for each target (not project), for following tabs:
General, Resource Tags, Build rules, Info:
There is no difference between different configs
Signing and Capabilities tab:
You can switch between teams and sign it with a different team. This is useful if you want to sign your beta builds with your enterprise certificate but sign your Appstore build with app store certificate.
Build Settings tab:
For almost every variable in this section you can give a different value based on the config. Common Build Settings to customize are:
Architectures - 'Build Active Architecture only'
Build Options 'Debug Information Format'
Packaging
Set the plist you want per configuration.
Change the bundle identifier (Packaging >> Product Bundle Identifier). If you switch values for a field then in the plist you'll see as:
Signing
Code Signing identity
Code Signing Style (Manual or Automatic)
Development team
Provisioning Profile
Apple Clang - Optimization Level
If the values are different then the row's value would be
<Multiple values>
and you basically have to expand that value to see what value is given for debug and what value is given for Release or QA config.
If all the values are the same then you'll just see the value that is given to all of them. By default the values are the same.
Build Phases:
There's no out GUI way of switching based on configuration. However you can still do run certain commands based on the configuration. Example:
if [ "${CONFIGURATION}" = "Debug" ]; then
"${PODS_ROOT}/SwiftLint/swiftlint" autocorrect
"${PODS_ROOT}/SwiftLint/swiftlint"
fi
Summary
Long story short, this allows you to have 2 different apps (targets) with the same code (project), in 3 different environments (dev, QA, release). You create the different environments using configurations.
To learn more on this I highly recommend you to read more about this in depth and understand what configuration files (xcconfig) is. It's much more simpler than you think. It's mainly a key value pair:
AppCoda - Using Xcode Configuration (.xcconfig) to Manage Different Build Settings
NSHipster - Xcode Build Configuration Files

Resources