XCodeEditor for Unity

in Projects

XCode project editor

Today I want to talk about the Xcode Project Editor for Unity that I recently released on GitHub. This year I spent most of my coding time writing custom plugins for Unity to interface our projects with different SDKs for iOS and Android. The biggest issue I bumped into was to automate the build process for custom libraries. The purpose of this project is to programmatically edit an XCode 4 project, directly within Unity, for the ones who need more control of the build process on iOS and Mac.

Reinventing the wheel

The PostProcessBuild script that is automatically executed at build time is a great help, and there are any official tools out there to edit xcode projects by script. After googlin’ around I came across a blog post about a python script by Calvin Rien that fills this gap perfectly. It consists in two main components: a library to read and edit a XCode project file, and a proper PostProcessBuild script to automate the workflow. I’ve used it for all my custom plugins on iOS, until Unity 3.5 released.

Unity 3.5 finally allows to write your postprocess scripts in C# too by the new PostProcessBuild attribute. There is nothing bad about the python editor library, but the new attribute opens a lot more customization opportunities, and any issues on the platform you are running your build process. I found much useful having a C# version of the library with little some changes.

The code is released under MIT license, is open and free to use. Although it’s still under development and needs more testing. and comments are welcome.

The xcodeproject container

Xcode projects are just container folders; it is a common behavior on OSX, just think about the applications and iPhoto. The real project structure data is the project.pbxproj file, inside the main xcodeproj container. There is very little documentation on the pbxproj file format (that is a custom structure of a OpenStep plist file). The PBXParser.cs is in charge to read and write the project file.

Installation

Clone the GitHub repo somewhere under Assets/Editor in your project. If your project is not yet checked into git, then you’ll need to do the appropriate setup and add this as a submodule (google: git-submodule). If you already use git for your project, then just add this as a submodule.

For the ones that are not used to git repositories, or that just want to give it a try without setting up everything, there is a unitypackage ready for an easy import.

Usage

You can use the XCProject class in any part of your editor and postprocess code. Taking advantage of the great powers of the new PostProcessBuild attribute, I suggest to use a small cs static class to run through all the projmods files in your asses folder and simply apply them to the newly created xcode project.

using UnityEditor;

public static class XCodePostProcess
{
	[PostProcessBuild]
	public static void OnPostProcessBuild( BuildTarget target, string path )
	{
		// Create a new project object from build target
		XCodeEditor.XCProject project = new XCodeEditor.XCProject( targetPath );

		// Find and run through all projmods files to patch the project
		var files = System.IO.Directory.GetFiles( Application.dataPath, "*.projmods", SearchOption.AllDirectories );
		foreach( var file in files ) {
			project.ApplyMod( file );
		}

		// Finally save the xcode project
		project.Save();
	}
}

The projmods file is a simple text file containing a JSON object. It will be used to pass the parameters to the ApplyMod method. This is the file I use for the GameCenter plugin as a brief example:

{
	"group": "GameCenter",
	"libs": [],
	"frameworks": ["GameKit.framework"],
	"headerpaths": ["Editor/iOS/GameCenter/**"],					
	"files":   ["Editor/iOS/GameCenter/GameCenterBinding.m",
				"Editor/iOS/GameCenter/GameCenterController.h",
				"Editor/iOS/GameCenter/GameCenterController.mm",
				"Editor/iOS/GameCenter/GameCenterManager.h",
				"Editor/iOS/GameCenter/GameCenterManager.m"],
	"folders": [],	
	"excludes": ["^.*.meta$", "^.*.mdown^", "^.*.pdf$"]
}
  • group: all files and folders will be parented to this group;
  • libs: add libraries to build phase;
  • frameworks: add frameworks to the project;
  • headerpaths: add header paths to build phase;
  • files: add single files to the project;
  • folders: create a subgroup and add all files to the project (recursive);
  • excludes: file mask to exclude;
Note: all paths are relative to projmods location

Leave a Reply

  1. I found your git hub source before finding your blog posting…duh…One thing that may throw people off is I think the MiniJSON script being used is the Prime31 one not Calvin’s(Darktable). I haven’t had a chance to take a whack at getting this working yet (besides fixing the missing script reference) but I will let you know if it breaks…

  2. I found this code very useful for my Unity project. I had to integrate an xcode library into the unity exported xcode project as a plugin. Also I added some features to modify some additional xcode project entries.

    • I’m happy it comes in handy, and I’m sure it will be good to integrate your upgrades for everyone use. Why don’t you send a pull request to the GitHub repository?

  3. Thank you very much for making this. However, I am having a hard time figuring out where we are supposed to place the json file. If any could help me figure that out I would really appreciate it.

  4. Since someone has already mentioned Prime31, I found that code similar to the example did not work in conjunction with Prime31′s post build steps. In fact, it worked perfectly, but caused the subsequent Prime31 post build step to NOT work. The solution is to ensure that the Prime31 step happens first, and to do that you simply need to modify line 5 of the example script to this:

    [PostProcessBuild(999)]