iosunity-game-enginebuild-automation

From Unity to iOS, how to perfectly automate frameworks, settings and plist?


in Unity3D when building to an iOS Xcode project,

how to perfectly automate all three of

Solution must have only the most modern 2019 syntax and variations, as this has changed slightly in Unity over the years.


Solution

  • IMPORTANT:

    Very unfortunately you can not use System.xml here as you would expect, since, Apple's plist format is insane. You probably have to use a munge.

    For 2019 ...

    enter image description here

    Filename, BuildPostProcessor.cs

    Put it in the folder Assets/Editor/ . (Just make the folder "Editor/" exactly there if it does not exist.)

    This shows how to do all three of frameworks, settings and plist.

    // filename BuildPostProcessor.cs
    // put it in a folder Assets/Editor/
    using System.IO;
    using UnityEngine;
    using UnityEditor;
    using UnityEditor.Callbacks;
    using UnityEditor.iOS.Xcode;
    
    public class BuildPostProcessor {
    
        [PostProcessBuild]
        public static void ChangeXcodePlist(BuildTarget buildTarget, string path) {
    
            if (buildTarget == BuildTarget.iOS) {
    
                string plistPath = path + "/Info.plist";
                PlistDocument plist = new PlistDocument();
                plist.ReadFromFile(plistPath);
    
                PlistElementDict rootDict = plist.root;
    
                Debug.Log(">> Automation, plist ... <<");
    
                // example of changing a value:
                // rootDict.SetString("CFBundleVersion", "6.6.6");
    
                // example of adding a boolean key...
                // < key > ITSAppUsesNonExemptEncryption </ key > < false />
                rootDict.SetBoolean("ITSAppUsesNonExemptEncryption", false);
    
                File.WriteAllText(plistPath, plist.WriteToString());
            }
        }
    
        [PostProcessBuildAttribute(1)]
        public static void OnPostProcessBuild(BuildTarget target, string path) {
    
            if (target == BuildTarget.iOS) {
    
                PBXProject project = new PBXProject();
                string sPath = PBXProject.GetPBXProjectPath(path);
                project.ReadFromFile(sPath);
    
                string tn = PBXProject.GetUnityTargetName();
                string g = project.TargetGuidByName(tn);
    
                ModifyFrameworksSettings(project, g);
    
                // modify frameworks and settings as desired
                File.WriteAllText(sPath, project.WriteToString());
            }
        }
    
        static void ModifyFrameworksSettings(PBXProject project, string g) {
    
            // add hella frameworks
    
            Debug.Log(">> Automation, Frameworks... <<");
    
            project.AddFrameworkToProject(g, "blah.framework", false);
            project.AddFrameworkToProject(g, "libz.tbd", false);
    
            // go insane with build settings
    
            Debug.Log(">> Automation, Settings... <<");
    
            project.AddBuildProperty(g,
                "LIBRARY_SEARCH_PATHS",
                "../blahblah/lib");
    
            project.AddBuildProperty(g,
                "OTHER_LDFLAGS",
                "-lsblah -lbz2");
    
            // note that, due to some Apple shoddyness, you usually need to turn this off
            // to allow the project to ARCHIVE correctly (ie, when sending to testflight):
            project.AddBuildProperty(g,
                "ENABLE_BITCODE",
                "false");
        }
    
    }
    

    That will do it.

    Note - the final part of the puzzle is copying across files (perhaps data files or text files). In reality it's best to just use the "StreamingAssets/" approach, explained fully in this QA.