Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/ACTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ void FindXCAssetsDirectory (string main, string secondary, out string mainResult
mainResult = main;
secondaryResult = secondary;

while (!string.IsNullOrEmpty (mainResult) && !mainResult.EndsWith (".xcassets", StringComparison.OrdinalIgnoreCase)) {
while (!string.IsNullOrEmpty (mainResult) && !mainResult.EndsWith (".xcassets", StringComparison.OrdinalIgnoreCase) && !mainResult.EndsWith (".icon", StringComparison.OrdinalIgnoreCase)) {
mainResult = Path.GetDirectoryName (mainResult)!;
if (!string.IsNullOrEmpty (secondaryResult))
secondaryResult = Path.GetDirectoryName (secondaryResult)!;
Expand Down Expand Up @@ -296,13 +296,13 @@ public override bool Execute ()
var vpath = BundleResource.GetVirtualProjectPath (this, imageAsset);
var catalogFullPath = imageAsset.GetMetadata ("FullPath");

// get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc)
// get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, .icon, etc)
var catalog = Path.GetDirectoryName (vpath);
catalogFullPath = Path.GetDirectoryName (catalogFullPath);

var assetType = Path.GetExtension (catalog).TrimStart ('.');

// keep walking up the directory structure until we get to the .xcassets directory
// keep walking up the directory structure until we get to the .xcassets or .icon directory
FindXCAssetsDirectory (catalog, catalogFullPath, out var catalog2, out var catalogFullPath2);
catalog = catalog2;
catalogFullPath = catalogFullPath2;
Expand All @@ -329,11 +329,11 @@ public override bool Execute ()
continue;
}

// filter out everything except paths containing a Contents.json file since our main processing loop only cares about these
if (Path.GetFileName (vpath) != "Contents.json")
continue;

items.Add (asset);
// Handle both Contents.json (for .xcassets) and icon.json (for .icon folders)
var fileName = Path.GetFileName (vpath);
if (fileName == "Contents.json" || fileName == "icon.json") {
items.Add (asset);
}
}

// clone any *.xcassets dirs that need cloning
Expand Down Expand Up @@ -374,8 +374,9 @@ public override bool Execute ()

File.Copy (src, dest, true);

// filter out everything except paths containing a Contents.json file since our main processing loop only cares about these
if (Path.GetFileName (vpath) != "Contents.json")
// Handle both Contents.json (for .xcassets) and icon.json (for .icon folders)
var fileName = Path.GetFileName (vpath);
if (fileName != "Contents.json" && fileName != "icon.json")
continue;

item = new TaskItem (dest);
Expand All @@ -384,16 +385,17 @@ public override bool Execute ()
FindXCAssetsDirectory (Path.GetFullPath (dest), "", out var catalogFullPath, out var _);
items.Add (new AssetInfo (item, vpath, asset.Catalog, catalogFullPath, asset.AssetType));
} else {
// filter out everything except paths containing a Contents.json file since our main processing loop only cares about these
if (Path.GetFileName (vpath) != "Contents.json")
// Handle both Contents.json (for .xcassets) and icon.json (for .icon folders)
var fileName = Path.GetFileName (vpath);
if (fileName != "Contents.json" && fileName != "icon.json")
continue;

items.Add (asset);
}
}
}

// Note: `items` contains only the Contents.json files at this point
// Note: `items` contains only the Contents.json and icon.json files at this point
for (int i = 0; i < items.Count; i++) {
var asset = items [i];
var assetItem = asset.Item;
Expand All @@ -409,8 +411,9 @@ public override bool Execute ()
brandAssetsInAssets.Add (Path.GetFileNameWithoutExtension (Path.GetDirectoryName (vpath)));
}
} else {
if (assetType.Equals ("appiconset", StringComparison.OrdinalIgnoreCase))
if (assetType.Equals ("appiconset", StringComparison.OrdinalIgnoreCase) || assetType.Equals ("icon", StringComparison.OrdinalIgnoreCase)) {
appIconsInAssets.Add (Path.GetFileNameWithoutExtension (Path.GetDirectoryName (vpath)));
}
}

if (unique.Add (catalog)) {
Expand All @@ -420,7 +423,8 @@ public override bool Execute ()
catalogs.Add (item);
}

if (SdkPlatform != "WatchSimulator") {
// Only process Contents.json files for on-demand resources (not icon.json files)
if (SdkPlatform != "WatchSimulator" && Path.GetFileName (vpath) == "Contents.json") {
var text = File.ReadAllText (assetItem.ItemSpec);

if (string.IsNullOrEmpty (text))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,5 +634,45 @@ public void XSAppIconAssetsAndAppIcon (ApplePlatform platform)
ExecuteTask (actool, 1);
Assert.AreEqual ("Can't specify both 'XSAppIconAssets' in the Info.plist and 'AppIcon' in the project file. Please select one or the other.", Engine.Logger.ErrorEvents [0].Message, "Error message");
}

[Test]
[TestCase (ApplePlatform.iOS)]
[TestCase (ApplePlatform.MacCatalyst)]
[TestCase (ApplePlatform.MacOSX)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't work on tvOS?

public void IconFileSupport (ApplePlatform platform)
{
// Test that .icon folders (Icon Composer format) are recognized as app icons
var projectDir = Cache.CreateTemporaryDirectory ();
var iconFolderPath = Path.Combine (projectDir, "Resources", "AppIcon.icon");
var assetsPath = Path.Combine (iconFolderPath, "Assets");
Directory.CreateDirectory (assetsPath);

// Create a dummy icon.json file (simplified structure for testing)
var iconJsonPath = Path.Combine (iconFolderPath, "icon.json");
File.WriteAllText (iconJsonPath, @"{""version"":1}");

// Create a dummy image file in the Assets folder
var imagePath = Path.Combine (assetsPath, "icon_512x512.png");
File.WriteAllText (imagePath, "dummy image");

var actool = CreateACToolTask (
platform,
projectDir,
out var _,
iconJsonPath + "|Resources/AppIcon.icon/icon.json",
imagePath + "|Resources/AppIcon.icon/Assets/icon_512x512.png"
);
actool.AppIcon = "AppIcon";

// The task should recognize AppIcon as a valid icon
// Note: This will fail at actool execution since we don't have a real .icon structure,
// but we're testing that the icon is recognized in the validation phase
ExecuteTask (actool, expectedErrorCount: 1); // Expected to fail at actool execution

// Verify that no error was logged about the icon not being found
var errorMessages = Engine.Logger.ErrorEvents.Select (e => e.Message).ToList ();
Assert.IsFalse (errorMessages.Any (m => m.Contains ("Can't find the AppIcon")),
"Should not report that AppIcon is not found among image resources");
}
}
}