Example #1
0
        private static void UpdateDependenciesElement(UwpBuildInfo buildInfo, XElement dependencies, XNamespace defaultNamespace)
        {
            if (string.IsNullOrWhiteSpace(buildInfo.UwpSdk))
            {
                var windowsSdkPaths = Directory.GetDirectories(@"C:\Program Files (x86)\Windows Kits\10\Lib");

                for (int i = 0; i < windowsSdkPaths.Length; i++)
                {
                    windowsSdkPaths[i] = windowsSdkPaths[i].Substring(windowsSdkPaths[i].LastIndexOf(@"\", StringComparison.Ordinal) + 1);
                }

                EditorUserBuildSettings.wsaUWPSDK = windowsSdkPaths[windowsSdkPaths.Length - 1];
            }

            string maxVersionTested = buildInfo.UwpSdk;
            string minVersion       = buildInfo.MinSdk;

            if (string.IsNullOrWhiteSpace(buildInfo.MinSdk))
            {
                minVersion = UwpBuildDeployPreferences.MIN_SDK_VERSION.ToString();
            }

            // Clear any we had before.
            dependencies.RemoveAll();

            foreach (var family in buildInfo.BuildTargetFamilies)
            {
                dependencies.Add(
                    new XElement(defaultNamespace + "TargetDeviceFamily",
                                 new XAttribute("Name", $"Windows.{family}"),
                                 new XAttribute("MinVersion", minVersion),
                                 new XAttribute("MaxVersionTested", maxVersionTested)));
            }

            if (!dependencies.HasElements)
            {
                dependencies.Add(
                    new XElement(defaultNamespace + "TargetDeviceFamily",
                                 new XAttribute("Name", "Windows.Universal"),
                                 new XAttribute("MinVersion", minVersion),
                                 new XAttribute("MaxVersionTested", maxVersionTested)));
            }
        }
Example #2
0
        private static async Task BuildAppxAsync(UwpBuildInfo buildInfo)
        {
            progress = 0f;

            var slnOutputPath = Path.Combine(buildInfo.OutputDirectory, buildInfo.SolutionPath);

            if (!File.Exists(slnOutputPath))
            {
                Debug.LogError("Unable to find Solution to build from!");
                return;
            }

            // Get and validate the msBuild path...
            var msBuildPath = await FindMsBuildPathAsync();

            if (!File.Exists(msBuildPath))
            {
                Debug.LogError($"MSBuild.exe is missing or invalid!\n{msBuildPath}");
                return;
            }

            var storagePath         = Path.GetFullPath(Path.Combine(Path.Combine(BuildDeployPreferences.ApplicationDataPath, ".."), buildInfo.OutputDirectory));
            var solutionProjectPath = Path.GetFullPath(Path.Combine(storagePath, buildInfo.SolutionPath));
            var appxBuildArgs       = $"\"{solutionProjectPath}\" /t:{(buildInfo.RebuildAppx ? "Rebuild" : "Build")} /p:Configuration={buildInfo.Configuration} /p:Platform={buildInfo.PlatformArchitecture} /verbosity:{buildInfo.Verbosity}";

            Debug.Log(appxBuildArgs);
            progress = 0.5f;
            var processResult = await new Process().RunAsync(appxBuildArgs, msBuildPath, true, cancellationTokenSource.Token, false);

            switch (processResult.ExitCode)
            {
            case 0:
                if (buildInfo.IsCommandLine)
                {
                    Debug.Log(string.Join("\n", processResult.Output));
                }
                break;

            case -1073741510:
                Debug.LogWarning("The build was terminated either by user's keyboard input CTRL+C or CTRL+Break or closing command prompt window.");
                break;

            default:
                if (processResult.ExitCode != 0)
                {
                    Debug.LogError($"{buildInfo.BundleIdentifier} appx build Failed! ErrorCode:{processResult.ExitCode}:{string.Join("\n", processResult.Errors)}");

                    if (buildInfo.IsCommandLine)
                    {
                        var buildOutput = new StringBuilder();

                        if (processResult.Output?.Length > 0)
                        {
                            buildOutput.Append("Appx Build Output:");

                            foreach (var message in processResult.Output)
                            {
                                buildOutput.Append($"\n{message}");
                            }
                        }

                        if (processResult.Errors?.Length > 0)
                        {
                            buildOutput.Append("Appx Build Errors:");

                            foreach (var error in processResult.Errors)
                            {
                                buildOutput.Append($"\n{error}");
                            }
                        }

                        Debug.LogError(buildOutput);
                    }
                }

                break;
            }

            progress = 1f;
        }
Example #3
0
        private static bool UpdateAppxManifest(UwpBuildInfo buildInfo)
        {
            progress = 0.25f;

            // Find the manifest, assume the one we want is the first one
            string[] manifests = Directory.GetFiles(buildInfo.AbsoluteOutputDirectory, "Package.appxmanifest", SearchOption.AllDirectories);

            if (manifests.Length == 0)
            {
                Debug.LogError($"Unable to find Package.appxmanifest file for build (in path - {buildInfo.AbsoluteOutputDirectory})");
                return(false);
            }

            if (manifests.Length > 1)
            {
                Debug.LogWarning("Found more than one appxmanifest in the target build folder!");
            }

            const string uap5 = "uap5";

            var rootNode     = XElement.Load(manifests[0]);
            var identityNode = rootNode.Element(rootNode.GetDefaultNamespace() + "Identity");

            if (identityNode == null)
            {
                Debug.LogError($"Package.appxmanifest for build (in path - {buildInfo.AbsoluteOutputDirectory}) is missing an <Identity /> node");
                return(false);
            }

            var dependencies = rootNode.Element(rootNode.GetDefaultNamespace() + "Dependencies");

            if (dependencies == null)
            {
                Debug.LogError($"Package.appxmanifest for build (in path - {buildInfo.AbsoluteOutputDirectory}) is missing <Dependencies /> node.");
                return(false);
            }

            UpdateDependenciesElement(buildInfo, dependencies, rootNode.GetDefaultNamespace());

            // Setup the 3d app icon.
            if (!string.IsNullOrWhiteSpace(UwpBuildDeployPreferences.MixedRealityAppIconPath))
            {
                // Add the uap5 namespace if it doesn't exist.
                if (rootNode.GetNamespaceOfPrefix(uap5) == null)
                {
                    rootNode.Add(new XAttribute(XNamespace.Xmlns + uap5, Uap5NameSpace));
                }

                var ignorable = rootNode.Attribute(XName.Get("IgnorableNamespaces"));

                if (ignorable != null)
                {
                    if (!ignorable.Value.Contains(uap5))
                    {
                        ignorable.Value = $"{ignorable.Value} {uap5}";
                    }
                }

                if (!string.IsNullOrEmpty(UwpBuildDeployPreferences.MixedRealityAppIconPath))
                {
                    string modelPath;

                    // find mixed reality model container
                    var modelContainer = rootNode.Descendants(Uap5NameSpace + "MixedRealityModel").ToArray();

                    try
                    {
                        var modelFullPath          = Path.GetFullPath(UwpBuildDeployPreferences.MixedRealityAppIconPath);
                        var absoluteBuildDirectory = Path.GetFullPath(BuildDeployPreferences.BuildDirectory);

                        modelPath = $"{absoluteBuildDirectory}/{buildInfo.BundleIdentifier}/Assets/{Path.GetFileName(modelFullPath)}";

                        if (File.Exists(modelPath))
                        {
                            File.Delete(modelPath);
                        }

                        File.Copy(modelFullPath, modelPath);
                        modelPath = modelPath.Replace($"{absoluteBuildDirectory}/{buildInfo.BundleIdentifier}/", string.Empty).Replace("/", "\\");
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(e.Message);
                        return(false);
                    }

                    if (modelContainer.Any())
                    {
                        var element = modelContainer.First();
                        var path    = element.Attribute(XName.Get("Path"));

                        if (path != null)
                        {
                            path.Value = modelPath;
                        }
                        else
                        {
                            element.Add(new XAttribute("Path", modelPath));
                        }
                    }
                    else
                    {
                        var modelElement = new XElement(Uap5NameSpace + "MixedRealityModel");
                        var defaultTile  = rootNode.Descendants(UapNameSpace + "DefaultTile").First();
                        defaultTile.Add(modelElement);
                        modelElement.Add(new XAttribute("Path", modelPath));
                    }
                }
            }

            // We use XName.Get instead of string -> XName implicit conversion because
            // when we pass in the string "Version", the program doesn't find the attribute.
            // Best guess as to why this happens is that implicit string conversion doesn't set the namespace to empty
            var versionAttr = identityNode.Attribute(XName.Get("Version"));

            if (versionAttr == null)
            {
                Debug.LogError($"Package.appxmanifest for build (in path - {buildInfo.AbsoluteOutputDirectory}) is missing a Version attribute in the <Identity /> node.");
                return(false);
            }

            versionAttr.Value = PlayerSettings.WSA.packageVersion.ToString();
            rootNode.Save(manifests[0]);
            return(true);
        }
Example #4
0
        /// <summary>
        /// Build the UWP appx bundle for this project.
        /// </summary>
        /// <param name="buildInfo"></param>
        /// <returns>True, if the appx build was successful.</returns>
        public static void BuildAppx(UwpBuildInfo buildInfo)
        {
            if (IsBuilding)
            {
                Debug.LogError("Build already in progress!");
                return;
            }

            IsBuilding = true;
            EditorAssemblyReloadManager.LockReloadAssemblies = true;

            cancellationTokenSource = new CancellationTokenSource();

            if (buildInfo.IsCommandLine)
            {
                // We don't need stack traces on all our logs. Makes things a lot easier to read.
                Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None);
            }

            progress = 0f;

            // Ensure that the generated .appx version increments by modifying Package.appxmanifest
            try
            {
                if (!UpdateAppxManifest(buildInfo))
                {
                    throw new Exception();
                }
            }
            catch (Exception)
            {
                Debug.LogError("Failed to update appxmanifest!");

                if (buildInfo.IsCommandLine)
                {
                    throw;
                }

                return;
            }

            Task.Run(async() =>
            {
                try
                {
                    await BuildAppxAsync(buildInfo);
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }

                IsBuilding = false;
            });

            while (!EditorUtility.DisplayCancelableProgressBar("XRTK Appx Build", string.Empty, progress))
            {
                if (!IsBuilding)
                {
                    break;
                }

                EditorApplication.Step();
            }

            cancellationTokenSource.Cancel();
            cancellationTokenSource.Dispose();
            cancellationTokenSource = null;
            IsBuilding = false;
            EditorApplication.delayCall += EditorUtility.ClearProgressBar;
            EditorAssemblyReloadManager.LockReloadAssemblies = false;
            AssetDatabase.SaveAssets();

            if (!buildInfo.IsCommandLine && buildInfo.Install)
            {
                //string fullBuildLocation = BuildDeployWindowOld.CalcMostRecentBuild();

                //if (UwpBuildDeployPreferences.TargetAllConnections)
                //{
                //    await BuildDeployWindowOld.InstallAppOnDevicesListAsync(fullBuildLocation, BuildDeployWindowOld.DevicePortalConnections);
                //}
                //else
                //{
                //    await BuildDeployWindowOld.InstallOnTargetDeviceAsync(fullBuildLocation, BuildDeployWindowOld.CurrentConnection);
                //}
            }
        }