/* * Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace iPhonePackager { internal class Config { /// /// The display name in title bars, popups, etc... /// public static string AppDisplayName = "Unreal iOS Configuration"; public static string RootRelativePath = @"..\..\..\..\"; public static string GameDirectory = ""; // "..\\..\\..\\..\\Engine\\Source\\UE4"; public static string BinariesDirectory = ""; // "..\\..\\..\\..\\Engine\\Binaries\\IOS\\" /// /// Optional Prefix to append to .xcent and .mobileprovision files, for handling multiple certificates on same source game /// public static string SigningPrefix = ""; public static string PCStagingRootDir = ""; /// /// The local staging directory for files needed by Xcode on the Mac (on PC) /// public static string PCXcodeStagingDir = ""; /// /// The staging directory from UAT that is passed into IPP (for repackaging, etc...) /// public static string RepackageStagingDirectory = ""; /// /// The project root directory that is passed into IPP from UAT /// public static string ProjectRootDirectory = ""; /// /// The device to deploy or launch on /// public static string DeviceId = ""; /// /// The local build directory (on PC) /// public static string BuildDirectory { get { string StandardGameBuildDir = GameDirectory + @"\Build\IOS"; // if the normal Build dir exists, return it, otherwise, use the program Resources directory return Path.GetFullPath(Directory.Exists(StandardGameBuildDir) ? StandardGameBuildDir : GameDirectory + @"\Resources\IOS"); } } /// /// The shared (Engine) build directory (on PC) /// public static string EngineBuildDirectory { get { return Path.GetFullPath(RootRelativePath + @"Engine\Build\IOS"); } } /// /// The local directory cooked files are placed (on PC) /// public static string CookedDirectory { get { return Path.GetFullPath(GameDirectory + @"\Saved\Cooked\IOS"); } } /// /// The local directory config files are placed (on PC) /// public static string ConfigDirectory { get { return Path.GetFullPath(GameDirectory + @"\Saved\Config"); } } /// /// The engine config files are placed (on PC) /// public static string DefaultConfigDirectory { get { return Path.GetFullPath(RootRelativePath + @"Engine\Config"); } } /// /// The local directory that a payload (GameName.app) is assembled into before being copied to the Mac (on PC) /// //@TODO: Deprecate this directory public static string PayloadDirectory { get { return Path.GetFullPath(PCStagingRootDir + @"\Payload\" + Program.GameName + Program.Architecture + ".app"); } } /// /// The local directory that a payload (GameName.app) is assembled into before being copied to the Mac (on PC) /// public static string PayloadCookedDirectory { get { return Path.GetFullPath(PayloadDirectory + @"\cookeddata"); } } /// /// The local directory that a payload (GameName.app) is assembled into before being copied to the Mac (on PC) /// public static string PayloadRootDirectory { get { return Path.GetFullPath(PCStagingRootDir + @"\Payload"); } } /// /// Returns the filename for the IPA (no path, just filename) /// public static string IPAFilenameOnMac { get { if (Program.GameConfiguration == "Development") { return SigningPrefix + Program.GameName + Program.Architecture + ".ipa"; } else { return SigningPrefix + Program.GameName + "-IOS-" + Program.GameConfiguration + Program.Architecture + ".ipa"; } } } /// /// Returns the name of the file containing user overrides that will be applied when packaging on PC /// public static string GetPlistOverrideFilename() { return GetPlistOverrideFilename(false); } public static string GetPlistOverrideFilename(bool bWantDistributionOverlay) { string Prefix = ""; if (bWantDistributionOverlay) { Prefix = "Distro_"; } return Path.Combine(BuildDirectory, Prefix + Program.GameName + "Overrides.plist"); } /// /// Returns the full path for either the stub or final IPA on the PC /// public static string GetIPAPath(string FileSuffix) { // Quash the default Epic_ so that stubs for UDK installers get named correctly and can be used string FilePrefix = (SigningPrefix == "Epic_") ? "" : SigningPrefix; string Filename; if (Program.GameConfiguration == "Development") { Filename = Path.Combine(Config.BinariesDirectory, FilePrefix + Program.GameName + Program.Architecture + FileSuffix); } else { Filename = Path.Combine(Config.BinariesDirectory, FilePrefix + Program.GameName + "-IOS-" + Program.GameConfiguration + Program.Architecture + FileSuffix); } return Filename; } public static string RemapIPAPath(string FileSuffix) { // Quash the default Epic_ so that stubs for UDK installers get named correctly and can be used string FilePrefix = (SigningPrefix == "Epic_") ? "" : SigningPrefix; string Filename; string BinariesDir = BinariesDirectory; string GameName = Program.GameName; if (!String.IsNullOrEmpty(ProjectRootDirectory)) { BinariesDir = Path.Combine(ProjectRootDirectory, "Binaries", "IOS"); GameName = ProjectRootDirectory.Substring(ProjectRootDirectory.LastIndexOfAny(new char[] { '\\', '/' }) + 1); } if (Program.GameConfiguration == "Development") { Filename = Path.Combine(BinariesDir, FilePrefix + GameName + Program.Architecture + FileSuffix); } else { Filename = Path.Combine(BinariesDir, FilePrefix + GameName + "-IOS-" + Program.GameConfiguration + Program.Architecture + FileSuffix); } // ensure the directory exists return Filename; } /// /// Returns the full path for the stub IPA, following the signing prefix resolution rules /// public static string GetIPAPathForReading(string FileSuffix) { if (Program.GameConfiguration == "Development") { return FileOperations.FindPrefixedFile(Config.BinariesDirectory, Program.GameName + Program.Architecture + FileSuffix); } else { return FileOperations.FindPrefixedFile(Config.BinariesDirectory, Program.GameName + "-IOS-" + Program.GameConfiguration + Program.Architecture + FileSuffix); } } /// /// Whether or not to allow interactive dialogs to pop up when a traditionally non-interactive command was specified /// (e.g., can we pop up a configuration dialog during PackageIPA?) /// public static bool bAllowInteractiveDialogsDuringNonInteractiveCommands = false; /// /// Whether or not to output extra information (like every file copy and date/time stamp) /// public static bool bVerbose = true; /// /// Whether or not to output extra information in code signing /// public static bool bCodeSignVerbose = false; /// /// Whether or not non-critical files will be packaged (critical == required for signing or .app validation, the app may still fail to /// run with only 'critical' files present). Also affects the name and location of the IPA back on the PC /// public static bool bCreateStubSet = false; /// /// Is this a distribution packaging build? Controls a number of aspects of packing (which signing prefix and provisioning profile to use, etc...) /// public static bool bForDistribution = false; /// /// Whether or not to strip symbols (they will always be stripped when packaging for distribution) /// public static bool bForceStripSymbols = false; /// /// Do a code signing update when repackaging? /// public static bool bPerformResignWhenRepackaging = false; /// /// Whether the cooked data will be cooked on the fly or was already cooked by the books. /// public static bool bCookOnTheFly = false; /// /// An override server Mac name /// public static string OverrideMacName = null; /// /// A name to use for the bundle indentifier and display name when resigning /// public static string OverrideBundleName = null; /// /// Whether to use None or Best for the compression setting when repackaging IPAs (int version of Ionic.Zlib.CompressionLevel) /// By making this an int, we are able to delay load the Ionic assembly from a different path (which is required) /// public static int RecompressionSetting = 0; //Ionic.Zlib.CompressionLevel.None; /// /// Returns the application directory inside the zip /// public static string AppDirectoryInZIP { get { return String.Format("Payload/{0}{1}.app", Program.GameName, Program.Architecture); } } /// /// If the requirements blob is present in the existing executable when code signing, should it be carried forward /// (true) or should a dummy requirements blob be created with no actual requirements (false) /// public static bool bMaintainExistingRequirementsWhenCodeSigning = false; /// /// The code signing identity to use when signing via RPC /// public static string CodeSigningIdentity; /// /// The minimum OS version /// public static string MinOSVersion; /// /// Returns a path to the place to back up documents from a device /// /// public static string GetRootBackedUpDocumentsDirectory() { return Path.GetFullPath(Path.Combine(GameDirectory + @"\IOS_Backups")); } public static bool Initialize(string InitialCurrentDirectory, string GamePath) { bool bIsEpicInternal = File.Exists(@"..\..\EpicInternal.txt"); // if the path is a directory (relative to where the game was launched from), then get the absolute directory string FullGamePath = Path.GetFullPath(Path.Combine(InitialCurrentDirectory, GamePath)); string OrigGamePath = GamePath; if (Directory.Exists(FullGamePath)) { GameDirectory = FullGamePath; } // is it a file? if so, just use the file's directory else if (File.Exists(FullGamePath)) { GameDirectory = Path.GetDirectoryName(FullGamePath); } // else we assume old school game name and look for it else { GameDirectory = Path.GetFullPath(Path.Combine(Config.RootRelativePath, Program.GameName)); } if (!Directory.Exists(GameDirectory)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(); Console.WriteLine("Unable to find a game or program {0}. You may need to specify a path to the program", OrigGamePath); Console.ResetColor(); return false ; } // special case handling for anything inside Engine/Source, it will go to the Engine/Binaries directory, not the Game's binaries directory if (OrigGamePath.Replace("\\", "/").Contains("Engine/Source")) { BinariesDirectory = Path.Combine(RootRelativePath, @"Engine\Binaries\IOS\"); } else if (!OrigGamePath.Contains(@"Binaries\IOS")) { // no sense in adding Binaries\IOS when it's already there. This is a special case to handle packaging UnrealLaunchDaemon from the command line. BinariesDirectory = Path.Combine(GameDirectory, @"Binaries\IOS\"); } else { BinariesDirectory = GameDirectory; } // Root directory on PC for staging files to copy to Mac Config.PCStagingRootDir = String.Format(@"{0}\Engine\Intermediate\IOS-Deploy\{1}\{2}{3}\", RootRelativePath, Program.GameName, Program.GameConfiguration, Program.Architecture); // make a directory for the shared XcodeSupportFiles directory Config.PCXcodeStagingDir = Config.PCStagingRootDir + @"..\XcodeSupportFiles"; // Code signing identity // Rules: // An environment variable wins if set // Otherwise for internal development builds, an internal identity is used // Otherwise, developer or distribution are used // Distro builds won't succeed on a machine with multiple distro certs installed unless the environment variable is set. Config.CodeSigningIdentity = Config.bForDistribution ? "iPhone Distribution" : "iPhone Developer"; if (Config.bForDistribution) { Config.CodeSigningIdentity = Utilities.GetEnvironmentVariable("ue.IOSDistributionSigningIdentity", Config.CodeSigningIdentity); } else { Config.CodeSigningIdentity = Utilities.GetEnvironmentVariable("ue.IOSDeveloperSigningIdentity", Config.CodeSigningIdentity); } // Remember to also change the default min version in UBT (iPhoneToolChain.cs) Config.MinOSVersion = Utilities.GetEnvironmentVariable("ue3.iPhone_MinOSVersion", "6.0"); // look for the signing prefix environment variable string DefaultPrefix = ""; if (bIsEpicInternal) { // default Epic to "Epic_" prefix DefaultPrefix = "Epic_"; } if (Config.bForDistribution) { DefaultPrefix = "Distro_"; } Config.SigningPrefix = Utilities.GetEnvironmentVariable("ue.IOSSigningPrefix", DefaultPrefix); // Windows doesn't allow environment vars to be set to blank so detect "none" and treat it as such if (Config.SigningPrefix == "none") { Config.SigningPrefix = Config.bForDistribution ? "Distro_" : ""; } CompileTime.ConfigurePaths(); return true; } } }