diff --git a/docs/build-apps/build-items.md b/docs/build-apps/build-items.md index 608836c94d40..e8f6b01fb402 100644 --- a/docs/build-apps/build-items.md +++ b/docs/build-apps/build-items.md @@ -9,6 +9,42 @@ ms.date: 09/19/2024 Build items control how .NET for iOS, Mac Catalyst, macOS, and tvOS application or library projects are built. +## PartialAppManifest + +`PartialAppManifest` can be used to add additional partial app manifests that +will be merged with the main app manifest (Info.plist). + +Any values in the partial app manifests will override values in the main app +manifest unless the `Overwrite` metadata is set to `false`. + +If the same value is specified in multiple partial app manifests, it's +undetermined which one will be the one used. + +```xml + + + +``` + +If the developer needs to execute a target to compute what to add to the +`PartialAppManifest` item group, it's possible to make sure this target is +executed before the `PartialAppManifest` items are procesed by adding it to +the `CollectAppManifestsDependsOn` property: + +```xml + + + AddPartialAppManifests; + $(CollectAppManifestsDependsOn); + + + + + + + +``` + ## XcodeProject `` can be used to build and consume the outputs diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs index 7901c1f9f72d..8f54d817cbd0 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs @@ -393,15 +393,17 @@ protected void SetValue (PDictionary dict, string key, string value) dict [key] = value; } - public static void MergePartialPlistDictionary (PDictionary plist, PDictionary partial) + public static void MergePartialPlistDictionary (PDictionary plist, PDictionary partial, bool overwrite) { foreach (var property in partial) { var key = property.Key!; if (plist.ContainsKey (key)) { + if (!overwrite) + continue; var value = plist [key]; if (value is PDictionary && property.Value is PDictionary) { - MergePartialPlistDictionary ((PDictionary) value, (PDictionary) property.Value); + MergePartialPlistDictionary ((PDictionary) value, (PDictionary) property.Value, overwrite); } else { plist [key] = property.Value.Clone (); } @@ -418,6 +420,7 @@ public static void MergePartialPLists (Task task, PDictionary plist, IEnumerable foreach (var template in partialLists) { PDictionary partial; + var overwrite = !string.Equals (template.GetMetadata ("Overwrite"), "false", StringComparison.OrdinalIgnoreCase); try { partial = PDictionary.FromFile (template.ItemSpec)!; @@ -426,7 +429,7 @@ public static void MergePartialPLists (Task task, PDictionary plist, IEnumerable continue; } - MergePartialPlistDictionary (plist, partial); + MergePartialPlistDictionary (plist, partial, overwrite); } } diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 534665a2d6b8..caf764e77050 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -509,7 +509,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. property to run targets that add to the `PartialAppManifest` item group before we process them. * Some MSBuild properties can also add values. - The precedence is: MSBuild properties can be overridden by the Info.plist, which can be overridden by a partial plist. + The precedence is: MSBuild properties can be overridden by the Info.plist, which can be overridden by a partial plist (a partial plist can also specify the "Overwrite=false" metadata to not overwrite any existing entries). 2. In the `CompileAppManifest` target we get all the inputs from above, and compute a temporary app manifest, which is written to a temporary output file. diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs index 93cc0b5e6d41..54b1e55a42d7 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs @@ -77,6 +77,36 @@ public void MultipleMinimumOSVersions () Assert.AreEqual ("13.0", plist.GetMinimumOSVersion (), "MinimumOSVersion"); } + [Test] + [TestCase (false, "14.0")] + [TestCase (true, "13.0")] + public void MultipleMinimumOSVersions_Overwrite (bool overwrite, string expectedMinimumOSVersion) + { + var dir = Cache.CreateTemporaryDirectory (); + var task = CreateTask (dir); + + var mainPath = Path.Combine (dir, "Info.plist"); + var main = new PDictionary (); + main.SetMinimumOSVersion ("14.0"); + main.Save (mainPath); + + var partialPath = Path.Combine (dir, "PartialAppManifest.plist"); + var partial = new PDictionary (); + partial.SetMinimumOSVersion ("13.0"); + partial.Save (partialPath); + + task.AppManifest = new TaskItem (mainPath); + var partialAppManifest = new TaskItem (partialPath); + partialAppManifest.SetMetadata ("Overwrite", overwrite ? "true" : "false"); + task.PartialAppManifests = new [] { partialAppManifest }; + task.SupportedOSPlatformVersion = "14.0"; + + ExecuteTask (task); + + var plist = PDictionary.FromFile (task.CompiledAppManifest!.ItemSpec)!; + Assert.AreEqual (expectedMinimumOSVersion, plist.GetMinimumOSVersion (), "MinimumOSVersion"); + } + [Test] public void ErrorWithMismatchedInfoPlistMinimumOSVersion () {