You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
372 lines
14 KiB
C#
372 lines
14 KiB
C#
/**
|
|
* Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
*/
|
|
|
|
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 Microsoft.Win32;
|
|
using Manzana;
|
|
using System.Linq;
|
|
using iPhonePackager;
|
|
|
|
namespace DeploymentServer
|
|
{
|
|
class DummyDeployTimeReporter : DeployTimeReportingInterface
|
|
{
|
|
public void Log(string Line)
|
|
{
|
|
Console.WriteLine("[DD] " + Line);
|
|
}
|
|
|
|
public void Error(string Line)
|
|
{
|
|
Console.WriteLine("[DD] Error: " + Line);
|
|
}
|
|
|
|
public void Warning(string Line)
|
|
{
|
|
Console.WriteLine("[DD] Warning: " + Line);
|
|
}
|
|
|
|
public void SetProgressIndex(int Progress)
|
|
{
|
|
}
|
|
|
|
public int GetTransferProgressDivider()
|
|
{
|
|
return 25;
|
|
}
|
|
}
|
|
|
|
class DeploymentImplementation : MarshalByRefObject, DeploymentInterface
|
|
{
|
|
bool bHaveRegisteredHandlers = false;
|
|
|
|
/// <summary>
|
|
/// Delay for 1 second after finding the first connected device, to wait for others to enumerate.
|
|
/// </summary>
|
|
const uint StandardEnumerationDelayMS = 1000;
|
|
|
|
const uint SleepAfterFailedDeviceCallMS = 500;
|
|
|
|
/// <summary>
|
|
/// Mappings from device type string to a more friendly device name
|
|
/// </summary>
|
|
Dictionary<string, string> DeviceTypeMapping = new Dictionary<string, string>();
|
|
|
|
/// <summary>
|
|
/// The reporting interface used to talk back to iPhonePackager
|
|
/// </summary>
|
|
static DeployTimeReportingInterface ReportIF = new DummyDeployTimeReporter();
|
|
|
|
public string DeviceId { get; set; }
|
|
|
|
public DeploymentImplementation()
|
|
{
|
|
// Setup the device type mapping
|
|
DeviceTypeMapping.Add("iPhone1,1", "iPhone 1G");
|
|
DeviceTypeMapping.Add("iPhone1,2", "iPhone 3G");
|
|
DeviceTypeMapping.Add("iPhone2,1", "iPhone 3GS");
|
|
DeviceTypeMapping.Add("iPhone3,1", "iPhone 4"); // AT&T
|
|
DeviceTypeMapping.Add("iPhone3,3", "iPhone 4"); // CDMA/Verizon
|
|
DeviceTypeMapping.Add("iPhone4,1", "iPhone 4S");
|
|
DeviceTypeMapping.Add("iPod1,1", "iPod Touch 1G");
|
|
DeviceTypeMapping.Add("iPod2,1", "iPod Touch 2G");
|
|
DeviceTypeMapping.Add("iPod3,1", "iPod Touch 3G");
|
|
DeviceTypeMapping.Add("iPod4,1", "iPod Touch 4G");
|
|
DeviceTypeMapping.Add("iPad1,1", "iPad");
|
|
DeviceTypeMapping.Add("iPad2,1", "iPad 2 (Wifi)"); // Wifi only
|
|
DeviceTypeMapping.Add("iPad2,2", "iPad 2 (with 3G)"); // AT&T
|
|
DeviceTypeMapping.Add("iPad2,3", "iPad 2 (with 3G)"); // CDMA/Verizon
|
|
|
|
Console.WriteLine("[deploy] Created deployment server.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a pretty device type name
|
|
/// </summary>
|
|
string GetPrettyDeviceType(string DeviceType)
|
|
{
|
|
string OutName;
|
|
if (!DeviceTypeMapping.TryGetValue(DeviceType, out OutName))
|
|
{
|
|
OutName = DeviceType;
|
|
}
|
|
return OutName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to determine if the device will not be able to run a UE3 application
|
|
/// </summary>
|
|
bool CanRunUE3Applications(string DeviceType)
|
|
{
|
|
// Not perfect, but it will give it a go
|
|
if (DeviceType.StartsWith("iPhone1,") || DeviceType.StartsWith("iPod1,") || DeviceType.StartsWith("iPod2,"))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void MobileDeviceConnected(object sender, Manzana.ConnectEventArgs args)
|
|
{
|
|
string DeviceName = "(unknown name)";
|
|
MobileDeviceInstance Inst = MobileDeviceInstanceManager.ConnectedDevices[args.Device];
|
|
if (Inst != null)
|
|
{
|
|
DeviceName = Inst.DeviceName;
|
|
}
|
|
|
|
ReportIF.Log(String.Format("Mobile Device '{0}' connected", DeviceName));
|
|
Inst.OnGenericProgress = MobileDeviceProgressCallback;
|
|
|
|
Inst.TransferProgressDivisor = ReportIF.GetTransferProgressDivider();
|
|
}
|
|
|
|
void MobileDeviceDisconnected(object sender, Manzana.ConnectEventArgs args)
|
|
{
|
|
ReportIF.Error("Mobile Device disconnected during run!");
|
|
}
|
|
|
|
void MobileDeviceProgressCallback(string Msg, int PercentDone)
|
|
{
|
|
ReportIF.SetProgressIndex(PercentDone);
|
|
ReportIF.Log(String.Format(" ... {0}", Msg));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to connect to all devices
|
|
/// </summary>
|
|
/// <param name="DelayAfterFirstDeviceMS"></param>
|
|
void ConnectToDevices(uint DelayAfterFirstDeviceMS)
|
|
{
|
|
{
|
|
ReportIF.Log("Trying to connect to mobile device running iOS ...");
|
|
|
|
try
|
|
{
|
|
// Initialize the mobile device manager
|
|
if (!bHaveRegisteredHandlers)
|
|
{
|
|
Manzana.MobileDeviceInstanceManager.Initialize(MobileDeviceConnected, MobileDeviceDisconnected);
|
|
bHaveRegisteredHandlers = true;
|
|
}
|
|
|
|
// Wait for connections to roll in
|
|
int SleepDurationMS = 100;
|
|
int TotalDurationMS = 5000;
|
|
while (!MobileDeviceInstanceManager.AreAnyDevicesConnected() && (TotalDurationMS > 0))
|
|
{
|
|
System.Threading.Thread.Sleep(SleepDurationMS);
|
|
TotalDurationMS -= SleepDurationMS;
|
|
}
|
|
|
|
// Wait one additional tick in case any new devices come online
|
|
//@TODO: Is there a better way to determine if all devices have been enumerated?
|
|
System.Threading.Thread.Sleep((int)DelayAfterFirstDeviceMS);
|
|
|
|
if (!MobileDeviceInstanceManager.AreAnyDevicesConnected())
|
|
{
|
|
ReportIF.Error("Timed out while trying to connect to a mobile device. Make sure one is connected.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ReportIF.Error(String.Format("Error encountered ('{0}') while trying to connect to a mobile device. Please verify that iTunes is installed", ex.Message));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A delegate to do work on a device, that knows if it has succeeded or failed
|
|
/// </summary>
|
|
delegate bool PerformDeviceActionDelegate(MobileDeviceInstance Device);
|
|
|
|
/// <summary>
|
|
/// Calls a delegate on all connected devices. This re-evaluates the currently connected devices
|
|
/// after each go, so if some devices take a while to enumerate, they will probably still be caught
|
|
/// after the first device work finishes (since the work is typically long).
|
|
/// </summary>
|
|
/// <param name="DelayEnumerationPeriodMS">The initial number of ms to wait after the first enumerated device is found</param>
|
|
/// <param name="PerDeviceWork">The delegate to perform on each connected device</param>
|
|
/// <returns>True if all devices had the work successfully performed, and false if any failed or none were found</returns>
|
|
bool PerformActionOnAllDevices(uint DelayEnumerationPeriodMS, PerformDeviceActionDelegate PerDeviceWork)
|
|
{
|
|
// Start enumerating the devices
|
|
ConnectToDevices(DelayEnumerationPeriodMS);
|
|
|
|
// Keep looking at the device list and executing on new ones as long as we keep finding them
|
|
Dictionary<MobileDeviceInstance, bool> Runs = new Dictionary<MobileDeviceInstance, bool>();
|
|
bool bFoundNewDevices = true;
|
|
while (bFoundNewDevices)
|
|
{
|
|
IEnumerable<MobileDeviceInstance> Devices = MobileDeviceInstanceManager.GetSnapshotInstanceList();
|
|
|
|
bFoundNewDevices = false;
|
|
foreach (MobileDeviceInstance PotentialDevice in Devices)
|
|
{
|
|
if (!Runs.ContainsKey(PotentialDevice))
|
|
{
|
|
string DeviceName = PotentialDevice.DeviceName;
|
|
if (DeviceName == String.Empty)
|
|
{
|
|
System.Threading.Thread.Sleep((int)SleepAfterFailedDeviceCallMS);
|
|
}
|
|
|
|
// New device, do the work on it
|
|
Runs.Add(PotentialDevice, PerDeviceWork(PotentialDevice));
|
|
bFoundNewDevices = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Determine if all succeeded
|
|
bool bAllSucceeded = true;
|
|
bool bAnySucceeded = Runs.Count > 0;
|
|
foreach (var KVP in Runs)
|
|
{
|
|
bAllSucceeded = bAllSucceeded && KVP.Value;
|
|
}
|
|
|
|
return bAllSucceeded && bAnySucceeded;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Uninstalls all application bundles with the specified application bundle ID on all connected devices
|
|
/// </summary>
|
|
public bool UninstallIPAOnDevice(string ApplicationIdentifier)
|
|
{
|
|
ReportIF.Log("Uninstalling IPA on device ... ");
|
|
|
|
// Connect to each device and issue the uninstall
|
|
return PerformActionOnAllDevices(StandardEnumerationDelayMS, delegate(MobileDeviceInstance Device)
|
|
{
|
|
ReportIF.Log(String.Format(" ... Uninstalling application with bundle identifier '{0}' on device '{1}'", ApplicationIdentifier, Device.DeviceName));
|
|
return Device.TryUninstall(ApplicationIdentifier);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes a dictionary of UDID->DeviceName for all connected devices
|
|
/// </summary>
|
|
public ConnectedDeviceInfo [] EnumerateConnectedDevices()
|
|
{
|
|
List<ConnectedDeviceInfo> Results = new List<ConnectedDeviceInfo>();
|
|
|
|
PerformActionOnAllDevices(2 * StandardEnumerationDelayMS, delegate(MobileDeviceInstance Device)
|
|
{
|
|
string DeviceName = Device.DeviceName;
|
|
string UDID = Device.DeviceId;
|
|
string DeviceType = Device.ProductType;
|
|
if (UDID != "")
|
|
{
|
|
Results.Add(new ConnectedDeviceInfo(DeviceName, UDID, GetPrettyDeviceType(DeviceType)));
|
|
ReportIF.Log(String.Format(" Connected device '{0}' has UDID '{1}' and type '{2}'... ", DeviceName, UDID, DeviceType));
|
|
}
|
|
else
|
|
{
|
|
ReportIF.Warning(String.Format(" Failed to query device for it's name or UDID"));
|
|
}
|
|
return true;
|
|
});
|
|
|
|
return Results.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Installs an IPA to all connected devices
|
|
/// </summary>
|
|
public bool InstallIPAOnDevice(string IPAPath)
|
|
{
|
|
if ((IPAPath == null) || (IPAPath.Length == 0))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Transfer to all connected devices
|
|
return PerformActionOnAllDevices(StandardEnumerationDelayMS, delegate(MobileDeviceInstance Device)
|
|
{
|
|
// Transfer the file to the device
|
|
string DeviceName = Device.DeviceName;
|
|
string UDID = Device.DeviceId;
|
|
string DeviceType = Device.ProductType;
|
|
|
|
// Check to see what kind of device it is
|
|
if (!CanRunUE3Applications(DeviceType))
|
|
{
|
|
ReportIF.Warning(String.Format("Device '{0}' is a {1} model, which does not support OpenGL ES2.0. The installation is likely to fail.", DeviceName, GetPrettyDeviceType(DeviceType)));
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(DeviceId) || Device.DeviceId == DeviceId)
|
|
{
|
|
ReportIF.Log(String.Format("Transferring IPA to device '{0}' ... ", DeviceName));
|
|
Device.CopyFileToPublicStaging(IPAPath);
|
|
|
|
// Request that the device install it
|
|
ReportIF.Log(String.Format("Installing IPA on device '{0}' ... ", DeviceName));
|
|
|
|
// Upgrade will function as install if the app isn't already installed, and has the added benefit of killing a running
|
|
// app rather than failing if the user is still running the app to upgrade
|
|
//return ConnectedDevice.TryInstall(IPAPath);
|
|
bool bResult = Device.TryUpgrade(IPAPath);
|
|
|
|
ReportIF.Log("");
|
|
|
|
return bResult;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
public bool BackupDocumentsDirectory(string BundleIdentifier, string DestinationDocumentsDirectory)
|
|
{
|
|
return PerformActionOnAllDevices(StandardEnumerationDelayMS, delegate(MobileDeviceInstance Device)
|
|
{
|
|
string SafeDeviceName = MobileDeviceInstance.SanitizePathNoFilename(Device.DeviceName);
|
|
|
|
// Destination folder
|
|
string TargetFolder = Path.Combine(DestinationDocumentsDirectory, SafeDeviceName);
|
|
|
|
// Source folder
|
|
string SourceFolder = "/Documents/";
|
|
|
|
bool bResult = Device.TryBackup(BundleIdentifier, SourceFolder, TargetFolder);
|
|
|
|
ReportIF.Log("");
|
|
|
|
return bResult;
|
|
});
|
|
}
|
|
|
|
public bool ListApplications()
|
|
{
|
|
return PerformActionOnAllDevices(StandardEnumerationDelayMS, delegate(MobileDeviceInstance Device)
|
|
{
|
|
Device.DumpInstalledApplications();
|
|
|
|
ReportIF.Log("");
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public void SetReportingInterface(DeployTimeReportingInterface InReporter)
|
|
{
|
|
// System.Threading.Thread.Sleep(10000);
|
|
|
|
ReportIF = InReporter;
|
|
}
|
|
}
|
|
}
|