public static bool GenerateIOSPList(string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, UEDeployIOS InThis = null)
        {
            // generate the Info.plist for future use
            string BuildDirectory        = ProjectDirectory + "/Build/IOS";
            bool   bSkipDefaultPNGs      = false;
            string IntermediateDirectory = (bIsUE4Game ? InEngineDir : ProjectDirectory) + "/Intermediate/IOS";
            string PListFile             = IntermediateDirectory + "/" + GameName + "-Info.plist";

            ProjectName = !String.IsNullOrEmpty(ProjectName) ? ProjectName : GameName;
            VersionUtilities.BuildDirectory = BuildDirectory;
            VersionUtilities.GameName       = GameName;

            // read the old file
            string OldPListData = File.Exists(PListFile) ? File.ReadAllText(PListFile) : "";

            // determine if there is a launch.xib
            string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib";

            if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib"))
            {
                LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib";
            }

            // get the settings from the ini file
            // plist replacements
            DirectoryReference DirRef = bIsUE4Game ? (!string.IsNullOrEmpty(UnrealBuildTool.GetRemoteIniPath()) ? new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()) : null) : new DirectoryReference(ProjectDirectory);
            ConfigCacheIni     Ini    = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", DirRef);

            // orientations
            string SupportedOrientations = "";
            bool   bSupported            = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsPortraitOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortrait</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsUpsideDownOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeLeftOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeRightOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n" : "";

            // bundle display name
            string BundleDisplayName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleDisplayName", out BundleDisplayName);

            // bundle identifier
            string BundleIdentifier;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

            // bundle name
            string BundleName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleName", out BundleName);

            // disable https requirement
            bool bDisableHTTPS;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDisableHTTPS", out bDisableHTTPS);

            // short version string
            string BundleShortVersion;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "VersionInfo", out BundleShortVersion);

            // required capabilities
            string RequiredCaps = "";

            if (InThis != null)
            {
                // required capabilities
                RequiredCaps += InThis.IOSPlatformContext.GetRequiredCapabilities();
            }

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsOpenGLES2", out bSupported);
            RequiredCaps += bSupported ? "\t\t<string>opengles-2</string>\n" : "";
            if (!bSupported)
            {
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsMetal", out bSupported);
                RequiredCaps += bSupported ? "\t\t<string>metal</string>\n" : "";
            }

            // minimum iOS version
            string MinVersion;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
            {
                switch (MinVersion)
                {
                case "IOS_61":
                    Log.TraceWarning("IOS 6 is no longer supported in UE4 as 4.11");
                    MinVersion = "7.0";
                    break;

                case "IOS_7":
                    MinVersion = "7.0";
                    break;

                case "IOS_8":
                    MinVersion = "8.0";
                    break;

                case "IOS_9":
                    MinVersion = "9.0";
                    break;
                }
            }
            else
            {
                MinVersion = "7.0";
            }

            // Get Facebook Support details
            bool bEnableFacebookSupport = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableFacebookSupport", out bEnableFacebookSupport);

            // Write the Facebook App ID if we need it.
            string FacebookAppID = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "FacebookAppID", out FacebookAppID);
            bEnableFacebookSupport = bEnableFacebookSupport && !string.IsNullOrWhiteSpace(FacebookAppID);

            // Add remote-notifications as background mode
            bool bRemoteNotificationsSupported = false;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableRemoteNotificationsSupport", out bRemoteNotificationsSupported);

            // extra plist data
            string ExtraData = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalPlistData", out ExtraData);

            // generate the plist file
            StringBuilder Text = new StringBuilder();

            Text.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            Text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
            Text.AppendLine("<plist version=\"1.0\">");
            Text.AppendLine("<dict>");
            Text.AppendLine("\t<key>CFBundleURLTypes</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleURLName</key>");
            Text.AppendLine("\t\t\t<string>com.Epic.Unreal</string>");
            Text.AppendLine("\t\t\t<key>CFBundleURLSchemes</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine(string.Format("\t\t\t\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            if (bEnableFacebookSupport)
            {
                // This is needed for facebook login to redirect back to the app after completion.
                Text.AppendLine(string.Format("\t\t\t\t<string>fb{0}</string>", FacebookAppID));
            }
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleDevelopmentRegion</key>");
            Text.AppendLine("\t<string>English</string>");
            Text.AppendLine("\t<key>CFBundleDisplayName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleDisplayName, ProjectName)));
            Text.AppendLine("\t<key>CFBundleExecutable</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            Text.AppendLine("\t<key>CFBundleIdentifier</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleIdentifier.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "")));
            Text.AppendLine("\t<key>CFBundleInfoDictionaryVersion</key>");
            Text.AppendLine("\t<string>6.0</string>");
            Text.AppendLine("\t<key>CFBundleName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleName, ProjectName)));
            Text.AppendLine("\t<key>CFBundlePackageType</key>");
            Text.AppendLine("\t<string>APPL</string>");
            Text.AppendLine("\t<key>CFBundleSignature</key>");
            Text.AppendLine("\t<string>????</string>");
            Text.AppendLine("\t<key>CFBundleVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", VersionUtilities.UpdateBundleVersion(OldPListData)));
            Text.AppendLine("\t<key>CFBundleShortVersionString</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleShortVersion));
            Text.AppendLine("\t<key>LSRequiresIPhoneOS</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIStatusBarHidden</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIRequiresFullScreen</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIViewControllerBasedStatusBarAppearance</key>");
            Text.AppendLine("\t<false/>");
            Text.AppendLine("\t<key>UISupportedInterfaceOrientations</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in SupportedOrientations.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>UIRequiredDeviceCapabilities</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in RequiredCaps.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleIcons</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon57.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
            Text.AppendLine("\t\t\t<true/>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</dict>");
            Text.AppendLine("\t<key>CFBundleIcons~ipad</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon50.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon72.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon76.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
            Text.AppendLine("\t\t\t<true/>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</dict>");
            if (File.Exists(LaunchXib))
            {
                // TODO: compile the xib via remote tool
                Text.AppendLine("\t<key>UILaunchStoryboardName</key>");
                Text.AppendLine("\t<string>LaunchScreen</string>");
                bSkipDefaultPNGs = true;
            }
            else
            {
                // this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist
                // eventually we want to generate this based on what the user has set in the project settings
                string[] IPhoneConfigs =
                {
                    "Default-IPhone6-Landscape",     "Landscape", "{375, 667}", "8.0",
                    "Default-IPhone6",               "Portrait",  "{375, 667}", "8.0",
                    "Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}", "8.0",
                    "Default-IPhone6Plus-Portrait",  "Portrait",  "{414, 736}", "8.0",
                    "Default",                       "Landscape", "{320, 480}", "7.0",
                    "Default",                       "Portrait",  "{320, 480}", "7.0",
                    "Default-568h",                  "Landscape", "{320, 568}", "7.0",
                    "Default-568h",                  "Portrait",  "{320, 568}", "7.0",
                };

                Text.AppendLine("\t<key>UILaunchImages~iphone</key>");
                Text.AppendLine("\t<array>");
                for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 4)
                {
                    Text.AppendLine("\t\t<dict>");
                    Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 3]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
                    Text.AppendLine("\t\t</dict>");
                }

                // close it out
                Text.AppendLine("\t</array>");

                // this is a temp way to inject the iPad Pro without needing to upgrade everyone's plist
                // eventually we want to generate this based on what the user has set in the project settings
                string[] IPadConfigs =
                {
                    "Default-Landscape",      "Landscape", "{768, 1024}",  "7.0",
                    "Default-Portrait",       "Portrait",  "{768, 1024}",  "7.0",
                    "Default-Landscape-1336", "Landscape", "{1024, 1366}", "9.0",
                    "Default-Portrait-1336",  "Portrait",  "{1024, 1366}", "9.0",
                };

                Text.AppendLine("\t<key>UILaunchImages~ipad</key>");
                Text.AppendLine("\t<array>");
                for (int ConfigIndex = 0; ConfigIndex < IPadConfigs.Length; ConfigIndex += 4)
                {
                    Text.AppendLine("\t\t<dict>");
                    Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 3]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 0]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 1]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 2]));
                    Text.AppendLine("\t\t</dict>");
                }
                Text.AppendLine("\t</array>");
            }
            Text.AppendLine("\t<key>CFBundleSupportedPlatforms</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<string>iPhoneOS</string>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>MinimumOSVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", MinVersion));
            // disable exempt encryption
            Text.AppendLine("\t<key>ITSAppUsesNonExemptEncryption</key>");
            Text.AppendLine("\t<false/>");

            // disable HTTPS requirement
            if (bDisableHTTPS)
            {
                Text.AppendLine("\t<key>NSAppTransportSecurity</key>");
                Text.AppendLine("\t\t<dict>");
                Text.AppendLine("\t\t\t<key>NSAllowsArbitraryLoads</key><true/>");
                Text.AppendLine("\t\t</dict>");
            }

            if (bEnableFacebookSupport)
            {
                Text.AppendLine("\t<key>FacebookAppID</key>");
                Text.AppendLine(string.Format("\t<string>{0}</string>", FacebookAppID));
            }
            if (!string.IsNullOrEmpty(ExtraData))
            {
                ExtraData = ExtraData.Replace("\\n", "\n");
                foreach (string Line in ExtraData.Split("\r\n".ToCharArray()))
                {
                    if (!string.IsNullOrWhiteSpace(Line))
                    {
                        Text.AppendLine("\t" + Line);
                    }
                }
            }

            // Add remote-notifications as background mode
            if (bRemoteNotificationsSupported)
            {
                Text.AppendLine("\t<key>UIBackgroundModes</key>");
                Text.AppendLine("\t<array>");
                Text.AppendLine("\t\t<string>remote-notification</string>");
                Text.AppendLine("\t</array>");
            }

            Text.AppendLine("</dict>");
            Text.AppendLine("</plist>");

            // Create the intermediate directory if needed
            if (!Directory.Exists(IntermediateDirectory))
            {
                Directory.CreateDirectory(IntermediateDirectory);
            }

            if (InThis != null && InThis.UPL != null)
            {
                // Allow UPL to modify the plist here
                XDocument XDoc;
                try
                {
                    XDoc = XDocument.Parse(Text.ToString());
                }
                catch (Exception e)
                {
                    throw new BuildException("plist is invalid {0}\n{1}", e, Text.ToString());
                }

                XDoc.DocumentType.InternalSubset = "";
                InThis.UPL.ProcessPluginNode("None", "iosPListUpdates", "", ref XDoc);
                string result = XDoc.Declaration.ToString() + "\n" + XDoc.ToString().Replace("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"[]>", "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
                File.WriteAllText(PListFile, result);
            }
            else
            {
                File.WriteAllText(PListFile, Text.ToString());
            }

            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
            {
                if (!Directory.Exists(AppDirectory))
                {
                    Directory.CreateDirectory(AppDirectory);
                }
                File.WriteAllText(AppDirectory + "/Info.plist", Text.ToString());
            }

            return(bSkipDefaultPNGs);
        }
