The Swift Package Manager is a really neat way to manage framework usage between Swift apps. However it has no direct support to build Cocoa applications. It is possible to use the SPM with Cocoa applications. This post shows how we do it.

The problem

The problem boils down to this: the package manager can generate Xcode projects, but only console applications. Not Cocoa applications.

Once an Xcode project has been generated we can add a Cocoa target. However when the dependencies change it is necessary to re-generate the Xcode project. Which -when done- will no longer contain the Cocoa target.

The easy way

This method boils down to “never regenerate the project”. For simple projects this should be feasible.

  • Using the SPM create a new executable project but do not use the envisioned name for the Cocoa project.
  • Fill out the package manifest to contain the frameworks that are needed.
  • Using the SPM create the Xcode project.
  • In Xcode, build the project (this compiles the frameworks).
  • In Xcode, add a new Cocoa target and give it the envisioned name.
  • In Xcode, add the frameworks to the Cocoa target as ‘embedded binaries’.

It may happen that frameworks are updated, when that happens, do NOT regenerate the Xcode project but do the following:

  • At the command line run the SPM ‘update’ command. This will update the frameworks.
  • In Xcode, build the non-Cocoa target to regenerate the frameworks.
  • Recommended: update the framework version number in the Xcode file navigator (only for clarity)
  • Switch to the Cocoa target, and rebuild it.

This method is easy and fast but does not allow for changes to be made to the dependency structure. I.e. it cannot be used to add frameworks to the Cocoa target. If that becomes necessary the hard way must be used.

The hard way

The hard way builds on the easy way. So everything that was done above, also applies here.

But when a framework must be added to the project the following steps should be followed:

Precondition: You must be using git.

  • Before doing anything, first commit all changes to git. This can be done in Xcode.
  • Add the new framework to the package manifest. This can be done in Xcode.
  • Exit Xcode.
  • Delete the your-project-name.xcodeproj file from the project directory.
  • Run the SPM update command.
  • Run the SPM generate-xcodeproj command (creating the same project as before).
  • Open the newly created Xcode project.
  • Create the Cocoa target again (with the same name as before)

Now you will see a blue folder and a yellow folder with the same name (target). And there will be a number of files with a ‘M’ behind them.

  • Select all files with an ‘M’ behind them (except for the project at the top) and right-click, select “Source Control -> Discard changes”. This restores the files from the previous target getting you back to where you were before adding the new framework(s).
  • Recommended: Move the files in the blue folder that are not already in the yellow folder (of the same name) to the yellow folder. And delete the references! of the blue folder afterwards.
  • Add the frameworks to the Cocoa target again (like above the easy way)
  • If you made any changes to the project settings, you will need to reapply them. (Like for example a bridging header file)