Fixing Unity3D Build for iOS Issues

Unity vs. XCode - It doesn't have to be this way.One of the annoying things about the XCode requirement for Unity3D's "Build for iOS" capability is that with each new version of XCode (and sometimes OS X) Unity loses its ability to command XCode to build and run the project.

Here I summarize two solutions: a patch to make the XCode plugin load, and: a "Build for iOS" script that will work even if Unity is crashing when you use the regular "Build" button.

1. Plugin Patch

The XCode plugin within the Unity.app bundle requires a special identifier to be able to work with each version of XCode, specifically to be able to command XCode from the Unity development environment. Depending on the version of Unity, the plugin is stored in different locations:

  • Unity 4.0: Unity.app/Contents/BuildTargetTools/iPhonePlayer/Unity4XC.xcplugin
  • Unity 4.5: Unity.app/Contents/PlaybackEngines/iOSSupport/Tools/OSX/Unity4XC.xcplugin
  • Unity 5.x: Unity.app/Contents/PlaybackEngines/iossupport/Tools/OSX/Unity4XC.xcplugin

Editing the Property List file (Contents/Info.plist) in the plugin's bundle is pretty straightforward. You'll use XCode to do the job, as shown in this helpful video:

Once the plugin is patched, quit and relaunch XCode. The first time you launch XCode, you'll probably see a dialog that says "The 'Unity4XC.xcplugin' code bundle is not provided by Apple. Loading code not provided by Apple can have a negative effect on the safety and stability of XCode or related tools." You can just press the Load Plugin button to allow the plugin to load.

Quit XCode again (if you want). Now try building for iOS using the built-in Unity dialog or menu commands. If all is well Unity will do the usual thing: Ask for a destination folder, launch XCode, close all open Unity projects, and start the XCode build.

Plugin Doesn't Work?

I found that with Unity 5.1.0f3 on OS X 10.11 "El Capitan", the Build and Build And Run buttons both caused Unity to immediately crash. Whatever the cause, it's not good that Unity can't even start a build on the latest OS X. Fortunately, Unity allows us to add custom build commands to the editor, so that's what we'll do to get around this situation.

2. Build for iOS Editor Script

This is the script you've been looking for! The original BuildForiOS Script came to us from user QI (Spinach Studio) in the Unity3D Forum. It's a great solution that comes with good default build options. But what if you want to be able to configure build options on the fly?

Unity actually makes it really easy to set our build options. Set the iOS build options as usual in the Build Settings dialog. The script can read the options right from Build Settings and apply them to the build! The following modified script does just that:

/**
 * Editor/BuildForiOS.cs
 */
using UnityEditor;
using UnityEngine;
 
public class BuildForiOS : MonoBehaviour {

  static void _BuildForiOS(bool appendFlag=false, bool openInXCode=false) {

    if (EditorUserBuildSettings.selectedBuildTargetGroup != BuildTargetGroup.iOS) {
      Debug.LogError("<b>Build for iOS</b> requires <b>iOS Platform</b> to be selected.");
      return;
    }

    // Get all scenes from build setting UI.
    EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes;
    string[] scenesPath = new string[scenes.Length];
    for (int i = 0; i < scenesPath.Length; i++) scenesPath[i] = scenes[i].path;

    // Select the target folder
    string  previousPath = EditorPrefs.GetString("BuildForiOS.PreviousPath", Application.persistentDataPath),
            destination = EditorUtility.SaveFilePanel("Choose a destination", previousPath, EditorPrefs.GetString("BuildForiOS.Name",""), "");

    // Check if user canceled the action.
    if (!string.IsNullOrEmpty(destination)) {

      // Save settings for the next build.
      int lastSlash = destination.LastIndexOf("/");
      string path = destination.Substring(0, lastSlash), name = destination.Substring(lastSlash + 1);
      EditorPrefs.SetString("BuildForiOS.PreviousPath", path);
      EditorPrefs.SetString("BuildForiOS.Name", name);

      // Standard build options
      BuildOptions buildOps = BuildOptions.ShowBuiltPlayer | BuildOptions.Il2CPP;

      // Append?
      if (appendFlag) buildOps |= BuildOptions.AcceptExternalModificationsToPlayer;

      // Open in XCode?
      //
      // This may not work until Unity knows about XCode:
      //  - Copy the value of DVTPlugInCompatibilityUUID from XCode.app/Contents/Info.plist
      //  - Paste into Unity4XC.xcplugin/Contents/Info.plist in the Unity.app bundle
      //
      if (openInXCode) buildOps |= BuildOptions.AutoRunPlayer;

      // Additional options from Unity's "Build Settings" dialog
      if (EditorUserBuildSettings.symlinkLibraries) buildOps |= BuildOptions.SymlinkLibraries;
      if (EditorUserBuildSettings.development) {
        buildOps |= BuildOptions.Development;
        if (EditorUserBuildSettings.connectProfiler) buildOps |= BuildOptions.ConnectWithProfiler;
        if (EditorUserBuildSettings.allowDebugging) buildOps |= BuildOptions.AllowDebugging;
      }

      Debug.Log("BuildOptions = " + buildOps);

      // Build the player. May not open XCode without customizing Info.plist.
      BuildPipeline.BuildPlayer(scenesPath, destination, BuildTarget.iOS, buildOps);
    }

  }

  [MenuItem("File/Build for iOS/Build")]
  static void BuildForiOSDefault() { _BuildForiOS(); }

  [MenuItem("File/Build for iOS/Build (Append)")]
  static void BuildForiOSAppend() { _BuildForiOS(true); }

  [MenuItem("File/Build for iOS/Build and Open")]
  static void RunForiOS() { _BuildForiOS(false, true); }

  [MenuItem("File/Build for iOS/Build and Open (Append)")]
  static void RunForiOSAppend() { _BuildForiOS(true, true); }

}

Download this script here: BuildForiOS.cs.tar.gz. To install BuildForiOS in a Unity project, make a folder named "Editor" in your project's Assets folder. Decompress the Tar file and put BuildForiOS.cs into the "Editor" folder you just created. When Unity compiles this script, the editor gets a new Build for iOS sub-menu at the bottom of the File menu.

Test "Build and Open"

Even with the custom build script XCode could still crash due to changes in the XCode plugin architecture. This usually happens when Unity is "closing all open Unity XCode projects", crashing somewhere inside of PostProcessiPhonePlayer.LaunchInXcode.

If this happens, all you can do is avoid using the Build and Open commands. The Build and Build (Append) commands can still create the XCode project, but you'll have to go to the Finder, open the project, and build it manually in XCode.

Enable Bitcode Problem

After all this you might still get a build error in XCode that says something about ENABLE_BITCODE = Yes. If this happens, you'll need to go to the Project Navigator tab in XCode and edit the Unity-iPhone > Build Settings. Find Enable Bitcode and set it to No. Now the "Unity-iPhone" project should Build.