5 using System.Collections.Generic;
22 private const float UpdateBuildsPeriod = 1.0f;
24 private const string SdkVersion =
25 #if UNITY_2017_2_OR_NEWER 31 private readonly
string[] tabNames = {
"Unity Build Options",
"Appx Build Options",
"Deploy Options" };
33 private readonly
string[] scriptingBackendNames = {
"IL2CPP",
".NET" };
35 private readonly
int[] scriptingBackendEnum = { (int)ScriptingImplementation.IL2CPP, (
int)ScriptingImplementation.WinRTDotNET };
37 private readonly
string[] deviceNames = {
"Any Device",
"PC",
"Mobile",
"HoloLens" };
39 private readonly List<string> builds =
new List<string>(0);
41 private static readonly List<string> appPackageDirectories =
new List<string>(0);
45 private readonly GUIContent buildAllThenInstallLabel =
new GUIContent(
"Build all, then Install",
"Builds the Unity Project, the APPX, then installs to the target device.");
47 private readonly GUIContent buildAllLabel =
new GUIContent(
"Build all",
"Builds the Unity Project and APPX");
49 private readonly GUIContent buildDirectoryLabel =
new GUIContent(
"Build Directory",
"It's recommended to use 'UWP'");
51 private readonly GUIContent useCSharpProjectsLabel =
new GUIContent(
"Unity C# Projects",
"Generate C# Project References for debugging");
53 private readonly GUIContent autoIncrementLabel =
new GUIContent(
"Auto Increment",
"Increases Version Build Number");
55 private readonly GUIContent versionNumberLabel =
new GUIContent(
"Version Number",
"Major.Minor.Build.Revision\nNote: Revision should always be zero because it's reserved by Windows Store.");
57 private readonly GUIContent pairHoloLensUsbLabel =
new GUIContent(
"Pair HoloLens",
"Pairs the USB connected HoloLens with the Build Window so you can deploy via USB");
59 private readonly GUIContent useSSLLabel =
new GUIContent(
"Use SSL?",
"Use SLL to communicate with Device Portal");
61 private readonly GUIContent addConnectionLabel =
new GUIContent(
"+",
"Add a remote connection");
63 private readonly GUIContent removeConnectionLabel =
new GUIContent(
"-",
"Remove a remote connection");
65 private readonly GUIContent ipAddressLabel =
new GUIContent(
"IpAddress",
"Note: Local Machine will install on any HoloLens connected to USB as well.");
67 private readonly GUIContent doAllLabel =
new GUIContent(
" Do actions on all devices",
"Should the build options perform actions on all the connected devices?");
69 private readonly GUIContent uninstallLabel =
new GUIContent(
"Uninstall First",
"Uninstall application before installing");
73 private enum BuildDeployTab
80 private enum BuildPlatformEnum
86 private enum BuildConfigEnum
95 private static bool ShouldOpenSLNBeEnabled
100 private static bool ShouldBuildSLNBeEnabled
105 private static bool ShouldBuildAppxBeEnabled
109 return ShouldBuildSLNBeEnabled &&
116 private static bool DevicePortalConnectionEnabled
121 private static bool CanInstall
125 bool canInstall =
true;
126 if (EditorUserBuildSettings.wsaSubtarget == WSASubtarget.HoloLens)
128 canInstall = DevicePortalConnectionEnabled;
135 private static string familyPackageName;
137 private static bool IsHoloLensConnectedUsb
141 bool isConnected =
false;
150 SessionState.SetBool(
"HoloLensUsbConnected", isConnected);
154 isConnected = SessionState.GetBool(
"HoloLensUsbConnected",
false);
161 #endregion // Properties 165 private int halfWidth;
166 private int quarterWidth;
168 private float timeLastUpdatedBuilds;
170 private string[] targetIps;
171 private string[] windowsSdkPaths;
173 private Vector2 scrollPosition;
175 private BuildDeployTab currentTab = BuildDeployTab.UnityBuildOptions;
177 private static bool isAppRunning;
178 private static int currentConnectionInfoIndex;
185 [MenuItem(
"Mixed Reality Toolkit/Build Window",
false, 8)]
189 var window = GetWindow<BuildDeployWindow>(typeof(SceneView));
190 window.titleContent =
new GUIContent(
"Build Window");
194 private void OnEnable()
201 titleContent =
new GUIContent(
"Build Window");
202 minSize =
new Vector2(512, 256);
204 windowsSdkPaths = Directory.GetDirectories(
@"C:\Program Files (x86)\Windows Kits\10\Lib");
206 for (
int i = 0; i < windowsSdkPaths.Length; i++)
208 windowsSdkPaths[i] = windowsSdkPaths[i].Substring(windowsSdkPaths[i].LastIndexOf(
@"\", StringComparison.Ordinal) + 1);
214 UpdatePortalConnections();
219 quarterWidth = Screen.width / 4;
220 halfWidth = Screen.width / 2;
222 #region Quick Options 224 if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WSAPlayer)
226 EditorGUILayout.HelpBox(
"Build window only available for UWP build target.", MessageType.Warning);
227 GUILayout.BeginVertical();
229 EditorGUILayout.BeginHorizontal();
233 EditorGUILayout.LabelField(buildDirectoryLabel, GUILayout.Width(96));
234 string newBuildDirectory = EditorGUILayout.TextField(curBuildDirectory, GUILayout.Width(64), GUILayout.ExpandWidth(
true));
236 if (newBuildDirectory != curBuildDirectory)
243 if (GUILayout.Button(
"Open Build Directory", GUILayout.Width(quarterWidth)))
250 if (GUILayout.Button(
"Open Player Settings", GUILayout.Width(quarterWidth)))
252 EditorApplication.ExecuteMenuItem(
"Edit/Project Settings/Player");
255 EditorGUILayout.EndHorizontal();
256 GUILayout.EndVertical();
260 GUILayout.BeginVertical();
262 GUILayout.Label(
"Quick Options");
263 EditorGUILayout.BeginHorizontal();
265 EditorUserBuildSettings.wsaSubtarget = (WSASubtarget)EditorGUILayout.Popup((
int)EditorUserBuildSettings.wsaSubtarget, deviceNames);
267 bool canInstall = CanInstall;
269 if (EditorUserBuildSettings.wsaSubtarget == WSASubtarget.HoloLens && !IsHoloLensConnectedUsb)
271 canInstall = IsHoloLensConnectedUsb;
274 GUI.enabled = ShouldBuildSLNBeEnabled;
277 if (GUILayout.Button(CanInstall ? buildAllThenInstallLabel : buildAllLabel, GUILayout.Width(halfWidth - 20)))
279 EditorApplication.delayCall += () => BuildAll(canInstall);
284 if (GUILayout.Button(
"Open Player Settings", GUILayout.Width(quarterWidth)))
286 EditorApplication.ExecuteMenuItem(
"Edit/Project Settings/Player");
289 EditorGUILayout.EndHorizontal();
290 GUILayout.EndVertical();
293 #endregion Quick Options 295 currentTab = (BuildDeployTab)GUILayout.Toolbar(SessionState.GetInt(
"_MRTK_BuildWindow_Tab", (
int)currentTab), tabNames);
296 SessionState.SetInt(
"_MRTK_BuildWindow_Tab", (
int)currentTab);
302 case BuildDeployTab.UnityBuildOptions:
305 case BuildDeployTab.AppxBuildOptions:
308 case BuildDeployTab.DeployOptions:
312 throw new ArgumentOutOfRangeException();
316 private void Update()
318 if (Time.realtimeSinceStartup - timeLastUpdatedBuilds > UpdateBuildsPeriod)
324 private void UnityBuildGUI()
326 GUILayout.BeginVertical();
327 EditorGUILayout.BeginHorizontal();
331 EditorGUILayout.LabelField(buildDirectoryLabel, GUILayout.Width(96));
332 string newBuildDirectory = EditorGUILayout.TextField(
334 GUILayout.Width(64), GUILayout.ExpandWidth(
true));
336 if (newBuildDirectory != curBuildDirectory)
343 if (GUILayout.Button(
"Open Build Directory", GUILayout.Width(halfWidth)))
350 EditorGUILayout.EndHorizontal();
351 EditorGUILayout.BeginHorizontal();
352 GUILayout.FlexibleSpace();
354 GUI.enabled = ShouldOpenSLNBeEnabled;
356 if (GUILayout.Button(
"Open in Visual Studio", GUILayout.Width(halfWidth)))
361 if (File.Exists(slnFilename))
363 EditorApplication.delayCall += () => Process.Start(
new FileInfo(slnFilename).FullName);
365 else if (EditorUtility.DisplayDialog(
366 "Solution Not Found",
367 "We couldn't find the Project's Solution. Would you like to Build the project now?",
375 EditorGUILayout.EndHorizontal();
376 EditorGUILayout.BeginHorizontal();
379 GUILayout.FlexibleSpace();
380 var previousLabelWidth = EditorGUIUtility.labelWidth;
381 EditorGUIUtility.labelWidth = 105;
382 bool generateReferenceProjects = EditorUserBuildSettings.wsaGenerateReferenceProjects;
383 bool shouldGenerateProjects = EditorGUILayout.Toggle(useCSharpProjectsLabel, generateReferenceProjects);
385 if (shouldGenerateProjects != generateReferenceProjects)
387 EditorUserBuildSettings.wsaGenerateReferenceProjects = shouldGenerateProjects;
390 EditorGUIUtility.labelWidth = previousLabelWidth;
393 GUI.enabled = ShouldBuildSLNBeEnabled;
395 if (GUILayout.Button(
"Build Unity Project", GUILayout.Width(halfWidth)))
402 EditorGUILayout.EndHorizontal();
403 EditorGUILayout.EndVertical();
406 private void AppxBuildGUI()
408 GUILayout.BeginVertical();
409 GUILayout.BeginHorizontal();
412 string currentSDKVersion = EditorUserBuildSettings.wsaUWPSDK;
414 int currentSDKVersionIndex = -1;
416 for (var i = 0; i < windowsSdkPaths.Length; i++)
418 if (
string.IsNullOrEmpty(currentSDKVersion))
420 currentSDKVersionIndex = windowsSdkPaths.Length - 1;
424 if (windowsSdkPaths[i].Equals(SdkVersion))
426 currentSDKVersionIndex = i;
431 EditorGUILayout.LabelField(
"Required SDK Version: " + SdkVersion);
434 if (currentSDKVersionIndex < 0)
436 Debug.LogErrorFormat(
"Unable to find the required Windows 10 SDK Target!\n" +
437 "Please be sure to install the {0} SDK from Visual Studio Installer.", SdkVersion);
438 GUILayout.EndHorizontal();
440 EditorGUILayout.HelpBox(
string.Format(
"Unable to find the required Windows 10 SDK Target!\n" +
441 "Please be sure to install the {0} SDK from Visual Studio Installer.", SdkVersion), MessageType.Error);
443 GUILayout.BeginHorizontal();
446 var curScriptingBackend = PlayerSettings.GetScriptingBackend(BuildTargetGroup.WSA);
448 if (curScriptingBackend == ScriptingImplementation.WinRTDotNET)
450 #if UNITY_2018_2_OR_NEWER 451 EditorGUILayout.HelpBox(
".NET Scripting backend is deprecated, please use IL2CPP.", MessageType.Warning);
453 EditorGUILayout.HelpBox(
".NET Scripting backend will be deprecated in 2018.2, please consider using IL2CPP.", MessageType.Info);
455 GUILayout.EndHorizontal();
456 GUILayout.BeginHorizontal();
457 GUILayout.FlexibleSpace();
460 var newScriptingBackend = (ScriptingImplementation)EditorGUILayout.IntPopup(
462 (
int)curScriptingBackend,
463 scriptingBackendNames,
464 scriptingBackendEnum,
465 GUILayout.Width(halfWidth));
467 if (newScriptingBackend != curScriptingBackend)
472 EditorUtility.DisplayDialog(
"Attention!",
473 string.Format(
"Build path contains project built with {0} scripting backend, while current project is using {1} scripting backend.\n\n" +
474 "Switching to a new scripting backend requires us to delete all the data currently in your build folder and rebuild the Unity Player!",
475 newScriptingBackend.ToString(),
476 curScriptingBackend.ToString()),
485 PlayerSettings.SetScriptingBackend(BuildTargetGroup.WSA, newScriptingBackend);
489 string newSDKVersion = windowsSdkPaths[currentSDKVersionIndex];
491 if (!newSDKVersion.Equals(currentSDKVersion))
493 EditorUserBuildSettings.wsaUWPSDK = newSDKVersion;
496 GUILayout.EndHorizontal();
497 GUILayout.BeginHorizontal();
498 GUILayout.FlexibleSpace();
503 BuildConfigEnum buildConfigOption;
504 if (curBuildConfigString.ToLower().Equals(
"master"))
506 buildConfigOption = BuildConfigEnum.Master;
508 else if (curBuildConfigString.ToLower().Equals(
"release"))
510 buildConfigOption = BuildConfigEnum.Release;
514 buildConfigOption = BuildConfigEnum.Debug;
517 buildConfigOption = (BuildConfigEnum)EditorGUILayout.EnumPopup(
"Build Configuration", buildConfigOption, GUILayout.Width(halfWidth));
519 string buildConfigString = buildConfigOption.ToString();
521 if (buildConfigString != curBuildConfigString)
526 GUILayout.EndHorizontal();
527 GUILayout.BeginHorizontal();
528 GUILayout.FlexibleSpace();
532 var buildPlatformOption = BuildPlatformEnum.x86;
534 if (curBuildPlatformString.ToLower().Equals(
"x86"))
536 buildPlatformOption = BuildPlatformEnum.x86;
538 else if (curBuildPlatformString.ToLower().Equals(
"x64"))
540 buildPlatformOption = BuildPlatformEnum.x64;
543 buildPlatformOption = (BuildPlatformEnum)EditorGUILayout.EnumPopup(
"Build Platform", buildPlatformOption, GUILayout.Width(halfWidth));
545 string newBuildPlatformString;
547 switch (buildPlatformOption)
549 case BuildPlatformEnum.x86:
550 case BuildPlatformEnum.x64:
551 newBuildPlatformString = buildPlatformOption.ToString();
554 throw new ArgumentOutOfRangeException();
557 if (newBuildPlatformString != curBuildPlatformString)
562 GUILayout.EndHorizontal();
563 GUILayout.BeginHorizontal();
564 GUILayout.FlexibleSpace();
566 var previousLabelWidth = EditorGUIUtility.labelWidth;
569 EditorGUIUtility.labelWidth = 96;
571 bool newIncrementVersion = EditorGUILayout.Toggle(autoIncrementLabel, curIncrementVersion);
574 EditorGUIUtility.labelWidth = previousLabelWidth;
576 if (newIncrementVersion != curIncrementVersion)
581 EditorGUILayout.LabelField(versionNumberLabel, GUILayout.Width(96));
582 Vector3 newVersion = Vector3.zero;
584 EditorGUI.BeginChangeCheck();
586 newVersion.x = EditorGUILayout.IntField(PlayerSettings.WSA.packageVersion.Major, GUILayout.Width(quarterWidth / 2 - 3));
587 newVersion.y = EditorGUILayout.IntField(PlayerSettings.WSA.packageVersion.Minor, GUILayout.Width(quarterWidth / 2 - 3));
588 newVersion.z = EditorGUILayout.IntField(PlayerSettings.WSA.packageVersion.Build, GUILayout.Width(quarterWidth / 2 - 3));
590 if (EditorGUI.EndChangeCheck())
592 PlayerSettings.WSA.packageVersion =
new Version((
int)newVersion.x, (
int)newVersion.y, (
int)newVersion.z, 0);
596 EditorGUILayout.IntField(PlayerSettings.WSA.packageVersion.Revision, GUILayout.Width(quarterWidth / 2 - 3));
599 GUILayout.EndHorizontal();
600 GUILayout.BeginHorizontal();
601 GUILayout.FlexibleSpace();
604 previousLabelWidth = EditorGUIUtility.labelWidth;
605 EditorGUIUtility.labelWidth = 50;
607 bool newForceRebuildAppx = EditorGUILayout.Toggle(
"Rebuild", curForceRebuildAppx);
609 if (newForceRebuildAppx != curForceRebuildAppx)
615 EditorGUIUtility.labelWidth = previousLabelWidth;
618 GUI.enabled = ShouldBuildAppxBeEnabled;
620 if (GUILayout.Button(
"Build APPX", GUILayout.Width(halfWidth)))
625 if (File.Exists(slnFilename))
628 EditorApplication.delayCall += () =>
631 PlayerSettings.productName,
640 else if (EditorUtility.DisplayDialog(
"Solution Not Found",
"We couldn't find the solution. Would you like to Build it?",
"Yes, Build",
"No"))
643 EditorApplication.delayCall += () => BuildAll(install:
false);
649 GUILayout.EndHorizontal();
650 GUILayout.BeginHorizontal();
651 GUILayout.FlexibleSpace();
654 string appxDirectory = curScriptingBackend == ScriptingImplementation.IL2CPP ?
"/AppPackages/" + PlayerSettings.productName :
"/" + PlayerSettings.productName +
"/AppPackages";
656 GUI.enabled = builds.Count > 0 && !
string.IsNullOrEmpty(appxBuildPath);
658 if (GUILayout.Button(
"Open APPX Packages Location", GUILayout.Width(halfWidth)))
660 EditorApplication.delayCall += () => Process.Start(
"explorer.exe",
"/f /open," + appxBuildPath);
665 GUILayout.EndHorizontal();
666 GUILayout.EndVertical();
669 private void DeployGUI()
672 Debug.Assert(currentConnectionInfoIndex >= 0);
674 GUILayout.BeginVertical();
675 EditorGUI.BeginChangeCheck();
676 GUILayout.BeginHorizontal();
679 GUI.enabled = IsHoloLensConnectedUsb;
681 if (GUILayout.Button(pairHoloLensUsbLabel, GUILayout.Width(quarterWidth)))
683 EditorApplication.delayCall += () =>
687 foreach (var targetDevice
in portalConnections.
Connections)
689 if (!IsLocalConnection(targetDevice))
697 if (networkInfo != null)
699 var newIps =
new List<string>();
700 foreach (var adapter
in networkInfo.Adapters)
702 newIps.AddRange(from address in adapter.IpAddresses where !address.IpAddress.Contains(
"0.0.0.0") select address.IpAddress);
705 if (newIps.Count == 0)
707 Debug.LogWarning(
"This HoloLens is not connected to any networks and cannot be paired.");
710 foreach (var ip
in newIps)
712 if (portalConnections.
Connections.Any(connection => connection.IP == ip))
714 Debug.LogFormat(
"Already paired");
718 newConnection.IP = ip;
719 newConnection.User = targetDevice.User;
720 newConnection.Password = targetDevice.Password;
722 if (machineName != null)
724 newConnection.MachineName = machineName.ComputerName;
730 if (IsValidIpAddress(newConnection.IP))
733 for (var i = 0; i < portalConnections.
Connections.Count; i++)
735 if (portalConnections.
Connections[i].IP == newConnection.IP)
737 currentConnectionInfoIndex = i;
738 SessionState.SetInt(
"_MRTK_BuildWindow_CurrentDeviceIndex", currentConnectionInfoIndex);
743 UpdatePortalConnections();
750 GUILayout.FlexibleSpace();
752 var previousLabelWidth = EditorGUIUtility.labelWidth;
753 EditorGUIUtility.labelWidth = 64;
755 EditorGUIUtility.labelWidth = previousLabelWidth;
757 currentConnectionInfoIndex = EditorGUILayout.Popup(
758 SessionState.GetInt(
"_MRTK_BuildWindow_CurrentDeviceIndex", 0), targetIps, GUILayout.Width(halfWidth - 48));
760 var currentConnection = portalConnections.
Connections[currentConnectionInfoIndex];
762 bool currentConnectionIsLocal = IsLocalConnection(currentConnection);
764 if (currentConnectionIsLocal)
766 currentConnection.MachineName =
"Local Machine";
769 GUI.enabled = IsValidIpAddress(currentConnection.IP);
771 if (GUILayout.Button(addConnectionLabel, GUILayout.Width(20)))
773 portalConnections.
Connections.Add(
new ConnectInfo(
"0.0.0.0", currentConnection.User, currentConnection.Password));
774 currentConnectionInfoIndex++;
775 currentConnection = portalConnections.
Connections[currentConnectionInfoIndex];
776 UpdatePortalConnections();
779 GUI.enabled = portalConnections.
Connections.Count > 1 && currentConnectionInfoIndex != 0;
781 if (GUILayout.Button(removeConnectionLabel, GUILayout.Width(20)))
783 portalConnections.
Connections.RemoveAt(currentConnectionInfoIndex);
784 currentConnectionInfoIndex--;
785 currentConnection = portalConnections.
Connections[currentConnectionInfoIndex];
786 UpdatePortalConnections();
791 GUILayout.EndHorizontal();
793 GUILayout.BeginHorizontal();
794 GUILayout.FlexibleSpace();
796 GUILayout.Label(currentConnection.MachineName, GUILayout.Width(halfWidth));
798 GUILayout.EndHorizontal();
800 previousLabelWidth = EditorGUIUtility.labelWidth;
801 EditorGUIUtility.labelWidth = 64;
802 GUILayout.BeginHorizontal();
803 GUILayout.FlexibleSpace();
805 GUI.enabled = !currentConnectionIsLocal;
806 currentConnection.IP = EditorGUILayout.TextField(
808 currentConnection.IP,
809 GUILayout.Width(halfWidth));
812 GUILayout.EndHorizontal();
813 GUILayout.BeginHorizontal();
814 GUILayout.FlexibleSpace();
815 currentConnection.User = EditorGUILayout.TextField(
"Username", currentConnection.User, GUILayout.Width(halfWidth));
816 GUILayout.EndHorizontal();
817 GUILayout.BeginHorizontal();
818 GUILayout.FlexibleSpace();
819 currentConnection.Password = EditorGUILayout.PasswordField(
"Password", currentConnection.Password, GUILayout.Width(halfWidth));
820 GUILayout.EndHorizontal();
821 GUILayout.BeginHorizontal();
823 EditorGUIUtility.labelWidth = 152;
825 bool processAll = EditorGUILayout.Toggle(
828 GUILayout.Width(176));
830 EditorGUIUtility.labelWidth = 86;
832 bool fullReinstall = EditorGUILayout.Toggle(
835 GUILayout.ExpandWidth(
false));
836 EditorGUIUtility.labelWidth = previousLabelWidth;
838 if (EditorGUI.EndChangeCheck())
840 SessionState.SetInt(
"_MRTK_BuildWindow_CurrentDeviceIndex", currentConnectionInfoIndex);
846 if (currentConnection.IP.Contains(
"127.0.0.1"))
848 currentConnection.IP =
"Local Machine";
851 portalConnections.
Connections[currentConnectionInfoIndex] = currentConnection;
852 UpdatePortalConnections();
856 GUILayout.FlexibleSpace();
859 if (!IsLocalConnection(currentConnection))
861 GUI.enabled = IsValidIpAddress(currentConnection.IP) && IsCredentialsValid(currentConnection);
863 if (GUILayout.Button(
"Connect", GUILayout.Width(quarterWidth)))
865 EditorApplication.delayCall += () =>
869 if (machineName != null)
871 currentConnection.MachineName = machineName.
ComputerName;
874 portalConnections.
Connections[currentConnectionInfoIndex] = currentConnection;
875 UpdatePortalConnections();
883 GUI.enabled = DevicePortalConnectionEnabled && CanInstall;
886 if (GUILayout.Button(
"Open Device Portal", GUILayout.Width(quarterWidth)))
888 EditorApplication.delayCall += () => OpenDevicePortal(portalConnections);
893 GUILayout.EndHorizontal();
896 if (builds.Count == 0)
898 GUILayout.Label(
"*** No builds found in build directory", EditorStyles.boldLabel);
902 EditorGUILayout.Separator();
903 GUILayout.BeginVertical(GUILayout.ExpandHeight(
true));
904 scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.ExpandHeight(
true), GUILayout.ExpandWidth(
true));
906 foreach (var fullBuildLocation
in builds)
908 int lastBackslashIndex = fullBuildLocation.LastIndexOf(
"\\", StringComparison.Ordinal);
910 var directoryDate = Directory.GetLastWriteTime(fullBuildLocation).ToString(
"yyyy/MM/dd HH:mm:ss");
911 string packageName = fullBuildLocation.Substring(lastBackslashIndex + 1);
914 EditorGUILayout.BeginHorizontal();
917 GUI.enabled = CanInstall;
918 if (GUILayout.Button(
"Install", GUILayout.Width(96)))
920 EditorApplication.delayCall += () =>
924 InstallAppOnDevicesList(fullBuildLocation, portalConnections);
928 InstallOnTargetDevice(fullBuildLocation, currentConnection);
936 GUI.enabled = CanInstall;
938 if (GUILayout.Button(
"Uninstall", GUILayout.Width(96)))
940 EditorApplication.delayCall += () =>
944 UninstallAppOnDevicesList(portalConnections);
948 UninstallAppOnTargetDevice(familyPackageName, currentConnection);
955 bool canLaunchLocal = currentConnectionInfoIndex == 0 && IsHoloLensConnectedUsb;
956 bool canLaunchRemote = DevicePortalConnectionEnabled && CanInstall && currentConnectionInfoIndex != 0;
959 GUI.enabled = canLaunchLocal || canLaunchRemote;
961 if (GUILayout.Button(
new GUIContent(isAppRunning ?
"Kill App" :
"Launch App",
"These are remote commands only"), GUILayout.Width(96)))
963 EditorApplication.delayCall += () =>
969 KillAppOnDeviceList(portalConnections);
970 isAppRunning =
false;
974 isAppRunning = !KillAppOnTargetDevice(currentConnection);
981 LaunchAppOnDeviceList(portalConnections);
986 isAppRunning = LaunchAppOnTargetDevice(currentConnection);
995 string localLogPath =
string.Format(
"%USERPROFILE%\\AppData\\Local\\Packages\\{0}\\TempState\\UnityPlayer.log", PlayerSettings.productName);
996 bool localLogExists = File.Exists(localLogPath);
998 GUI.enabled = localLogExists || canLaunchRemote || canLaunchLocal;
1000 if (GUILayout.Button(
"View Log", GUILayout.Width(96)))
1002 EditorApplication.delayCall += () =>
1006 OpenLogFilesOnDeviceList(portalConnections, localLogPath);
1010 OpenLogFileForTargetDevice(currentConnection, localLogPath);
1018 GUILayout.Label(
new GUIContent(packageName +
" (" + directoryDate +
")"));
1019 EditorGUILayout.EndHorizontal();
1022 GUILayout.EndScrollView();
1023 GUILayout.EndVertical();
1026 GUILayout.EndVertical();
1029 #endregion // Methods 1033 private void BuildAll(
bool install =
true)
1043 PlayerSettings.productName,
1050 showDialog: !install))
1058 string fullBuildLocation = CalcMostRecentBuild();
1062 InstallAppOnDevicesList(fullBuildLocation, portalConnections);
1066 InstallOnTargetDevice(fullBuildLocation, portalConnections.
Connections[currentConnectionInfoIndex]);
1071 private void UpdateBuilds()
1075 var curScriptingBackend = PlayerSettings.GetScriptingBackend(BuildTargetGroup.WSA);
1076 string appxDirectory = curScriptingBackend == ScriptingImplementation.IL2CPP ?
"AppPackages\\" + PlayerSettings.productName : PlayerSettings.productName +
"\\AppPackages";
1080 appPackageDirectories.Clear();
1082 foreach (
string appBuild
in buildList)
1084 if (appBuild.Contains(appxDirectory) && !appBuild.Contains(appxDirectory +
"\\"))
1086 appPackageDirectories.AddRange(Directory.GetDirectories(appBuild));
1090 IEnumerable<string> selectedDirectories =
1091 from
string directory in appPackageDirectories
1092 orderby Directory.GetLastWriteTime(directory) descending
1093 select Path.GetFullPath(directory);
1094 builds.AddRange(selectedDirectories);
1096 catch (DirectoryNotFoundException)
1101 familyPackageName = CalcPackageFamilyName();
1103 timeLastUpdatedBuilds = Time.realtimeSinceStartup;
1106 private string CalcMostRecentBuild()
1109 DateTime mostRecent = DateTime.MinValue;
1110 string mostRecentBuild =
string.Empty;
1112 foreach (var fullBuildLocation
in builds)
1114 DateTime directoryDate = Directory.GetLastWriteTime(fullBuildLocation);
1116 if (directoryDate > mostRecent)
1118 mostRecentBuild = fullBuildLocation;
1119 mostRecent = directoryDate;
1123 return mostRecentBuild;
1126 private void UpdatePortalConnections()
1128 targetIps =
new string[portalConnections.
Connections.Count];
1129 if (currentConnectionInfoIndex > portalConnections.
Connections.Count - 1)
1131 currentConnectionInfoIndex = portalConnections.
Connections.Count - 1;
1134 targetIps[0] =
"Local Machine";
1135 for (
int i = 1; i < targetIps.Length; i++)
1137 targetIps[i] = portalConnections.
Connections[i].MachineName;
1144 private static bool IsLocalConnection(
ConnectInfo connection)
1146 return connection.
IP.Contains(
"Local Machine") || connection.
IP.Contains(
"127.0.0.1");
1149 private static bool IsCredentialsValid(
ConnectInfo connection)
1151 return !
string.IsNullOrEmpty(connection.
User) && !
string.IsNullOrEmpty(connection.
IP);
1154 private static bool IsValidIpAddress(
string ip)
1156 if (
string.IsNullOrEmpty(ip))
1161 if (ip.Contains(
"Local Machine"))
1166 if (ip.Contains(
"0.0.0.0"))
1171 var subAddresses = ip.Split(
'.');
1172 return subAddresses.Length > 3;
1175 private static string CalcPackageFamilyName()
1177 if (appPackageDirectories.Count == 0)
1179 return string.Empty;
1185 if (manifests.Length == 0)
1188 return string.Empty;
1191 string manifest = manifests[0];
1194 using (var reader =
new XmlTextReader(manifest))
1196 while (reader.Read())
1198 switch (reader.NodeType)
1200 case XmlNodeType.Element:
1201 if (reader.Name.Equals(
"identity", StringComparison.OrdinalIgnoreCase))
1203 while (reader.MoveToNextAttribute())
1205 if (reader.Name.Equals(
"name", StringComparison.OrdinalIgnoreCase))
1207 return reader.Value;
1217 Debug.LogError(
"Unable to find PackageFamilyName in manifest file (" + manifest +
")");
1218 return string.Empty;
1223 #region Device Portal Commands 1229 if (IsHoloLensConnectedUsb)
1234 for (
int i = 0; i < targetDevices.
Connections.Count; i++)
1236 bool isLocalMachine = IsLocalConnection(targetDevices.
Connections[i]);
1238 if (isLocalMachine && !IsHoloLensConnectedUsb)
1243 if (IsHoloLensConnectedUsb)
1245 if (isLocalMachine || usbMachine != null && usbMachine.
ComputerName != targetDevices.
Connections[i].MachineName)
1252 if (!isLocalMachine)
1260 private static void InstallOnTargetDevice(
string buildPath,
ConnectInfo targetDevice)
1262 isAppRunning =
false;
1264 string packageFamilyName = CalcPackageFamilyName();
1266 if (
string.IsNullOrEmpty(packageFamilyName))
1271 if (IsLocalConnection(targetDevice) && !IsHoloLensConnectedUsb || buildPath.Contains(
"x64"))
1273 FileInfo[] installerFiles =
new DirectoryInfo(buildPath).GetFiles(
"*.ps1");
1274 if (installerFiles.Length == 1)
1276 var pInfo =
new ProcessStartInfo
1278 FileName =
"powershell.exe",
1279 CreateNoWindow =
false,
1280 Arguments =
string.Format(
"-executionpolicy bypass -File \"{0}\"", installerFiles[0].FullName)
1283 var process =
new Process { StartInfo = pInfo };
1291 if (buildPath.Contains(
"x64"))
1297 FileInfo[] files =
new DirectoryInfo(buildPath).GetFiles(
"*.appx");
1298 files = files.Length == 0 ?
new DirectoryInfo(buildPath).GetFiles(
"*.appxbundle") : files;
1300 if (files.Length == 0)
1302 Debug.LogErrorFormat(
"No APPX found in folder build folder ({0})", buildPath);
1314 string packageFamilyName = CalcPackageFamilyName();
1316 if (
string.IsNullOrEmpty(packageFamilyName))
1323 UninstallAppOnDevicesList(targetList);
1328 for (
int i = 0; i < targetList.
Connections.Count; i++)
1330 EditorUtility.DisplayProgressBar(
"Installing on devices",
1331 string.Format(
"Installing on {0}", targetList.
Connections[i].MachineName),
1334 InstallOnTargetDevice(buildPath, targetList.
Connections[i]);
1339 Debug.LogError(e.Message);
1342 EditorUtility.ClearProgressBar();
1345 private static void UninstallAppOnTargetDevice(
string packageFamilyName,
ConnectInfo currentConnection,
bool showDialog =
true)
1347 isAppRunning =
false;
1349 if (IsLocalConnection(currentConnection) && !IsHoloLensConnectedUsb)
1351 var pInfo =
new ProcessStartInfo
1353 FileName =
"powershell.exe",
1354 CreateNoWindow =
true,
1355 Arguments =
string.Format(
"-windowstyle hidden -nologo Get-AppxPackage *{0}* | Remove-AppxPackage", packageFamilyName)
1358 var process =
new Process { StartInfo = pInfo };
1372 string packageFamilyName = CalcPackageFamilyName();
1374 if (
string.IsNullOrEmpty(packageFamilyName))
1381 for (
int i = 0; i < targetList.
Connections.Count; i++)
1383 EditorUtility.DisplayProgressBar(
"Uninstalling on devices",
string.Format(
"Uninstalling ({0})", targetList.
Connections[i].IP), i / (
float)targetList.
Connections.Count);
1384 UninstallAppOnTargetDevice(packageFamilyName, targetList.
Connections[i],
false);
1389 Debug.LogError(e.ToString());
1392 EditorUtility.ClearProgressBar();
1395 private static bool LaunchAppOnTargetDevice(
ConnectInfo targetDevice,
bool showDialog =
true)
1397 string packageFamilyName = CalcPackageFamilyName();
1399 if (
string.IsNullOrEmpty(packageFamilyName))
1404 if (IsLocalConnection(targetDevice) && !IsHoloLensConnectedUsb)
1411 EditorUtility.DisplayProgressBar(
"Launching Application",
string.Format(
"Launching {0} on {1}", packageFamilyName, targetDevice.
MachineName), 0.25f);
1419 EditorUtility.ClearProgressBar();
1427 for (
int i = 0; i < targetDevices.
Connections.Count; i++)
1429 EditorUtility.DisplayProgressBar(
"Launching App on devices",
1430 string.Format(
"Launching on {0}", targetDevices.
Connections[i].IP),
1433 LaunchAppOnTargetDevice(targetDevices.
Connections[i],
false);
1437 private static bool KillAppOnTargetDevice(
ConnectInfo targetDevice,
bool showDialog =
true)
1439 string packageFamilyName = CalcPackageFamilyName();
1441 if (
string.IsNullOrEmpty(packageFamilyName))
1446 if (IsLocalConnection(targetDevice) && !IsHoloLensConnectedUsb)
1453 EditorUtility.DisplayProgressBar(
"Stopping Application",
string.Format(
"Stopping {0} on {1}", packageFamilyName, targetDevice.
MachineName), 0.5f);
1461 EditorUtility.ClearProgressBar();
1469 for (
int i = 0; i < targetDevices.
Connections.Count; i++)
1471 EditorUtility.DisplayProgressBar(
"Stopping Application on devices",
1472 string.Format(
"Stopping on {0}", targetDevices.
Connections[i].MachineName),
1474 KillAppOnTargetDevice(targetDevices.
Connections[i],
false);
1478 private static void OpenLogFileForTargetDevice(
ConnectInfo targetDevice,
string localLogPath)
1480 string packageFamilyName = CalcPackageFamilyName();
1482 if (
string.IsNullOrEmpty(packageFamilyName))
1487 if (IsLocalConnection(targetDevice) && File.Exists(localLogPath))
1489 Process.Start(localLogPath);
1493 if (!IsLocalConnection(targetDevice) || IsHoloLensConnectedUsb)
1499 Debug.Log(
"No Log Found");
1504 for (
int i = 0; i < targetDevices.
Connections.Count; i++)
1506 OpenLogFileForTargetDevice(targetDevices.
Connections[i], localLogPath);