You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#change UBT will check for API version of all UnrealHeaderTool binaries to detect partial syncs #change Added BuildHostPlatform class for runtime platform abstraction [CL 2245408 by Robert Manuszewski in Main branch]
437 lines
18 KiB
C#
437 lines
18 KiB
C#
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using System.IO;
|
|
|
|
namespace UnrealBuildTool.IOS
|
|
{
|
|
class UEDeployIOS : UEBuildDeploy
|
|
{
|
|
/**
|
|
* Register the platform with the UEBuildDeploy class
|
|
*/
|
|
public override void RegisterBuildDeploy()
|
|
{
|
|
// TODO: print debug info and handle any cases that would keep this from registering
|
|
UEBuildDeploy.RegisterBuildDeploy(UnrealTargetPlatform.IOS, this);
|
|
}
|
|
|
|
private static void CopyFileWithReplacements(string SourceFilename, string DestFilename, Dictionary<string, string> Replacements)
|
|
{
|
|
if (!File.Exists(SourceFilename))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// make the dst filename with the same structure as it was in SourceDir
|
|
if (File.Exists(DestFilename))
|
|
{
|
|
File.Delete(DestFilename);
|
|
}
|
|
|
|
// make the subdirectory if needed
|
|
string DestSubdir = Path.GetDirectoryName(DestFilename);
|
|
if (!Directory.Exists(DestSubdir))
|
|
{
|
|
Directory.CreateDirectory(DestSubdir);
|
|
}
|
|
|
|
// some files are handled specially
|
|
string Ext = Path.GetExtension(SourceFilename);
|
|
if (Ext == ".plist")
|
|
{
|
|
string Contents = File.ReadAllText(SourceFilename);
|
|
|
|
// replace some varaibles
|
|
foreach (var Pair in Replacements)
|
|
{
|
|
Contents = Contents.Replace(Pair.Key, Pair.Value);
|
|
}
|
|
|
|
// write out file
|
|
File.WriteAllText(DestFilename, Contents);
|
|
}
|
|
else
|
|
{
|
|
File.Copy(SourceFilename, DestFilename);
|
|
|
|
// remove any read only flags
|
|
FileInfo DestFileInfo = new FileInfo(DestFilename);
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
}
|
|
|
|
public override bool PrepForUATPackageOrDeploy(string InProjectName, string InProjectDirectory, string InExecutablePath, string InEngineDir, bool bForDistribution, string CookFlavor)
|
|
{
|
|
bool bIsUE4Game = InExecutablePath.Contains ("UE4Game");
|
|
string BinaryPath = Path.GetDirectoryName (InExecutablePath);
|
|
string GameExeName = Path.GetFileName (InExecutablePath);
|
|
string GameName = bIsUE4Game ? "UE4Game" : InProjectName;
|
|
string PayloadDirectory = BinaryPath + "/Payload";
|
|
string AppDirectory = PayloadDirectory + "/" + GameName + ".app";
|
|
string CookedContentDirectory = AppDirectory + "/cookeddata";
|
|
string BuildDirectory = InProjectDirectory + "/Build/IOS";
|
|
string IntermediateDirectory = (bIsUE4Game ? InEngineDir : InProjectDirectory) + "/Intermediate/IOS";
|
|
|
|
// don't delete the payload directory, just update the data in it
|
|
//if (Directory.Exists(PayloadDirectory))
|
|
//{
|
|
// Directory.Delete(PayloadDirectory, true);
|
|
//}
|
|
|
|
Directory.CreateDirectory(BinaryPath);
|
|
Directory.CreateDirectory(PayloadDirectory);
|
|
Directory.CreateDirectory(AppDirectory);
|
|
Directory.CreateDirectory(BuildDirectory);
|
|
Directory.CreateDirectory(CookedContentDirectory);
|
|
|
|
// create the entitlements file
|
|
WriteEntitlementsFile(Path.Combine(IntermediateDirectory, GameName + ".entitlements"));
|
|
|
|
// delete some old files if they exist
|
|
if (Directory.Exists(AppDirectory + "/_CodeSignature"))
|
|
{
|
|
Directory.Delete(AppDirectory + "/_CodeSignature", true);
|
|
}
|
|
if (File.Exists(AppDirectory + "/CustomResourceRules.plist"))
|
|
{
|
|
File.Delete(AppDirectory + "/CustomResourceRules.plist");
|
|
}
|
|
if (File.Exists(AppDirectory + "/embedded.mobileprovision"))
|
|
{
|
|
File.Delete(AppDirectory + "/embedded.mobileprovision");
|
|
}
|
|
if (File.Exists(AppDirectory + "/PkgInfo"))
|
|
{
|
|
File.Delete(AppDirectory + "/PkgInfo");
|
|
}
|
|
|
|
// install the provision
|
|
FileInfo DestFileInfo;
|
|
string ProvisionWithPrefix = InEngineDir + "/Build/IOS/UE4Game.mobileprovision";
|
|
if (File.Exists(BuildDirectory + "/" + InProjectName + ".mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildDirectory + "/" + InProjectName + ".mobileprovision";
|
|
}
|
|
else
|
|
{
|
|
if (File.Exists(BuildDirectory + "/NotForLicensees/" + InProjectName + ".mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildDirectory + "/NotForLicensees/" + InProjectName + ".mobileprovision";
|
|
}
|
|
else if (!File.Exists(ProvisionWithPrefix))
|
|
{
|
|
ProvisionWithPrefix = InEngineDir + "/Build/IOS/NotForLicensees/UE4Game.mobileprovision";
|
|
}
|
|
}
|
|
if (File.Exists (ProvisionWithPrefix))
|
|
{
|
|
Directory.CreateDirectory (Environment.GetEnvironmentVariable ("HOME") + "/Library/MobileDevice/Provisioning Profiles/");
|
|
if (File.Exists(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + ".mobileprovision"))
|
|
{
|
|
DestFileInfo = new FileInfo(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + ".mobileprovision");
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
File.Copy (ProvisionWithPrefix, Environment.GetEnvironmentVariable ("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + ".mobileprovision", true);
|
|
DestFileInfo = new FileInfo (Environment.GetEnvironmentVariable ("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + ".mobileprovision");
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
else
|
|
{
|
|
// copy all provisions from the game directory, the engine directory, and the notforlicensees directory
|
|
// copy all of the provisions from the game directory to the library
|
|
{
|
|
if (Directory.Exists(BuildDirectory))
|
|
{
|
|
foreach (string Provision in Directory.EnumerateFiles(BuildDirectory, "*.mobileprovision", SearchOption.AllDirectories))
|
|
{
|
|
if (!File.Exists(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision)) || File.GetLastWriteTime(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision)) < File.GetLastWriteTime(Provision))
|
|
{
|
|
if (File.Exists(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision)))
|
|
{
|
|
DestFileInfo = new FileInfo(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision));
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
File.Copy(Provision, Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision), true);
|
|
DestFileInfo = new FileInfo(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision));
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// copy all of the provisions from the engine directory to the library
|
|
{
|
|
if (Directory.Exists(InEngineDir + "/Build/IOS"))
|
|
{
|
|
foreach (string Provision in Directory.EnumerateFiles(InEngineDir + "/Build/IOS", "*.mobileprovision", SearchOption.AllDirectories))
|
|
{
|
|
if (!File.Exists(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision)) || File.GetLastWriteTime(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision)) < File.GetLastWriteTime(Provision))
|
|
{
|
|
if (File.Exists(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision)))
|
|
{
|
|
DestFileInfo = new FileInfo(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision));
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
File.Copy(Provision, Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision), true);
|
|
DestFileInfo = new FileInfo(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + Path.GetFileName(Provision));
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// install the distribution provision
|
|
ProvisionWithPrefix = InEngineDir + "/Build/IOS/UE4Game_Distro.mobileprovision";
|
|
if (File.Exists(BuildDirectory + "/" + InProjectName + "_Distro.mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildDirectory + "/" + InProjectName + "_Distro.mobileprovision";
|
|
}
|
|
else
|
|
{
|
|
if (File.Exists(BuildDirectory + "/NotForLicensees/" + InProjectName + "_Distro.mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildDirectory + "/NotForLicensees/" + InProjectName + "_Distro.mobileprovision";
|
|
}
|
|
else if (!File.Exists(ProvisionWithPrefix))
|
|
{
|
|
ProvisionWithPrefix = InEngineDir + "/Build/IOS/NotForLicensees/UE4Game_Distro.mobileprovision";
|
|
}
|
|
}
|
|
if (File.Exists(ProvisionWithPrefix))
|
|
{
|
|
if (File.Exists(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + "_Distro.mobileprovision"))
|
|
{
|
|
DestFileInfo = new FileInfo(Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + "_Distro.mobileprovision");
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
File.Copy(ProvisionWithPrefix, Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + "_Distro.mobileprovision", true);
|
|
DestFileInfo = new FileInfo (Environment.GetEnvironmentVariable ("HOME") + "/Library/MobileDevice/Provisioning Profiles/" + InProjectName + "_Distro.mobileprovision");
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
|
|
// copy plist file
|
|
string PListFile = InEngineDir + "/Build/IOS/UE4Game-Info.plist";
|
|
if (File.Exists(BuildDirectory + "/" + InProjectName + "-Info.plist"))
|
|
{
|
|
PListFile = BuildDirectory + "/" + InProjectName + "-Info.plist";
|
|
}
|
|
|
|
Dictionary<string, string> Replacements = new Dictionary<string, string>();
|
|
Replacements.Add("${EXECUTABLE_NAME}", GameName);
|
|
Replacements.Add("${BUNDLE_IDENTIFIER}", InProjectName.Replace("_", ""));
|
|
CopyFileWithReplacements(PListFile, AppDirectory + "/Info.plist", Replacements);
|
|
CopyFileWithReplacements(PListFile, IntermediateDirectory + "/" + GameName + "-Info.plist", Replacements);
|
|
|
|
// ensure the destination is writable
|
|
if (File.Exists(AppDirectory + "/" + GameName))
|
|
{
|
|
FileInfo GameFileInfo = new FileInfo(AppDirectory + "/" + GameName);
|
|
GameFileInfo.Attributes = GameFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
|
|
// copy the GameName binary
|
|
File.Copy(BinaryPath + "/" + GameExeName, AppDirectory + "/" + GameName, true);
|
|
|
|
// copy engine assets in
|
|
CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "*.png", true);
|
|
// merge game assets on top
|
|
if (Directory.Exists(BuildDirectory + "/Resources/Graphics"))
|
|
{
|
|
CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "*.png", true);
|
|
}
|
|
|
|
// copy additional engine framework assets in
|
|
string FrameworkAssetsPath = InEngineDir + "/Intermediate/IOS/FrameworkAssets";
|
|
|
|
// Let project override assets if they exist
|
|
if ( Directory.Exists( InProjectDirectory + "/Intermediate/IOS/FrameworkAssets" ) )
|
|
{
|
|
FrameworkAssetsPath = InProjectDirectory + "/Intermediate/IOS/FrameworkAssets";
|
|
}
|
|
|
|
if ( Directory.Exists( FrameworkAssetsPath ) )
|
|
{
|
|
CopyFolder( FrameworkAssetsPath, AppDirectory, true );
|
|
}
|
|
|
|
//CopyFiles(BuildDirectory, PayloadDirectory, null, "iTunesArtwork", null);
|
|
CopyFolder(InEngineDir + "/Content/Stats", AppDirectory + "/cookeddata/engine/content/stats", true);
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool PrepTargetForDeployment(UEBuildTarget InTarget)
|
|
{
|
|
string GameName = InTarget.AppName;
|
|
string BuildPath = InTarget.ProjectDirectory + "/Binaries/IOS";
|
|
string ProjectDirectory = InTarget.ProjectDirectory;
|
|
|
|
if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac && Environment.GetEnvironmentVariable("UBT_NO_POST_DEPLOY") != "true")
|
|
{
|
|
string DecoratedGameName;
|
|
if (InTarget.Configuration == UnrealTargetConfiguration.Development)
|
|
{
|
|
DecoratedGameName = GameName;
|
|
}
|
|
else
|
|
{
|
|
DecoratedGameName = String.Format("{0}-{1}-{2}", GameName, InTarget.Platform.ToString(), InTarget.Configuration.ToString());
|
|
}
|
|
|
|
return PrepForUATPackageOrDeploy(GameName, ProjectDirectory, BuildPath + "/" + DecoratedGameName, "../../Engine", false, "");
|
|
}
|
|
else
|
|
{
|
|
// If it is requested, send the app bundle back to the platform executing these commands.
|
|
if (BuildConfiguration.bCopyAppBundleBackToDevice)
|
|
{
|
|
Log.TraceInformation("Copying binaries back to this device...");
|
|
|
|
IOSToolChain Toolchain = UEToolChain.GetPlatformToolChain(CPPTargetPlatform.IOS) as IOSToolChain;
|
|
|
|
try
|
|
{
|
|
string BinaryDir = Path.GetDirectoryName(InTarget.OutputPath) + "\\";
|
|
if (BinaryDir.EndsWith(InTarget.AppName + "\\Binaries\\IOS\\") && InTarget.Rules.Type != TargetRules.TargetType.Game)
|
|
{
|
|
BinaryDir = BinaryDir.Replace(InTarget.Rules.Type.ToString(), "Game");
|
|
}
|
|
|
|
// Get the app bundle's name
|
|
string AppFullName = InTarget.AppName;
|
|
if (InTarget.Configuration != UnrealTargetConfiguration.Development)
|
|
{
|
|
AppFullName += "-" + InTarget.Platform.ToString();
|
|
AppFullName += "-" + InTarget.Configuration.ToString();
|
|
}
|
|
|
|
foreach (string BinaryPath in Toolchain.BuiltBinaries)
|
|
{
|
|
if (!BinaryPath.Contains("Dummy"))
|
|
{
|
|
RPCUtilHelper.CopyFile(Toolchain.ConvertPath(BinaryPath), BinaryPath, false);
|
|
}
|
|
}
|
|
Log.TraceInformation("Copied binaries successfully.");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Log.TraceInformation("Copying binaries back to this device failed.");
|
|
}
|
|
}
|
|
|
|
// install the provision
|
|
/* string ProvisionWithPrefix = "../../Engine/Build/IOS/UE4Game.mobileprovision";
|
|
if (File.Exists(BuildPath + "/" + GameName + ".mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildPath + "/" + GameName + ".mobileprovision";
|
|
}
|
|
else
|
|
{
|
|
if (File.Exists(BuildPath + "/NotForLicensees/" + GameName + ".mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildPath + "/NotForLicensees/" + GameName + ".mobileprovision";
|
|
}
|
|
else if (!File.Exists(ProvisionWithPrefix))
|
|
{
|
|
ProvisionWithPrefix = "../../Engine/Build/IOS/NotForLicensees/UE4Game.mobileprovision";
|
|
}
|
|
}
|
|
string LibraryDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/Apple Computer/MobileDevice/Provisioning Profiles/";
|
|
if (File.Exists(ProvisionWithPrefix))
|
|
{
|
|
Directory.CreateDirectory(LibraryDir);
|
|
File.Copy(ProvisionWithPrefix, LibraryDir + GameName + ".mobileprovision", true);
|
|
FileInfo DestFileInfo = new FileInfo(LibraryDir + GameName + ".mobileprovision");
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}
|
|
|
|
// install the distribution provision
|
|
ProvisionWithPrefix = "../../Engine/Build/IOS/UE4Game_Distro.mobileprovision";
|
|
if (File.Exists(BuildPath + "/" + GameName + "_Distro.mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildPath + "/" + GameName + "_Distro.mobileprovision";
|
|
}
|
|
else
|
|
{
|
|
if (File.Exists(BuildPath + "/NotForLicensees/" + GameName + "_Distro.mobileprovision"))
|
|
{
|
|
ProvisionWithPrefix = BuildPath + "/NotForLicensees/" + GameName + "_Distro.mobileprovision";
|
|
}
|
|
else if (!File.Exists(ProvisionWithPrefix))
|
|
{
|
|
ProvisionWithPrefix = "../../Engine/Build/IOS/NotForLicensees/UE4Game_Distro.mobileprovision";
|
|
}
|
|
}
|
|
if (File.Exists(ProvisionWithPrefix))
|
|
{
|
|
File.Copy(ProvisionWithPrefix, LibraryDir + GameName + "_Distro.mobileprovision", true);
|
|
FileInfo DestFileInfo = new FileInfo(LibraryDir + GameName + "_Distro.mobileprovision");
|
|
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
|
|
}*/
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void WriteEntitlementsFile(string OutputFilename)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(OutputFilename));
|
|
// we need to have something so Xcode will compile, so we just set the get-task-allow, since we know the value,
|
|
// which is based on distribution or not (true means debuggable)
|
|
File.WriteAllText(OutputFilename, string.Format("<plist><dict><key>get-task-allow</key><{0}/></dict></plist>",
|
|
/*Config.bForDistribution ? "false" : */"true"));
|
|
}
|
|
|
|
static void SafeFileCopy(FileInfo SourceFile, string DestinationPath, bool bOverwrite)
|
|
{
|
|
FileInfo DI = new FileInfo(DestinationPath);
|
|
if (DI.Exists && bOverwrite)
|
|
{
|
|
DI.IsReadOnly = false;
|
|
DI.Delete();
|
|
}
|
|
|
|
SourceFile.CopyTo(DestinationPath, bOverwrite);
|
|
}
|
|
|
|
private void CopyFiles(string SourceDirectory, string DestinationDirectory, string TargetFiles, bool bOverwrite = false)
|
|
{
|
|
DirectoryInfo SourceFolderInfo = new DirectoryInfo(SourceDirectory);
|
|
FileInfo[] SourceFiles = SourceFolderInfo.GetFiles(TargetFiles);
|
|
foreach (FileInfo SourceFile in SourceFiles)
|
|
{
|
|
string DestinationPath = Path.Combine(DestinationDirectory, SourceFile.Name);
|
|
SafeFileCopy(SourceFile, DestinationPath, bOverwrite);
|
|
}
|
|
}
|
|
|
|
private void CopyFolder(string SourceDirectory, string DestinationDirectory, bool bOverwrite = false)
|
|
{
|
|
Directory.CreateDirectory(DestinationDirectory);
|
|
RecursiveFolderCopy(new DirectoryInfo(SourceDirectory), new DirectoryInfo(DestinationDirectory), bOverwrite);
|
|
}
|
|
|
|
static private void RecursiveFolderCopy(DirectoryInfo SourceFolderInfo, DirectoryInfo DestFolderInfo, bool bOverwrite = false)
|
|
{
|
|
foreach (FileInfo SourceFileInfo in SourceFolderInfo.GetFiles())
|
|
{
|
|
string DestinationPath = Path.Combine(DestFolderInfo.FullName, SourceFileInfo.Name);
|
|
SafeFileCopy(SourceFileInfo, DestinationPath, bOverwrite);
|
|
}
|
|
|
|
foreach (DirectoryInfo SourceSubFolderInfo in SourceFolderInfo.GetDirectories())
|
|
{
|
|
string DestFolderName = Path.Combine(DestFolderInfo.FullName, SourceSubFolderInfo.Name);
|
|
Directory.CreateDirectory(DestFolderName);
|
|
RecursiveFolderCopy(SourceSubFolderInfo, new DirectoryInfo(DestFolderName), bOverwrite);
|
|
}
|
|
}
|
|
}
|
|
}
|