| File: GenerateTizenManifest.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 GenerateTizenManifest : Task { const string ApplicationIdPlaceholder = "maui-application-id-placeholder"; const string LabelPlaceholder = "maui-application-title-placeholder"; const string ManifestVersionPlaceholder = "0.0.0"; const string AppIconPlaceholder = "maui-appicon-placeholder"; const string TizenManifestFileName = "tizen-manifest.xml"; const string IconDefaultDpiType = "xhdpi"; const string IconImageExtension = ".png"; const string UiApplicationName = "ui-application"; const string PackageName = "package"; const string AppidName = "appid"; const string VersionName = "version"; const string LabelName = "label"; const string IconName = "icon"; const string SplashScreensName = "splash-screens"; const string SplashScreenName = "splash-screen"; const string DpiName = "dpi"; [Required] public string IntermediateOutputPath { get; set; } = null!; [Required] public string TizenManifestFile { get; set; } = TizenManifestFileName; public string GeneratedFilename { get; set; } = TizenManifestFileName; 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 GeneratedTizenManifest { get; set; } = null!; string? _tizenManifestFilePath; public override bool Execute() { try { Directory.CreateDirectory(IntermediateOutputPath); _tizenManifestFilePath = Path.Combine(Environment.CurrentDirectory, TizenManifestFile); var targetFilename = Path.Combine(IntermediateOutputPath, GeneratedFilename); var manifest = XDocument.Load(_tizenManifestFilePath); UpdateManifest(manifest); manifest.Save(targetFilename); GeneratedTizenManifest = new TaskItem(targetFilename); } catch (Exception ex) { Log.LogErrorFromException(ex); } return !Log.HasLoggedErrors; } void UpdateManifest(XDocument tizenManifest) { var xmlns = tizenManifest.Root!.GetDefaultNamespace(); var manifest = tizenManifest.Root; var uiApplication = manifest.Element(xmlns + UiApplicationName); if (manifest == null || uiApplication == null) { return; } UpdateSharedManifest(xmlns, manifest); UpdateSharedResources(xmlns, manifest); } void UpdateSharedManifest(XNamespace xmlns, XElement manifest) { var uiApplication = manifest.Element(xmlns + UiApplicationName); if (!string.IsNullOrEmpty(ApplicationId)) { UpdateElementAttribute(manifest, PackageName, ApplicationId, ApplicationIdPlaceholder); UpdateElementAttribute(uiApplication, AppidName, ApplicationId, ApplicationIdPlaceholder); } if (!string.IsNullOrEmpty(ApplicationDisplayVersion)) { if (TryMergeVersionNumbers(ApplicationDisplayVersion, out var finalVersion)) { UpdateElementAttribute(manifest, VersionName, finalVersion, ManifestVersionPlaceholder); } else { Log.LogWarning($"ApplicationDisplayVersion '{ApplicationDisplayVersion}' was not a valid version for Tizen"); } } if (!string.IsNullOrEmpty(ApplicationTitle)) { var label = uiApplication.Element(xmlns + LabelName); if (label == null) { label = new XElement(xmlns + LabelName); uiApplication.AddFirst(label); } UpdateElementValue(label, ApplicationTitle, LabelPlaceholder); } } void UpdateSharedResources(XNamespace xmlns, XElement manifestElement) { var uiApplicationElement = manifestElement.Element(xmlns + UiApplicationName); var appIconInfo = AppIcon?.Length > 0 ? ResizeImageInfo.Parse(AppIcon[0]) : null; if (appIconInfo != null) { var xiconName = xmlns + IconName; var iconElements = uiApplicationElement.Elements(xiconName); var iconPlaceholderElements = iconElements.Where(d => d.Value == AppIconPlaceholder); foreach (var icon in iconPlaceholderElements) { if (icon.Attribute(DpiName) == null) { var defaultDpi = DpiPath.Tizen.AppIcon.Where(n => n.Path.EndsWith(IconDefaultDpiType)).FirstOrDefault(); icon.Value = IconDefaultDpiType + "/" + appIconInfo.OutputName + defaultDpi.FileSuffix + IconImageExtension; } else { string dpiValue = icon.Attribute(DpiName).Value; string fileSuffix = dpiValue == IconDefaultDpiType ? "xhigh" : "high"; icon.Value = dpiValue + "/" + appIconInfo.OutputName + fileSuffix + IconImageExtension; } } } var splashInfo = SplashScreen?.Length > 0 ? ResizeImageInfo.Parse(SplashScreen[0]) : null; if (splashInfo != null) { var splashscreensElement = uiApplicationElement.Element(xmlns + SplashScreensName); if (splashscreensElement == null) { splashscreensElement = new XElement(xmlns + SplashScreensName); uiApplicationElement.Add(splashscreensElement); } foreach (var image in TizenSplashUpdater.splashDpiMap) { var splashElements = splashscreensElement.Elements(xmlns + SplashScreenName).Where( d => d.Attribute("type")?.Value == "img" && d.Attribute(DpiName)?.Value == image.Key.Resolution && d.Attribute("orientation")?.Value == image.Key.Orientation && d.Attribute("indicator-display")?.Value == "false"); if (splashElements.Count() == 0) { var splashscreenElement = new XElement(xmlns + SplashScreenName); splashscreenElement.SetAttributeValue("src", image.Value); splashscreenElement.SetAttributeValue("type", "img"); splashscreenElement.SetAttributeValue(DpiName, image.Key.Resolution); splashscreenElement.SetAttributeValue("orientation", image.Key.Orientation); splashscreenElement.SetAttributeValue("indicator-display", "false"); splashscreensElement.Add(splashscreenElement); } } } } void UpdateElementAttribute(XElement element, XName attrName, string? value, string? placeholder) { var attr = element.Attribute(attrName); if (attr == null || string.IsNullOrEmpty(attr.Value) || attr.Value == placeholder) { element.SetAttributeValue(attrName, value); } } void UpdateElementValue(XElement element, string? value, string? placeholder) { if (string.IsNullOrEmpty(element.Value) || element.Value == placeholder) { element.Value = value; } } public static bool TryMergeVersionNumbers(string? displayVersion, out string? finalVersion) { displayVersion = displayVersion?.Trim(); finalVersion = null; var parts = displayVersion?.Split('.') ?? Array.Empty<string>(); if (parts.Length > 3) return false; var v = new int[3]; for (var i = 0; i < 3 && i < parts.Length; i++) { if (!int.TryParse(parts[i], out var parsed)) return false; v[i] = parsed; } if (!VerifyTizenVersion(v[0], v[1], v[2])) return false; finalVersion = $"{v[0]:0}.{v[1]:0}.{v[2]:0}"; return true; } static bool VerifyTizenVersion(int x, int y, int z) { return (x < 0 || x > 255 || y < 0 || y > 255 || z < 0 || z > 65535) ? false : true; } } }