Created
August 31, 2020 23:39
-
-
Save xwipeoutx/913449ad97a719e434f2803d8476183f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Xml; | |
using UnityEditor; | |
using UnityEditor.Build; | |
using UnityEditor.Build.Reporting; | |
using UnityEngine; | |
namespace Project.Scripts.Editor | |
{ | |
/// <summary> | |
/// Adds a 3d icon to the project and appxmanifest. | |
/// See https://docs.microsoft.com/en-us/windows/mixed-reality/implementing-3d-app-launchers | |
/// </summary> | |
public class MixedReality3dAppLauncher : IPostprocessBuildWithReport | |
{ | |
private const string Uap5Namespace = "http://schemas.microsoft.com/appx/manifest/uap/windows10/5"; | |
private const string AppIconSourcePath = "Assets/app-icon.glb"; | |
private const string AppIconAssetPath = "Assets\\app-icon.glb"; | |
public int callbackOrder => 0; | |
public void OnPostprocessBuild(BuildReport report) | |
{ | |
if (report.summary.platform != BuildTarget.WSAPlayer) | |
return; | |
PatchProjectAndManifest(report.summary.outputPath, Application.productName); | |
} | |
[MenuItem("UWP Tools/Patch Manifest and project")] | |
public static void ManuallyPatch() | |
{ | |
var buildLocation = EditorUserBuildSettings.GetBuildLocation(BuildTarget.WSAPlayer); | |
if (!Directory.Exists(buildLocation)) | |
{ | |
var defaultOptions = new BuildPlayerOptions(); | |
var options = BuildPlayerWindow.DefaultBuildMethods.GetBuildPlayerOptions(defaultOptions); | |
buildLocation = options.locationPathName; | |
} | |
PatchProjectAndManifest(buildLocation, Application.productName); | |
} | |
static void PatchProjectAndManifest(string path, string appName) | |
{ | |
var modelPath = Path.Combine(Directory.GetCurrentDirectory(), AppIconSourcePath); | |
if (!File.Exists(modelPath)) | |
{ | |
Debug.LogWarning(" MixedReality3dAppLauncher: Cannot add 3d model - please place one in Assets/app-icon.glb"); | |
return; | |
} | |
var projectPath = Path.Combine(path, appName); | |
CopyModelAndPatchXProj(appName, projectPath, modelPath); | |
PatchAppxWithIcon(projectPath); | |
Debug.Log(" MixedReality3dAppLauncher: Patched with 3d app launcher"); | |
} | |
private static void CopyModelAndPatchXProj(string appName, string projectPath, string modelPath) | |
{ | |
var destinationModelPath = Path.Combine(projectPath, AppIconAssetPath); | |
if (File.GetLastWriteTimeUtc(modelPath) > File.GetLastWriteTimeUtc(destinationModelPath)) | |
File.Copy(modelPath, destinationModelPath, true); | |
var projectXmlPath = Path.Combine(projectPath, $"{appName}.vcxproj"); | |
var doc = new XmlDocument(); | |
doc.LoadXml(File.ReadAllText(projectXmlPath)); | |
var nsmgr = new XmlNamespaceManager(doc.NameTable); | |
nsmgr.AddNamespace("ns", doc.DocumentElement.NamespaceURI); | |
var itemGroup = doc.SelectSingleNode("//ns:AppxManifest", nsmgr).ParentNode; | |
var hasExisting = itemGroup.ChildNodes.Cast<XmlNode>().Any(n => n.Attributes[0].Value == AppIconAssetPath); | |
if (!hasExisting) | |
{ | |
Debug.Log(" MixedReality3dAppLauncher: Adding icon include"); | |
var includeNode = doc.CreateNode(XmlNodeType.Element, "None", doc.DocumentElement.NamespaceURI); | |
var includeAttribute = doc.CreateAttribute("Include"); | |
includeAttribute.Value = AppIconAssetPath; | |
includeNode.Attributes.Append(includeAttribute); | |
itemGroup.AppendChild(includeNode); | |
var deploymentContentNode = | |
doc.CreateNode(XmlNodeType.Element, "DeploymentContent", doc.DocumentElement.NamespaceURI); | |
deploymentContentNode.InnerText = "true"; | |
includeNode.AppendChild(deploymentContentNode); | |
} | |
using (var writer = new XmlTextWriter(projectXmlPath, Encoding.UTF8)) | |
{ | |
writer.Formatting = Formatting.Indented; | |
doc.WriteTo(writer); | |
} | |
} | |
private static void PatchAppxWithIcon(string projectPath) | |
{ | |
var manifestPath = Path.Combine(projectPath, "package.appxmanifest"); | |
var doc = new XmlDocument(); | |
doc.LoadXml(File.ReadAllText(manifestPath)); | |
var nsmgr = new XmlNamespaceManager(doc.NameTable); | |
nsmgr.AddNamespace("ns", doc.DocumentElement.NamespaceURI); | |
var packageNode = doc.SelectSingleNode("/ns:Package", nsmgr); | |
var uapNamespace = packageNode.Attributes.Cast<XmlAttribute>().First(a => a.Name == "xmlns:uap").Value; | |
nsmgr.AddNamespace("uap", uapNamespace); | |
nsmgr.AddNamespace("uap5", Uap5Namespace); | |
if (!packageNode.Attributes.Cast<XmlAttribute>().Any(a => a.Name == "xmlns:uap5")) | |
{ | |
var uap5Attribute = doc.CreateAttribute("xmlns:uap5"); | |
uap5Attribute.Value = Uap5Namespace; | |
packageNode.Attributes.Append(uap5Attribute); | |
Debug.Log(" MixedReality3dAppLauncher: Added uap5 namspace to root node"); | |
} | |
var ignoreNamespaces = packageNode.Attributes.Cast<XmlAttribute>().First(a => a.Name == "IgnorableNamespaces"); | |
if (!ignoreNamespaces.Value.Contains("uap5")) | |
{ | |
ignoreNamespaces.Value = ignoreNamespaces.Value + " uap5"; | |
Debug.Log(" MixedReality3dAppLauncher: Added uap5 to IgnorableNamespaces"); | |
} | |
var defaultTileNode = doc.SelectSingleNode("//uap:DefaultTile", nsmgr); | |
if (!defaultTileNode.HasChildNodes) | |
{ | |
var modelNode = doc.CreateNode(XmlNodeType.Element, "uap5:MixedRealityModel", Uap5Namespace); | |
var pathAttribute = doc.CreateAttribute("Path"); | |
pathAttribute.Value = AppIconAssetPath; | |
modelNode.Attributes.Append(pathAttribute); | |
defaultTileNode.AppendChild(modelNode); | |
Debug.Log(" MixedReality3dAppLauncher: Added mixed reality model node"); | |
} | |
else | |
{ | |
var modelNode = doc.SelectSingleNode("//uap5:MixedRealityModel", nsmgr); | |
var pathAttribute = modelNode.Attributes.Cast<XmlAttribute>().First(a => a.Name == "Path"); | |
if (pathAttribute.Value != AppIconAssetPath) | |
{ | |
pathAttribute.Value = AppIconAssetPath; | |
Debug.Log(" MixedReality3dAppLauncher: Updated model path"); | |
} | |
} | |
using (var writer = new XmlTextWriter(manifestPath, Encoding.UTF8)) | |
{ | |
writer.Formatting = Formatting.Indented; | |
doc.WriteTo(writer); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment