| File: GeneratePackageAppxManifest.cs | Web Access |
| Project: src\src\SingleProject\Resizetizer\src\Resizetizer.csproj (Microsoft.Maui.Resizetizer) |
#nullable enable using System; using System.IO; using System.Linq; using System.Xml.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Microsoft.Maui.Resizetizer { public class GeneratePackageAppxManifest : Task { const string DefaultPlaceholder = "$placeholder$"; const string PngPlaceholder = "$placeholder$.png"; const string PackageNamePlaceholder = "maui-package-name-placeholder"; const string PackageVersionPlaceholder = "0.0.0.0"; const string ErrorVersionNumberCombination = "ApplicationDisplayVersion '{0}' was not a valid 3 part semver version number and/or ApplicationVersion '{1}' was not a valid integer."; static readonly XNamespace xmlnsUap = "http://schemas.microsoft.com/appx/manifest/uap/windows10"; [Required] public string IntermediateOutputPath { get; set; } = null!; [Required] public ITaskItem AppxManifest { get; set; } = null!; public string? GeneratedFilename { get; set; } public string? ApplicationId { get; set; } public string? ApplicationDisplayVersion { get; set; } public string? ApplicationVersion { get; set; } public string? ApplicationTitle { get; set; } public ITaskItem[]? AppIcon { get; set; } public ITaskItem[]? SplashScreen { get; set; } [Output] public ITaskItem GeneratedAppxManifest { get; set; } = null!; public override bool Execute() { try { Directory.CreateDirectory(IntermediateOutputPath); var filename = Path.Combine(IntermediateOutputPath, GeneratedFilename ?? "Package.appxmanifest"); var appx = XDocument.Load(AppxManifest.ItemSpec); UpdateManifest(appx); appx.Save(filename); GeneratedAppxManifest = new TaskItem(filename); } catch (Exception ex) { Log.LogErrorFromException(ex); } return !Log.HasLoggedErrors; } void UpdateManifest(XDocument appx) { var appIconInfo = AppIcon?.Length > 0 ? ResizeImageInfo.Parse(AppIcon[0]) : null; var splashInfo = SplashScreen?.Length > 0 ? ResizeImageInfo.Parse(SplashScreen[0]) : null; var xmlns = appx.Root!.GetDefaultNamespace(); // <Identity Name="" Version="" /> if (!string.IsNullOrEmpty(ApplicationId) || !string.IsNullOrEmpty(ApplicationDisplayVersion) || !string.IsNullOrEmpty(ApplicationVersion)) { // <Identity> var xidentity = xmlns + "Identity"; var identity = appx.Root.Element(xidentity); if (identity == null) { identity = new XElement(xidentity); appx.Root.Add(identity); } // Name="" if (!string.IsNullOrEmpty(ApplicationId)) { var xname = "Name"; var attr = identity.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PackageNamePlaceholder) { identity.SetAttributeValue(xname, ApplicationId); } } // Version="" if (!string.IsNullOrEmpty(ApplicationDisplayVersion) || !string.IsNullOrEmpty(ApplicationVersion)) { var xname = "Version"; var attr = identity.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PackageVersionPlaceholder) { if (!TryMergeVersionNumbers(ApplicationDisplayVersion, ApplicationVersion, out var finalVersion)) { Log.LogError(ErrorVersionNumberCombination, ApplicationDisplayVersion, ApplicationVersion); return; } identity.SetAttributeValue(xname, finalVersion); } } } // <Properties> // <DisplayName /> // <Logo /> // </Properties> if (!string.IsNullOrEmpty(ApplicationTitle) || appIconInfo != null) { // <Properties> var xproperties = xmlns + "Properties"; var properties = appx.Root.Element(xproperties); if (properties == null) { properties = new XElement(xproperties); appx.Root.Add(properties); } // <DisplayName> if (!string.IsNullOrEmpty(ApplicationTitle)) { var xname = xmlns + "DisplayName"; var xelem = properties.Element(xname); if (xelem == null || string.IsNullOrEmpty(xelem.Value) || xelem.Value == DefaultPlaceholder) properties.SetElementValue(xname, ApplicationTitle); } // <Logo> if (appIconInfo != null) { var xname = xmlns + "Logo"; var xelem = properties.Element(xname); if (xelem == null || string.IsNullOrEmpty(xelem.Value) || xelem.Value == PngPlaceholder) { var dpi = DpiPath.Windows.StoreLogo[0]; var path = Resizer.GetRasterFileDestination(appIconInfo, dpi, includeScale: false); properties.SetElementValue(xname, path); } } } // <Applications> // <Application> // <uap:VisualElements DisplayName="" Description="" BackgroundColor="" Square150x150Logo="" Square44x44Logo=""> // <uap:DefaultTile Wide310x150Logo="" Square71x71Logo="" Square310x310Logo="" ShortName=""> // <uap:ShowNameOnTiles> // <uap:ShowOn /> // </uap:ShowNameOnTiles> // </uap:DefaultTile> // <uap:SplashScreen Image="" /> // </uap:VisualElements> // </Application> // </Applications> if (!string.IsNullOrEmpty(ApplicationTitle) || appIconInfo != null || splashInfo != null) { // <Applications> var xapplications = xmlns + "Applications"; var applications = appx.Root.Element(xapplications); if (applications == null) { applications = new XElement(xapplications); appx.Root.Add(applications); } // <Application> var xapplication = xmlns + "Application"; var application = applications.Element(xapplication); if (application == null) { application = new XElement(xapplication); applications.Add(application); } // <uap:VisualElements> var xvisual = xmlnsUap + "VisualElements"; var visual = application.Element(xvisual); if (visual == null) { visual = new XElement(xvisual); application.Add(visual); } if (!string.IsNullOrEmpty(ApplicationTitle)) { // DisplayName="" { var xname = "DisplayName"; var attr = visual.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == DefaultPlaceholder) visual.SetAttributeValue(xname, ApplicationTitle); } // Description="" { var xname = "Description"; var attr = visual.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == DefaultPlaceholder) visual.SetAttributeValue(xname, ApplicationTitle); } } // BackgroundColor="" { var xname = "BackgroundColor"; var attr = visual.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value)) visual.SetAttributeValue(xname, "transparent"); } if (appIconInfo != null) { // Square150x150Logo="" { var xname = "Square150x150Logo"; var attr = visual.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PngPlaceholder) { var dpi = DpiPath.Windows.MediumTile[0]; var path = Resizer.GetRasterFileDestination(appIconInfo, dpi, includeScale: false); visual.SetAttributeValue(xname, path); } } // Square44x44Logo="" { var xname = "Square44x44Logo"; var attr = visual.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PngPlaceholder) { var dpi = DpiPath.Windows.Logo[0]; var path = Resizer.GetRasterFileDestination(appIconInfo, dpi, includeScale: false); visual.SetAttributeValue(xname, path); } } } // <uap:DefaultTile> var xtile = xmlnsUap + "DefaultTile"; var tile = visual.Element(xtile); if (tile == null) { tile = new XElement(xtile); visual.Add(tile); } if (appIconInfo != null) { // Wide310x150Logo="" { var xname = "Wide310x150Logo"; var attr = tile.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PngPlaceholder) { var dpi = DpiPath.Windows.WideTile[0]; var path = Resizer.GetRasterFileDestination(appIconInfo, dpi, includeScale: false); tile.SetAttributeValue(xname, path); } } // Square71x71Logo="" { var xname = "Square71x71Logo"; var attr = tile.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PngPlaceholder) { var dpi = DpiPath.Windows.SmallTile[0]; var path = Resizer.GetRasterFileDestination(appIconInfo, dpi, includeScale: false); tile.SetAttributeValue(xname, path); } } // Square310x310Logo="" { var xname = "Square310x310Logo"; var attr = tile.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PngPlaceholder) { var dpi = DpiPath.Windows.LargeTile[0]; var path = Resizer.GetRasterFileDestination(appIconInfo, dpi, includeScale: false); tile.SetAttributeValue(xname, path); } } } // ShortName="" if (!string.IsNullOrEmpty(ApplicationTitle)) { var xname = "ShortName"; var attr = tile.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value)) tile.SetAttributeValue(xname, ApplicationTitle); } // <uap:ShowNameOnTiles> var xshowname = xmlnsUap + "ShowNameOnTiles"; var showname = tile.Element(xshowname); if (showname == null) { showname = new XElement(xshowname); tile.Add(showname); } // <ShowOn> var xshowon = xmlnsUap + "ShowOn"; var showons = showname.Elements(xshowon).ToArray(); if (showons.All(x => x.Attribute("Tile")?.Value != "square150x150Logo")) showname.Add(new XElement(xshowon, new XAttribute("Tile", "square150x150Logo"))); if (showons.All(x => x.Attribute("Tile")?.Value != "wide310x150Logo")) showname.Add(new XElement(xshowon, new XAttribute("Tile", "wide310x150Logo"))); if (splashInfo != null) { // <uap:SplashScreen> var xsplash = xmlnsUap + "SplashScreen"; var splash = visual.Element(xsplash); if (splash == null) { splash = new XElement(xsplash); visual.Add(splash); } // Image="" { var xname = "Image"; var attr = splash.Attribute(xname); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == PngPlaceholder) { var dpi = DpiPath.Windows.SplashScreen[0]; var path = Resizer.GetRasterFileDestination(splashInfo, dpi, includeScale: false); splash.SetAttributeValue(xname, path); } } } } } public static bool TryMergeVersionNumbers(string? displayVersion, string? version, out string? finalVersion) { displayVersion = displayVersion?.Trim(); version = version?.Trim(); finalVersion = null; // either a 4 part display version and no version or a 3 part display and an int version var parts = displayVersion?.Split('.') ?? Array.Empty<string>(); if (parts.Length > 3 && !string.IsNullOrEmpty(version)) return false; else if (parts.Length > 4) return false; var v = new int[4]; for (var i = 0; i < 4 && i < parts.Length; i++) { if (!int.TryParse(parts[i], out var parsed)) return false; v[i] = parsed; } if (!string.IsNullOrEmpty(version)) { if (!int.TryParse(version, out var parsed)) return false; v[3] = parsed; } finalVersion = $"{v[0]:0}.{v[1]:0}.{v[2]:0}.{v[3]:0}"; return true; } } }