Upon moving a couple of recent projects to 2020.4, we learned that recent versions of Unity apparently have problems when exporting iOS applications. They’ll run and test fine, but upon uploading to the App Store, you’ll get an error. This reads:
Invalid Bundle. The bundle at 'my.app/Frameworks/UnityFramework.framework' contains disallowed file 'Frameworks'.
We spent a long while trying suggestions on forum threads and reviewing the build behavior before we came up with a solution that works for us. This also handles a further error we got after submitting the iOS app, which reads:
Invalid Swift Support - The SwiftSupport folder is empty. Rebuild your app using the current public (GM) version of Xcode and resubmit it.
You can use the solution we created by saving the below code out to a file called UpdateXcodeBuildSystemPostProcessor.cs and putting it in your project’s assets/editor folder.
using System.IO;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
#if UNITY_IOS || UNITY_TVOS
// Create specific aliases for iOS.Xcode imports.
// Unity Editor on macOS can report a conflict with other plugins
using PlistDocument = UnityEditor.iOS.Xcode.PlistDocument;
using PlistElementDict = UnityEditor.iOS.Xcode.PlistElementDict;
#endif
public class UpdateXcodeBuildSystemPostProcessor : MonoBehaviour
{
[PostProcessBuild(999)]
public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
{
if (buildTarget == BuildTarget.iOS || buildTarget == BuildTarget.tvOS)
{
UpdateXcodeBuildSystem(path);
}
}
private static void UpdateXcodeBuildSystem(string projectPath)
{
string workspaceSettingsPath = Path.Combine(projectPath,
"Unity-iPhone.xcodeproj/project.xcworkspace/xcshareddata/" +
"WorkspaceSettings.xcsettings");
if (File.Exists(workspaceSettingsPath))
{
// Read the plist document, and find the root element
PlistDocument workspaceSettings = new PlistDocument();
workspaceSettings.ReadFromFile(workspaceSettingsPath);
PlistElementDict root = workspaceSettings.root;
// Modify the document as necessary.
bool workspaceSettingsChanged = false;
// Remove the BuildSystemType entry because it specifies the
// legacy Xcode build system, which is deprecated
if (root.values.ContainsKey("BuildSystemType"))
{
root.values.Remove("BuildSystemType");
workspaceSettingsChanged = true;
}
// If actual changes to the document occurred, write the result
// back to disk.
if (workspaceSettingsChanged)
{
Debug.Log("UpdateXcodeBuildSystem: Writing updated " +
"workspace settings to disk.");
try
{
workspaceSettings.WriteToFile(workspaceSettingsPath);
}
catch (System.Exception e)
{
Debug.LogError(string.Format("UpdateXcodeBuildSystem: " +
"Exception occurred writing workspace settings to " +
"disk: \n{0}",
e.Message));
throw;
}
}
else
{
Debug.Log("UpdateXcodeBuildSystem: workspace settings did " +
"not require modifications.");
}
}
else
{
Debug.LogWarningFormat("UpdateXcodeBuildSystem: could not find " +
"workspace settings files [{0}]",
workspaceSettingsPath);
}
// Get the path to the Xcode project
string pbxProjectPath = PBXProject.GetPBXProjectPath(projectPath);
var pbxProject = new PBXProject();
// Open the Xcode project
pbxProject.ReadFromFile(pbxProjectPath);
// Get the UnityFramework target GUID
string unityFrameworkTargetGuid =
pbxProject.GetUnityFrameworkTargetGuid();
// Modify the Swift version in the UnityFramework target to a
// compatible string
pbxProject.SetBuildProperty(unityFrameworkTargetGuid,
"SWIFT_VERSION", "5.0");
// Write out the Xcode project
pbxProject.WriteToFile(pbxProjectPath);
Debug.Log("UpdateXcodeBuildSystem: update Swift version in Xcode " +
"project.");
}
}
We do two things here:
- Unity writes out the Xcode project using Xcode’s “Legacy Build System”, which is currently deprecated in Xcode 12.5.1 where this was tested. We remove the “BuildSystemType” key from the Xcode workspace settings so that Xcode uses the default build system.
- Once Xcode is using the default build system, it no longer recognizes the format of the Swift version that Unity writes out in the Xcode project. Unity writes something like “5 0 5 1”, but Xcode expects “5.0”. So we forcibly set the Swift version to a value Xcode currently understands.
You could do this manually. After making a Unity build for iOS, you would open the Xcode project, go to the File menu, select Project Settings, and change the Build System in the drop-down menu there. Changing this through Xcode will automatically fix the Swift version value.
Thanks to everyone on the various Unity forum threads who have been wrestling with this problem.
Thanks also to user uannoymejo on this forum thread for bringing up the Xcode build system.