2014-03-14 14:13:41 -04:00
/ * *
2014-12-07 19:09:38 -05:00
* Copyright 1998 - 2015 Epic Games , Inc . All Rights Reserved .
2014-03-14 14:13:41 -04:00
* /
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Net ;
using System.Runtime.InteropServices ;
using System.Text ;
using System.Threading ;
using System.Windows.Forms ;
using Microsoft.Win32 ;
using System.Linq ;
using System.Runtime.Remoting.Channels.Ipc ;
using System.Runtime.Remoting.Channels ;
using System.Runtime.Remoting ;
namespace iPhonePackager
{
// Implementation of DeploymentServer -> Application interface
[Serializable]
class DeployTimeReporter : DeployTimeReportingInterface
{
public void Log ( string Line )
{
Program . Log ( Line ) ;
}
public void Error ( string Line )
{
Program . Error ( Line ) ;
}
public void Warning ( string Line )
{
Program . Warning ( Line ) ;
}
public void SetProgressIndex ( int Progress )
{
Program . ProgressIndex = Progress ;
}
public int GetTransferProgressDivider ( )
{
return ( Program . BGWorker ! = null ) ? 1000 : 25 ;
}
}
class DeploymentHelper
{
static DeploymentInterface DeployTimeInstance ;
public static Process DeploymentServerProcess = null ;
public static void InstallIPAOnConnectedDevices ( string IPAPath )
{
// Read the mobile provision to check for issues
FileOperations . ReadOnlyZipFileSystem Zip = new FileOperations . ReadOnlyZipFileSystem ( IPAPath ) ;
MobileProvision Provision = null ;
try
{
MobileProvisionParser . ParseFile ( Zip . ReadAllBytes ( "embedded.mobileprovision" ) ) ;
}
catch ( System . Exception ex )
{
Program . Warning ( String . Format ( "Couldn't find an embedded mobile provision ({0})" , ex . Message ) ) ;
Provision = null ;
}
2014-08-06 15:37:27 -04:00
Zip . Close ( ) ;
2014-03-14 14:13:41 -04:00
if ( Provision ! = null )
{
var DeviceList = DeploymentHelper . Get ( ) . EnumerateConnectedDevices ( ) ;
foreach ( var DeviceInfo in DeviceList )
{
string UDID = DeviceInfo . UDID ;
string DeviceName = DeviceInfo . DeviceName ;
// Check the IPA's mobile provision against the connected device to make sure this device is authorized
// We'll still try installing anyways, but this message is more friendly than the failure we get back from MobileDeviceInterface
if ( UDID ! = String . Empty )
{
if ( ! Provision . ContainsUDID ( UDID ) )
{
Program . Warning ( String . Format ( "Embedded provision in IPA does not include the UDID {0} of device '{1}'. The installation is likely to fail." , UDID , DeviceName ) ) ;
}
}
else
{
Program . Warning ( String . Format ( "Unable to query device for UDID, and therefore unable to verify IPA embedded mobile provision contains this device." ) ) ;
}
}
}
DeploymentHelper . Get ( ) . InstallIPAOnDevice ( IPAPath ) ;
}
public static bool ExecuteDeployCommand ( string Command , string GamePath , string RPCCommand )
{
switch ( Command . ToLowerInvariant ( ) )
{
case "backup" :
{
string ApplicationIdentifier = RPCCommand ;
if ( ApplicationIdentifier = = null )
{
ApplicationIdentifier = Utilities . GetStringFromPList ( "CFBundleIdentifier" ) ;
}
2014-12-11 16:20:07 -05:00
if ( Config . FilesForBackup . Count > 0 )
{
if ( ! DeploymentHelper . Get ( ) . BackupFiles ( ApplicationIdentifier , Config . FilesForBackup . ToArray ( ) ) )
{
Program . Error ( "Failed to transfer manifest file from device to PC" ) ;
Program . ReturnCode = ( int ) ErrorCodes . Error_DeviceBackupFailed ;
}
}
else if ( ! DeploymentHelper . Get ( ) . BackupDocumentsDirectory ( ApplicationIdentifier , Config . GetRootBackedUpDocumentsDirectory ( ) ) )
2014-03-14 14:13:41 -04:00
{
Program . Error ( "Failed to transfer documents directory from device to PC" ) ;
2014-08-01 20:30:13 -04:00
Program . ReturnCode = ( int ) ErrorCodes . Error_DeviceBackupFailed ;
2014-03-14 14:13:41 -04:00
}
}
break ;
case "uninstall" :
{
string ApplicationIdentifier = RPCCommand ;
if ( ApplicationIdentifier = = null )
{
ApplicationIdentifier = Utilities . GetStringFromPList ( "CFBundleIdentifier" ) ;
}
if ( ! DeploymentHelper . Get ( ) . UninstallIPAOnDevice ( ApplicationIdentifier ) )
{
Program . Error ( "Failed to uninstall IPA on device" ) ;
2014-09-12 06:23:49 -04:00
Program . ReturnCode = ( int ) ErrorCodes . Error_AppUninstallFailed ;
2014-03-14 14:13:41 -04:00
}
}
break ;
case "deploy" :
case "install" :
{
string IPAPath = GamePath ;
2014-10-02 14:08:18 -04:00
string AdditionalCommandline = Program . AdditionalCommandline ;
2014-03-14 14:13:41 -04:00
2014-12-11 16:20:07 -05:00
if ( ! String . IsNullOrEmpty ( AdditionalCommandline ) & & ! Config . bIterate )
2014-10-03 12:05:32 -04:00
{
// Read the mobile provision to check for issues
FileOperations . ReadOnlyZipFileSystem Zip = new FileOperations . ReadOnlyZipFileSystem ( IPAPath ) ;
try
{
// Compare the commandline embedded to prevent us from any unnecessary writing.
byte [ ] CommandlineBytes = Zip . ReadAllBytes ( "ue4commandline.txt" ) ;
string ExistingCommandline = Encoding . UTF8 . GetString ( CommandlineBytes , 0 , CommandlineBytes . Length ) ;
2014-10-02 14:08:18 -04:00
if ( ExistingCommandline ! = AdditionalCommandline )
2014-10-03 12:05:32 -04:00
{
// Ensure we have a temp dir to stage our temporary ipa
if ( ! Directory . Exists ( Config . PCStagingRootDir ) )
{
Directory . CreateDirectory ( Config . PCStagingRootDir ) ;
}
2014-10-02 14:08:18 -04:00
2014-10-03 12:05:32 -04:00
string TmpFilePath = Path . Combine ( Path . GetDirectoryName ( Config . PCStagingRootDir ) , Path . GetFileNameWithoutExtension ( IPAPath ) + ".tmp.ipa" ) ;
if ( File . Exists ( TmpFilePath ) )
{
File . Delete ( TmpFilePath ) ;
}
2014-10-02 14:08:18 -04:00
2014-10-03 12:05:32 -04:00
File . Copy ( IPAPath , TmpFilePath ) ;
2014-10-02 14:08:18 -04:00
// Get the project name:
string ProjectFile = ExistingCommandline . Split ( ' ' ) . FirstOrDefault ( ) ;
2014-10-03 12:05:32 -04:00
// Write out the new commandline.
FileOperations . ZipFileSystem WritableZip = new FileOperations . ZipFileSystem ( TmpFilePath ) ;
2014-10-02 14:08:18 -04:00
byte [ ] NewCommandline = Encoding . UTF8 . GetBytes ( ProjectFile + " " + AdditionalCommandline ) ;
2014-10-03 12:05:32 -04:00
WritableZip . WriteAllBytes ( "ue4commandline.txt" , NewCommandline ) ;
2014-10-02 14:08:18 -04:00
2014-10-03 12:05:32 -04:00
// We need to residn the application after the commandline file has changed.
CodeSignatureBuilder CodeSigner = new CodeSignatureBuilder ( ) ;
CodeSigner . FileSystem = WritableZip ;
2014-10-02 14:08:18 -04:00
2014-10-03 12:05:32 -04:00
CodeSigner . PrepareForSigning ( ) ;
CodeSigner . PerformSigning ( ) ;
2014-10-02 14:08:18 -04:00
2014-10-03 12:05:32 -04:00
WritableZip . Close ( ) ;
2014-10-02 14:08:18 -04:00
2014-10-03 12:05:32 -04:00
// Set the deploying ipa path to our new ipa
IPAPath = TmpFilePath ;
}
}
catch ( System . Exception ex )
{
Program . Warning ( String . Format ( "Failed to override the commandline.txt file: ({0})" , ex . Message ) ) ;
}
Zip . Close ( ) ;
}
2014-10-02 14:08:18 -04:00
2014-12-11 16:20:07 -05:00
if ( Config . bIterate )
{
string ApplicationIdentifier = RPCCommand ;
if ( String . IsNullOrEmpty ( ApplicationIdentifier ) )
{
ApplicationIdentifier = Utilities . GetStringFromPList ( "CFBundleIdentifier" ) ;
}
if ( ! String . IsNullOrEmpty ( Config . DeviceId ) & & ! Config . DeviceId . Contains ( "All_iOS_On" ) )
{
DeploymentHelper . Get ( ) . DeviceId = Config . DeviceId ;
}
if ( ! DeploymentHelper . Get ( ) . InstallFilesOnDevice ( ApplicationIdentifier , Config . DeltaManifest ) )
{
Program . Error ( "Failed to install Files on device" ) ;
Program . ReturnCode = ( int ) ErrorCodes . Error_FilesInstallFailed ;
}
}
else if ( File . Exists ( IPAPath ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:45:54 -04:00
if ( ! String . IsNullOrEmpty ( Config . DeviceId ) & & ! Config . DeviceId . Contains ( "All_iOS_On" ) )
2014-04-02 18:09:23 -04:00
{
DeploymentHelper . Get ( ) . DeviceId = Config . DeviceId ;
}
2014-03-14 14:13:41 -04:00
if ( ! DeploymentHelper . Get ( ) . InstallIPAOnDevice ( IPAPath ) )
{
Program . Error ( "Failed to install IPA on device" ) ;
2014-09-12 06:23:49 -04:00
Program . ReturnCode = ( int ) ErrorCodes . Error_AppInstallFailed ;
2014-03-14 14:13:41 -04:00
}
}
else
{
Program . Error ( String . Format ( "Failed to find IPA file: '{0}'" , IPAPath ) ) ;
2014-09-12 06:23:49 -04:00
Program . ReturnCode = ( int ) ErrorCodes . Error_AppNotFound ;
2014-03-14 14:13:41 -04:00
}
}
break ;
default :
return false ;
}
return true ;
}
static DeployTimeReporter Reporter = new DeployTimeReporter ( ) ;
public static DeploymentInterface Get ( )
{
if ( DeployTimeInstance = = null )
{
if ( DeploymentServerProcess = = null )
{
DeploymentServerProcess = CreateDeploymentServerProcess ( ) ;
}
DeployTimeInstance = ( DeploymentInterface ) Activator . GetObject (
typeof ( DeploymentInterface ) ,
@"ipc://iPhonePackager/DeploymentServer_PID" + Process . GetCurrentProcess ( ) . Id . ToString ( ) ) ;
}
if ( DeployTimeInstance = = null )
{
Program . Error ( "Failed to connect to deployment server" ) ;
throw new Exception ( "Failed to connect to deployment server" ) ;
}
DeployTimeInstance . SetReportingInterface ( Reporter ) ;
return DeployTimeInstance ;
}
static Process CreateDeploymentServerProcess ( )
{
Process NewProcess = new Process ( ) ;
2014-12-11 16:20:07 -05:00
if ( Environment . OSVersion . Platform = = PlatformID . MacOSX | | Environment . OSVersion . Platform = = PlatformID . Unix )
{
NewProcess . StartInfo . WorkingDirectory = Path . GetFullPath ( "." ) ;
NewProcess . StartInfo . FileName = "../../../Build/BatchFiles/Mac/RunMono.sh" ;
NewProcess . StartInfo . Arguments = "\"" + NewProcess . StartInfo . WorkingDirectory + "/DeploymentServer.exe\" -iphonepackager " + Process . GetCurrentProcess ( ) . Id . ToString ( ) ;
}
else
{
NewProcess . StartInfo . WorkingDirectory = Path . GetFullPath ( "." ) ;
NewProcess . StartInfo . FileName = NewProcess . StartInfo . WorkingDirectory + "\\DeploymentServer.exe" ;
NewProcess . StartInfo . Arguments = "-iphonepackager " + Process . GetCurrentProcess ( ) . Id . ToString ( ) ;
}
2014-03-14 14:13:41 -04:00
NewProcess . StartInfo . UseShellExecute = false ;
try
{
NewProcess . Start ( ) ;
System . Threading . Thread . Sleep ( 500 ) ;
}
catch ( System . Exception ex )
{
Program . Error ( "Failed to create deployment server process ({0})" , ex . Message ) ;
}
return NewProcess ;
}
}
}