Пример #2
0
		public static bool GenerateIOSPList(string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, UEDeployIOS InThis = null)
		{
			// generate the Info.plist for future use
			string BuildDirectory = ProjectDirectory + "/Build/IOS";
			bool bSkipDefaultPNGs = false;
			string IntermediateDirectory = (bIsUE4Game ? InEngineDir : ProjectDirectory) + "/Intermediate/IOS";
			string PListFile = IntermediateDirectory + "/" + GameName + "-Info.plist";
			ProjectName = !String.IsNullOrEmpty(ProjectName) ? ProjectName : GameName;
			VersionUtilities.BuildDirectory = BuildDirectory;
			VersionUtilities.GameName = GameName;

			// read the old file
			string OldPListData = File.Exists(PListFile) ? File.ReadAllText(PListFile) : "";

			// determine if there is a launch.xib
			string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib";
			if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib"))
			{
				LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib";
			}

			// get the settings from the ini file
			// plist replacements
			DirectoryReference DirRef = bIsUE4Game ? (!string.IsNullOrEmpty(UnrealBuildTool.GetRemoteIniPath()) ? new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()) : null) : new DirectoryReference(ProjectDirectory);
			ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", DirRef);

			// orientations
			string SupportedOrientations = "";
			bool bSupported = true;
			Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsPortraitOrientation", out bSupported);
			SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortrait</string>\n" : "";
			Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsUpsideDownOrientation", out bSupported);
			SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n" : "";
			Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeLeftOrientation", out bSupported);
			SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n" : "";
			Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeRightOrientation", out bSupported);
			SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n" : "";

			// bundle display name
			string BundleDisplayName;
			Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleDisplayName", out BundleDisplayName);

			// bundle identifier
			string BundleIdentifier;
			Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

			// bundle name
			string BundleName;
			Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleName", out BundleName);

			// disable https requirement
            bool bDisableHTTPS;
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDisableHTTPS", out bDisableHTTPS);

			// short version string
			string BundleShortVersion;
			Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "VersionInfo", out BundleShortVersion);

            // required capabilities
            string RequiredCaps = "";

            if (InThis != null)
            {
                // required capabilities
                RequiredCaps += InThis.IOSPlatformContext.GetRequiredCapabilities();
            }

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsOpenGLES2", out bSupported);
			RequiredCaps += bSupported ? "\t\t<string>opengles-2</string>\n" : "";
			if (!bSupported)
			{
				Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsMetal", out bSupported);
				RequiredCaps += bSupported ? "\t\t<string>metal</string>\n" : "";
			}

			// minimum iOS version
			string MinVersion;
			if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
			{
				switch (MinVersion)
				{
					case "IOS_61":
						Log.TraceWarning("IOS 6 is no longer supported in UE4 as 4.11");
						MinVersion = "7.0";
						break;
					case "IOS_7":
						MinVersion = "7.0";
						break;
					case "IOS_8":
						MinVersion = "8.0";
						break;
					case "IOS_9":
						MinVersion = "9.0";
						break;
				}
			}
			else
			{
				MinVersion = "7.0";
			}

			// Get Facebook Support details
			bool bEnableFacebookSupport = true;
			Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableFacebookSupport", out bEnableFacebookSupport);

			// Write the Facebook App ID if we need it.
			string FacebookAppID = "";
			Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "FacebookAppID", out FacebookAppID);
			bEnableFacebookSupport = bEnableFacebookSupport && !string.IsNullOrWhiteSpace(FacebookAppID);

			// extra plist data
			string ExtraData = "";
			Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalPlistData", out ExtraData);

			// generate the plist file
			StringBuilder Text = new StringBuilder();
			Text.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			Text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
			Text.AppendLine("<plist version=\"1.0\">");
			Text.AppendLine("<dict>");
			Text.AppendLine("\t<key>CFBundleURLTypes</key>");
			Text.AppendLine("\t<array>");
			Text.AppendLine("\t\t<dict>");
			Text.AppendLine("\t\t\t<key>CFBundleURLName</key>");
			Text.AppendLine("\t\t\t<string>com.Epic.Unreal</string>");
			Text.AppendLine("\t\t\t<key>CFBundleURLSchemes</key>");
			Text.AppendLine("\t\t\t<array>");
			Text.AppendLine(string.Format("\t\t\t\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
			if (bEnableFacebookSupport)
			{
				// This is needed for facebook login to redirect back to the app after completion.
				Text.AppendLine(string.Format("\t\t\t\t<string>fb{0}</string>", FacebookAppID));
			}
			Text.AppendLine("\t\t\t</array>");
			Text.AppendLine("\t\t</dict>");
			Text.AppendLine("\t</array>");
			Text.AppendLine("\t<key>CFBundleDevelopmentRegion</key>");
			Text.AppendLine("\t<string>English</string>");
			Text.AppendLine("\t<key>CFBundleDisplayName</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleDisplayName, ProjectName)));
			Text.AppendLine("\t<key>CFBundleExecutable</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
			Text.AppendLine("\t<key>CFBundleIdentifier</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", BundleIdentifier.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "")));
			Text.AppendLine("\t<key>CFBundleInfoDictionaryVersion</key>");
			Text.AppendLine("\t<string>6.0</string>");
			Text.AppendLine("\t<key>CFBundleName</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleName, ProjectName)));
			Text.AppendLine("\t<key>CFBundlePackageType</key>");
			Text.AppendLine("\t<string>APPL</string>");
			Text.AppendLine("\t<key>CFBundleSignature</key>");
			Text.AppendLine("\t<string>????</string>");
			Text.AppendLine("\t<key>CFBundleVersion</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", VersionUtilities.UpdateBundleVersion(OldPListData)));
			Text.AppendLine("\t<key>CFBundleShortVersionString</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", BundleShortVersion));
			Text.AppendLine("\t<key>LSRequiresIPhoneOS</key>");
			Text.AppendLine("\t<true/>");
			Text.AppendLine("\t<key>UIStatusBarHidden</key>");
			Text.AppendLine("\t<true/>");
			Text.AppendLine("\t<key>UIRequiresFullScreen</key>");
			Text.AppendLine("\t<true/>");
			Text.AppendLine("\t<key>UIViewControllerBasedStatusBarAppearance</key>");
			Text.AppendLine("\t<false/>");
			Text.AppendLine("\t<key>UISupportedInterfaceOrientations</key>");
			Text.AppendLine("\t<array>");
			foreach (string Line in SupportedOrientations.Split("\r\n".ToCharArray()))
			{
				if (!string.IsNullOrWhiteSpace(Line))
				{
					Text.AppendLine(Line);
				}
			}
			Text.AppendLine("\t</array>");
			Text.AppendLine("\t<key>UIRequiredDeviceCapabilities</key>");
			Text.AppendLine("\t<array>");
			foreach (string Line in RequiredCaps.Split("\r\n".ToCharArray()))
			{
				if (!string.IsNullOrWhiteSpace(Line))
				{
					Text.AppendLine(Line);
				}
			}
			Text.AppendLine("\t</array>");
			Text.AppendLine("\t<key>CFBundleIcons</key>");
			Text.AppendLine("\t<dict>");
			Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
			Text.AppendLine("\t\t<dict>");
			Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
			Text.AppendLine("\t\t\t<array>");
			Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>Icon57.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t</array>");
			Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
			Text.AppendLine("\t\t\t<true/>");
			Text.AppendLine("\t\t</dict>");
			Text.AppendLine("\t</dict>");
			Text.AppendLine("\t<key>CFBundleIcons~ipad</key>");
			Text.AppendLine("\t<dict>");
			Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
			Text.AppendLine("\t\t<dict>");
			Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
			Text.AppendLine("\t\t\t<array>");
			Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>Icon50.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>Icon72.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>Icon76.png</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
			Text.AppendLine("\t\t\t</array>");
			Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
			Text.AppendLine("\t\t\t<true/>");
			Text.AppendLine("\t\t</dict>");
			Text.AppendLine("\t</dict>");
			if (File.Exists(LaunchXib))
			{
				// TODO: compile the xib via remote tool
				Text.AppendLine("\t<key>UILaunchStoryboardName</key>");
				Text.AppendLine("\t<string>LaunchScreen</string>");
				bSkipDefaultPNGs = true;
			}
			else
			{
				// this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist
				// eventually we want to generate this based on what the user has set in the project settings
				string[] IPhoneConfigs =  
					{ 
						"Default-IPhone6-Landscape", "Landscape", "{375, 667}", "8.0", 
						"Default-IPhone6", "Portrait", "{375, 667}",  "8.0",
						"Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}",  "8.0",
						"Default-IPhone6Plus-Portrait", "Portrait", "{414, 736}",  "8.0",
						"Default", "Landscape", "{320, 480}", "7.0",
						"Default", "Portrait", "{320, 480}", "7.0",
						"Default-568h", "Landscape", "{320, 568}", "7.0",
						"Default-568h", "Portrait", "{320, 568}", "7.0",
					};

				Text.AppendLine("\t<key>UILaunchImages~iphone</key>");
				Text.AppendLine("\t<array>");
				for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 4)
				{
					Text.AppendLine("\t\t<dict>");
					Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 3]));
					Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
					Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
					Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
					Text.AppendLine("\t\t</dict>");
				}

				// close it out
				Text.AppendLine("\t</array>");

				// this is a temp way to inject the iPad Pro without needing to upgrade everyone's plist
				// eventually we want to generate this based on what the user has set in the project settings
				string[] IPadConfigs =  
					{ 
						"Default-Landscape", "Landscape", "{768, 1024}", "7.0", 
						"Default-Portrait", "Portrait", "{768, 1024}",  "7.0",
						"Default-Landscape-1336", "Landscape", "{1024, 1366}",  "9.0",
						"Default-Portrait-1336", "Portrait", "{1024, 1366}",  "9.0",
					};

				Text.AppendLine("\t<key>UILaunchImages~ipad</key>");
				Text.AppendLine("\t<array>");
				for (int ConfigIndex = 0; ConfigIndex < IPadConfigs.Length; ConfigIndex += 4)
				{
					Text.AppendLine("\t\t<dict>");
					Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 3]));
					Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
					Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
					Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
					Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
					Text.AppendLine("\t\t</dict>");
				}
				Text.AppendLine("\t</array>");
			}
			Text.AppendLine("\t<key>CFBundleSupportedPlatforms</key>");
			Text.AppendLine("\t<array>");
			Text.AppendLine("\t\t<string>iPhoneOS</string>");
			Text.AppendLine("\t</array>");
			Text.AppendLine("\t<key>MinimumOSVersion</key>");
			Text.AppendLine(string.Format("\t<string>{0}</string>", MinVersion));
			// disable exempt encryption
			Text.AppendLine("\t<key>ITSAppUsesNonExemptEncryption</key>");
			Text.AppendLine("\t<false/>");
			
			// disable HTTPS requirement
            if (bDisableHTTPS)
            {
                Text.AppendLine("\t<key>NSAppTransportSecurity</key>");
                Text.AppendLine("\t\t<dict>");
                Text.AppendLine("\t\t\t<key>NSAllowsArbitraryLoads</key><true/>");
                Text.AppendLine("\t\t</dict>");
            }
            
			if (bEnableFacebookSupport)
			{
				Text.AppendLine("\t<key>FacebookAppID</key>");
				Text.AppendLine(string.Format("\t<string>{0}</string>", FacebookAppID));

			}
			if (!string.IsNullOrEmpty(ExtraData))
			{
				ExtraData = ExtraData.Replace("\\n", "\n");
				foreach (string Line in ExtraData.Split("\r\n".ToCharArray()))
				{
					if (!string.IsNullOrWhiteSpace(Line))
					{
						Text.AppendLine("\t" + Line);
					}
				}
			}
			Text.AppendLine("</dict>");
			Text.AppendLine("</plist>");

			// Create the intermediate directory if needed
			if (!Directory.Exists(IntermediateDirectory))
			{
				Directory.CreateDirectory(IntermediateDirectory);
			}

			if(InThis != null && InThis.UPL != null)
			{
				// Allow UPL to modify the plist here
				XDocument XDoc;
				try
				{
					XDoc = XDocument.Parse(Text.ToString());
				}
				catch (Exception e)
				{
					throw new BuildException("plist is invalid {0}\n{1}", e, Text.ToString());
				}

				XDoc.DocumentType.InternalSubset = "";
				InThis.UPL.ProcessPluginNode("None", "iosPListUpdates", "", ref XDoc);
                string result = XDoc.Declaration.ToString() + "\n" + XDoc.ToString().Replace("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"[]>", "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
				File.WriteAllText(PListFile, result);
			}
			else
			{
				File.WriteAllText(PListFile, Text.ToString());
			}

			if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
			{
				if (!Directory.Exists(AppDirectory))
				{
					Directory.CreateDirectory(AppDirectory);
				}
				File.WriteAllText(AppDirectory + "/Info.plist", Text.ToString());
			}

			return bSkipDefaultPNGs;
		}