Share Xcode Schemes

So you are facing one of these Xcode errors where it tells you that there’s no such scheme? This post could help to explain why Xcode does it and how to solve this problem.

Shared vs User Schemes

While setting up build server for iOS app I have faced this issue multitude of times. Xcode schemes can be either shared or not. By default schemes are not shared and are owned by a user that creates them.

Here’s how it looks in Xcode, note the last column with checkboxes.

If you look inside kartoteka-reloaded.xcodeproj folder you will see how Xcode stores the schemes.
Here’s how it looks when kartoteka-reloaded.xcscheme is not shared

Notice how the kartoteka-reloaded.xcscheme moved from user data folder to shared data folder. This is basically what makes scheme a shared one.

The general practice for Xcode projects .gitignore file is to ignore user data

# .gitignore
xcuserdata/
*.xcuserdatad

So when you check out source code on a build box, there won’t be any user schemes inside .xcodeproj folder and xcodebuild won’t be able to see the schemes and will fail to build them.

Solution

You can solve this problem either manually or automatically.

Of course you can just talk to devs and ask them to share the scheme. Done!
You can even do this change yourself and create pull request with changes.

But this approach will not work in some cases. For example, if you want to run UI automation tests with Calabash, the steps are

Duplicate existing Xcode target and name new test target with -cal suffix

Add Calabash framework to test target

Build -cal test target and run tests

The first step is done with calabash-ios setup command. When new target is created a scheme is created for it as well. This is the default setting for all Xcode projects and in this post we’ll assume that’s the way you have it configured as well.

Now the tricky part, it doesn’t matter if original scheme was shared, the new -cal scheme will not be shared. That means you won’t be able to build it from command line.

Since it all happens on a build box as part of a build plan, you can’t push anything back to the repository, you have to find a way to make this new scheme shared right now.

The answer to your problems comes from Ruby world. In particular the xcodeproj Ruby gem. This is an incredibly handy library to work with Xcode projects and workspaces. You can do pretty much anything you need, create and modify targets and schemes, add new files to targets, modify build settings and other properties, and, of course, share schemes. By the way, xcodeproj is used by CocoaPods and that says a lot.

This is it! Put your Xcode project name in there, then run and the scheme will be shared.

chmod +x share_schemes.rb
./share_schemes.rb

Caveats

It sounds to good to be true, right?
There’s a number of situations where sharing a scheme via Ruby script will not work as expected.

If your Xcode project already has a shared scheme, then you will end up having one scheme from user’s data directory and another one form xcshareddata. Xcode IDE will pick up both and that’s the reason why you see same scheme twice with project name in parentheses.

That’s not very bad and doesn’t normally cause any problems. Until that moment of time when you modify one scheme and forget about another. The best way to avoid this problem is to share schemes from day 1, Xcode will not create user schemes then.

The real trouble begins if you didn’t have any shared schemes and the scheme that you want to recreate and share is linked to a test target. That’s the default configuration for unit tests. So the problem is that xcodeprojdoesn’t recreate dependencies to test target. If you run a xcodebuild test action you’ll be surprised to see it failing. Unfortunately there isn’t an easy workaround for this problem, so you’d better share those schemes manually and commit changes to source control system.

Summary

Surely the Ruby script can be improved, you’d want to pass Xcode project name as an argument or even look it up automatically.

As usual, in Summary I just provide file listing with a solution ready to copy-paste. Here’s more advanced Ruby script for your use. You can just get the file directly if you’d like, share-schemes.rb