From 7541fbc0eec1063ed1c98858d7f54587b234741b Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 18 Oct 2024 08:35:57 +0100 Subject: [PATCH 1/2] Rework Design Time Build to use .aar files directly. --- .../Steps/Step_CopyExtraResultFilesForCI.cs | 1 + .../Android/Xamarin.Android.Aapt2.targets | 2 +- .../Xamarin.Android.Resource.Designer.targets | 38 +++- ...osoft.Android.Sdk.AndroidLibraries.targets | 2 +- ...oft.Android.Sdk.AssemblyResolution.targets | 2 + .../Microsoft.Android.Sdk.BuildOrder.targets | 8 +- .../targets/Microsoft.Android.Sdk.targets | 2 +- .../Tasks/GenerateResourceCaseMap.cs | 37 ++++ .../Tasks/GenerateRtxt.cs | 4 +- .../Xamarin.Android.Build.Tests/BuildTest.cs | 17 +- .../IncrementalBuildTest.cs | 17 +- .../Utilities/FileResourceParser.cs | 169 +++++++++++------- .../Xamarin.Android.Common.targets | 8 +- .../Tests/PerformanceTest.cs | 21 +++ .../MSBuildDeviceIntegration.csv | 1 + 15 files changed, 238 insertions(+), 91 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_CopyExtraResultFilesForCI.cs b/build-tools/xaprepare/xaprepare/Steps/Step_CopyExtraResultFilesForCI.cs index fd88a337d04..be286992a62 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_CopyExtraResultFilesForCI.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_CopyExtraResultFilesForCI.cs @@ -90,6 +90,7 @@ void CopyExtraBuildFiles (string destinationRoot, Context context) "*log", "TestOutput-*.txt", "Timing_*", + "*.runsettings", }; void CopyExtraTestFiles (string destinationRoot, Context context) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Aapt2.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Aapt2.targets index d1bfde205de..be0c6c61539 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Aapt2.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Aapt2.targets @@ -27,7 +27,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - + <_SetLatestTargetFrameworkVersionDependsOnTargets> $(_SetLatestTargetFrameworkVersionDependsOnTargets); _CreateAapt2VersionCache; diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index 3fa46d4a2b9..e9636fc9521 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -45,6 +45,8 @@ Copyright (C) 2016 Xamarin. All rights reserved. per TargetFramework. --> <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' And '$(_OuterIntermediateOutputPath)' != '' ">$(_OuterIntermediateOutputPath) + <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' And '$(_OuterIntermediateOutputPath)' != '' And '$(AndroidUseDesignerAssembly)' == 'True' And '$(DesignTimeBuild)' == 'true' ">$(_OuterIntermediateOutputPath)designtime\ + <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' And '$(AndroidUseDesignerAssembly)' == 'True' And '$(DesignTimeBuild)' == 'true' ">$(IntermediateOutputPath)designtime\ <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' ">$(IntermediateOutputPath) <_GenerateResourceDesignerAssemblyOutput>$(_DesignerIntermediateOutputPath)$(_DesignerAssemblyName).dll <_GenerateResourceDesignerClassFile Condition=" '$(Language)' == 'F#' ">$(_DesignerIntermediateOutputPath)_$(_DesignerAssemblyName).fs @@ -56,15 +58,44 @@ Copyright (C) 2016 Xamarin. All rights reserved. + + + <_ProjectReferenceResourceDirectory Include="$(MSBuildProjectDirectory)\$(MonoAndroidResourcePrefix)" + StampFile="$(MSBuildProjectFile)" + Condition="!Exists('$(OutputPath)$(TargetName).aar')" + /> + + + + + + + + + + + + + <_DesignTimeAarFiles Include="@(AndroidAarLibrary)" Condition=" '@(LibraryResourceDirectories->Count())' == '0' " /> + + + <_BuildResourceDesignerDependsOn> _SetupDesignerProperties; + _ResolveAars; + _CalculateDesignTimeAars; _GenerateResourceCaseMap; _GenerateRtxt; _GenerateResourceDesignerIntermediateClass; diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets index 14b9e8c2dee..e678933ab8b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets @@ -18,7 +18,7 @@ projects. <_AarOutputPath>$(OutputPath)$(TargetName).aar - + <_AarSearchDirectory Include="@(_ReferencePath->'%(RootDir)%(Directory)')" /> <_AarSearchDirectory Include="@(_ReferenceDependencyPaths->'%(RootDir)%(Directory)')" /> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index 5bb9041cb5f..afda07d8c7d 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets @@ -90,6 +90,7 @@ _ResolveAssemblies MSBuild target. <_AdditionalProperties> _ComputeFilesToPublishForRuntimeIdentifiers=true ;SelfContained=true + ;DesignTimeBuild=$(DesignTimeBuild) ;AppendRuntimeIdentifierToOutputPath=true ;ResolveAssemblyReferencesFindRelatedSatellites=false ;SkipCompilerExecution=true @@ -105,6 +106,7 @@ _ResolveAssemblies MSBuild target. <_ProjectToBuild Include="$(MSBuildProjectFile)" AdditionalProperties="RuntimeIdentifier=%(_RIDs.Identity);$(_AdditionalProperties)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets index ee627e65d03..e9f450b2398 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets @@ -112,14 +112,9 @@ properties that determine build ordering. $(CoreResolveReferencesDependsOn); UpdateAndroidResources; - _BuildResourceDesigner; UpdateAndroidInterfaceProxies; _CheckForInvalidDesignerConfig; - - $(DesignTimeResolveAssemblyReferencesDependsOn); - _BuildResourceDesigner; - <_UpdateAndroidResourcesDependsOn> $(CoreResolveReferencesDependsOn); _CreatePropertiesCache; @@ -127,7 +122,6 @@ properties that determine build ordering. _ComputeAndroidResourcePaths; _UpdateAndroidResgen; _CreateAar; - _BuildResourceDesigner; _SetupMSBuildAllProjects; @@ -142,9 +136,9 @@ properties that determine build ordering. _CollectGeneratedManagedBindingFiles; _ClearGeneratedManagedBindings; AddBindingsToCompile; + $(CompileDependsOn); _BuildResourceDesigner; _AddResourceDesignerFiles; - $(CompileDependsOn); _CheckAndroidHttpClientHandlerType; diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets index 31755d131e8..3b6efd9aab2 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets @@ -26,7 +26,7 @@ + Condition="Exists('$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props') And '$(DesignTimeBuild)' != 'true'"/> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs index bf6aa0563aa..fff2ed70673 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs @@ -6,6 +6,8 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Microsoft.Android.Build.Tasks; +using Xamarin.Android.Tools; +using Xamarin.Tools.Zip; namespace Xamarin.Android.Tasks { @@ -22,6 +24,8 @@ public class GenerateResourceCaseMap : AndroidTask public ITaskItem[] AdditionalResourceDirectories { get; set; } + public string[] AarLibraries { get; set; } + [Required] public ITaskItem OutputFile { get; set; } @@ -64,6 +68,39 @@ public override bool RunTask () AddRename (tok [1].Replace ('/', Path.DirectorySeparatorChar), tok [0].Replace ('/', Path.DirectorySeparatorChar)); } } + var resmap = ".net/__res_name_case_map.txt"; + foreach (var aar in AarLibraries ?? Array.Empty()) { + Log.LogDebugMessage ($"Processing Aar file {aar}"); + if (!File.Exists (aar)) { + Log.LogDebugMessage ($"Skipping non-existent aar: {aar}"); + continue; + } + using (var file = File.OpenRead (aar)) { + using var zip = ZipArchive.Open (file); + if (!zip.ContainsEntry (resmap)) { + Log.LogDebugMessage ($"Skipping non-existent file: {resmap}"); + continue; + } + ZipEntry entry = zip.ReadEntry (resmap); + Log.LogDebugMessage ($"Found: {entry.FullName}"); + var ms = MemoryStreamPool.Shared.Rent (); + try { + entry.Extract (ms); + ms.Position = 0; + using var reader = new StreamReader (ms); + string line; + // Read each line until the end of the file + while ((line = reader.ReadLine()) != null) { + if (string.IsNullOrEmpty (line)) + continue; + string [] tok = line.Split (';'); + AddRename (tok [1].Replace ('/', Path.DirectorySeparatorChar), tok [0].Replace ('/', Path.DirectorySeparatorChar)); + } + } finally { + MemoryStreamPool.Shared.Return (ms); + } + } + } if (MonoAndroidHelper.SaveMapFile (BuildEngine4, Path.GetFullPath (OutputFile.ItemSpec), resource_fixup)) { Log.LogDebugMessage ($"Writing to: {OutputFile.ItemSpec}"); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs index 563318d357c..5de36f9cd7c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs @@ -17,6 +17,8 @@ public class GenerateRtxt : AndroidTask public string ResourceDirectory { get; set; } public string[] AdditionalResourceDirectories { get; set; } + public string[] AarLibraries { get; set; } + public string JavaPlatformJarPath { get; set; } public string ResourceFlagFile { get; set; } @@ -31,7 +33,7 @@ public override bool RunTask () var javaPlatformDirectory = string.IsNullOrEmpty (JavaPlatformJarPath) ? "" : Path.GetDirectoryName (JavaPlatformJarPath); var parser = new FileResourceParser () { Log = Log, JavaPlatformDirectory = javaPlatformDirectory, ResourceFlagFile = ResourceFlagFile}; - var resources = parser.Parse (ResourceDirectory, AdditionalResourceDirectories, resource_fixup); + var resources = parser.Parse (ResourceDirectory, AdditionalResourceDirectories, AarLibraries, resource_fixup); // only update if it changed. writer.Write (RTxtFile, resources); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 47f6c3dbff5..48c1ed3685b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -752,6 +752,7 @@ public void BuildAfterUpgradingNuget () } [Test] + [Category ("SmokeTests")] public void BuildInDesignTimeMode ([Values(false, true)] bool useManagedParser) { var proj = new XamarinAndroidApplicationProject () { @@ -762,20 +763,20 @@ public void BuildInDesignTimeMode ([Values(false, true)] bool useManagedParser) builder.Target = "UpdateAndroidResources"; builder.Build (proj, parameters: new string[] { "DesignTimeBuild=true" }); Assert.IsFalse (builder.Output.IsTargetSkipped ("_CreatePropertiesCache"), "target \"_CreatePropertiesCache\" should have been run."); - Assert.IsFalse (builder.Output.IsTargetSkipped ("_ResolveLibraryProjectImports"), "target \"_ResolveLibraryProjectImports\' should have been run."); + Assert.IsFalse (builder.Output.IsTargetSkipped ("_GenerateRtxt"), "target \"_GenerateRtxt\' should have been run."); var intermediate = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath); - var librarycache = Path.Combine (intermediate, "designtime", "libraryprojectimports.cache"); - Assert.IsTrue (File.Exists (librarycache), $"'{librarycache}' should exist."); - librarycache = Path.Combine (intermediate, "libraryprojectimports.cache"); - Assert.IsFalse (File.Exists (librarycache), $"'{librarycache}' should not exist."); + var rTxtFile = Path.Combine (intermediate, "designtime", "R.txt"); + Assert.IsTrue (File.Exists (rTxtFile), $"'{rTxtFile}' should exist."); + rTxtFile = Path.Combine (intermediate, "R.txt"); + Assert.IsFalse (File.Exists (rTxtFile), $"'{rTxtFile}' should not exist."); builder.Build (proj, parameters: new string[] { "DesignTimeBuild=true" }); Assert.IsFalse (builder.Output.IsTargetSkipped ("_CreatePropertiesCache"), "target \"_CreatePropertiesCache\" should have been run."); - Assert.IsTrue (builder.Output.IsTargetSkipped ("_ResolveLibraryProjectImports"), "target \"_ResolveLibraryProjectImports\' should have been skipped."); + Assert.IsTrue (builder.Output.IsTargetSkipped ("_GenerateRtxt"), "target \"_GenerateRtxt\' should have been skipped."); Assert.IsTrue (builder.Clean (proj), "Clean Should have succeeded"); builder.Target = "_CleanDesignTimeIntermediateDir"; Assert.IsTrue (builder.Build (proj), "_CleanDesignTimeIntermediateDir should have succeeded"); - librarycache = Path.Combine (intermediate, "designtime", "libraryprojectimports.cache"); - Assert.IsFalse (File.Exists (librarycache), $"'{librarycache}' should not exist."); + rTxtFile = Path.Combine (intermediate, "designtime", "R.txt"); + Assert.IsFalse (File.Exists (rTxtFile), $"'{rTxtFile}' should not exist."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs index 75f45a1d833..32b79d45e83 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs @@ -1199,17 +1199,26 @@ public void DesignTimeBuild () { var proj = new XamarinAndroidApplicationProject (); using (var b = CreateApkBuilder (Path.Combine ("temp", $"{nameof (IncrementalBuildTest)}{TestName}"))) { + b.BuildLogFile = "dtb1.log"; Assert.IsTrue (b.DesignTimeBuild (proj), "first dtb should have succeeded."); - var target = "_ResolveLibraryProjectImports"; + var target = "_GenerateResourceDesignerAssembly"; Assert.IsFalse (b.Output.IsTargetSkipped (target), $"`{target}` should not have been skipped."); + var importsTarget = "_ResolveLibraryProjectImports"; + Assert.IsTrue (b.Output.IsTargetSkipped (importsTarget, defaultIfNotUsed: true), $"`{importsTarget}` should have been skipped."); // DesignTimeBuild=true lowercased var parameters = new [] { "DesignTimeBuild=true" }; + b.BuildLogFile = "compile.log"; Assert.IsTrue (b.RunTarget (proj, "Compile", doNotCleanupOnUpdate: true, parameters: parameters), "second dtb should have succeeded."); - Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should have been skipped."); + Assert.IsTrue (b.Output.IsTargetSkipped (target, defaultIfNotUsed: true), $"`{target}` should have been skipped."); + Assert.IsTrue (b.Output.IsTargetSkipped (importsTarget, defaultIfNotUsed: true), $"`{importsTarget}` should have been skipped."); + b.BuildLogFile = "updategeneratedfiles.log"; Assert.IsTrue (b.RunTarget (proj, "UpdateGeneratedFiles", doNotCleanupOnUpdate: true, parameters: parameters), "UpdateGeneratedFiles should have succeeded."); - Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should have been skipped."); + Assert.IsTrue (b.Output.IsTargetSkipped (target, defaultIfNotUsed: true), $"`{target}` should have been skipped."); + Assert.IsTrue (b.Output.IsTargetSkipped (importsTarget, defaultIfNotUsed: true), $"`{importsTarget}` should have been skipped."); + b.BuildLogFile = "build.log"; Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "full build should have succeeded."); Assert.IsFalse (b.Output.IsTargetSkipped (target), $"`{target}` should not have been skipped."); + Assert.IsFalse (b.Output.IsTargetSkipped (importsTarget), $"`{importsTarget}` should not have been skipped."); } } @@ -1234,7 +1243,7 @@ public void DesignTimeBuildSignAndroidPackage () Assert.IsTrue (builder.RunTarget (proj, "SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed"); builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 2); builder.Output.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 1); - builder.Output.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 1); + builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceDesignerIntermediateClass"); builder.Output.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly", occurrence: 2); builder.BuildLogFile = "build2.log"; Assert.IsTrue (builder.RunTarget (proj, "SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed 2"); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs index cfac54ddb42..709ae2a7dd8 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs @@ -1,5 +1,6 @@ using System; using System.CodeDom; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -11,6 +12,7 @@ using System.Text.RegularExpressions; using Microsoft.Build.Utilities; using Microsoft.Android.Build.Tasks; +using Xamarin.Tools.Zip; namespace Xamarin.Android.Tasks { @@ -43,7 +45,7 @@ protected XDocument LoadPublicXml () { return null; } - public IList Parse (string resourceDirectory, IEnumerable additionalResourceDirectories, Dictionary resourceMap) + public IList Parse (string resourceDirectory, IEnumerable additionalResourceDirectories, IEnumerable aarLibraries, Dictionary resourceMap) { Log.LogDebugMessage ($"Parsing Directory {resourceDirectory}"); publicXml = LoadPublicXml (); @@ -71,6 +73,38 @@ public IList Parse (string resourceDirectory, IEnumerable additionalR Log.LogDebugMessage ($"Skipping non-existent directory: {dir}"); } } + foreach (var aar in aarLibraries ?? Array.Empty()) { + Log.LogDebugMessage ($"Processing Aar file {aar}"); + if (!File.Exists (aar)) { + Log.LogDebugMessage ($"Skipping non-existent aar: {aar}"); + continue; + } + using (var file = File.Open (aar, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) { + using var zip = ZipArchive.Open (file); + foreach (var entry in zip) { + if (entry.IsDirectory) + continue; + if (!entry.FullName.StartsWith ("res")) + continue; + var ext = Path.GetExtension (entry.FullName); + var path = Directory.GetParent (entry.FullName).Name; + if (ext == ".xml" || ext == ".axml") { + if (string.Compare (path, "raw", StringComparison.OrdinalIgnoreCase) != 0) { + var ms = MemoryStreamPool.Shared.Rent (); + try { + entry.Extract (ms); + ms.Position = 0; + using XmlReader reader = XmlReader.Create (ms); + ProcessXmlFile (reader, resources); + } finally { + MemoryStreamPool.Shared.Return (ms); + } + } + } + ProcessResourceFile (entry.FullName, resources, processXml: false); + } + } + } // now generate the Id's we need in a specific order List declarationIds = new List (); @@ -172,7 +206,7 @@ int GetId (ICollection resources, string identifier) return -1; } - void ProcessResourceFile (string file, Dictionary> resources) + void ProcessResourceFile (string file, Dictionary> resources, bool processXml = true) { Log.LogDebugMessage ($"{nameof(ProcessResourceFile)} {file}"); var fileName = Path.GetFileNameWithoutExtension (file); @@ -181,6 +215,10 @@ void ProcessResourceFile (string file, Dictionary> resour if (fileName.EndsWith (".9", StringComparison.OrdinalIgnoreCase)) fileName = Path.GetFileNameWithoutExtension (fileName); var path = Directory.GetParent (file).Name; + if (!processXml) { + CreateResourceField (path, fileName, resources); + return; + } var ext = Path.GetExtension (file); switch (ext) { case ".xml": @@ -299,8 +337,6 @@ void ProcessStyleable (XmlReader reader, Dictionary> reso fields.Add (r); } } - if (field.Type != RType.Array) - return; arrayMapping.Add (field, fields.ToArray ()); field.Ids = new int [attribs.Count]; @@ -321,72 +357,81 @@ resources [field.ResourceTypeName].Add (new R () { void ProcessXmlFile (string file, Dictionary> resources) { - Log.LogDebugMessage ($"{nameof(ProcessXmlFile)}"); using (var reader = XmlReader.Create (file)) { - while (reader.Read ()) { - if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) - continue; - if (reader.IsStartElement ()) { - var elementName = reader.Name; - var elementNS = reader.NamespaceURI; - if (!string.IsNullOrEmpty (elementNS)) { - if (elementNS != "http://schemas.android.com/apk/res/android") - continue; - } - if (elementName == "declare-styleable" || elementName == "configVarying" || elementName == "add-resource") { - ProcessStyleable (reader.ReadSubtree (), resources); + ProcessXmlFile (reader, resources); + } + } + + void ProcessXmlFile (XmlReader reader, Dictionary> resources) + { + Log.LogDebugMessage ($"{nameof(ProcessXmlFile)}"); + while (reader.Read ()) { + if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) + continue; + if (reader.IsStartElement ()) { + var elementName = reader.Name; + var elementNS = reader.NamespaceURI; + if (!string.IsNullOrEmpty (elementNS)) { + if (elementNS != "http://schemas.android.com/apk/res/android") continue; + } + if (elementName == "declare-styleable" || elementName == "configVarying" || elementName == "add-resource") { + try { + ProcessStyleable (reader.ReadSubtree (), resources); + } catch (Exception ex) { + Log.LogErrorFromException (ex); } - if (reader.HasAttributes) { - string name = null; - string type = null; - string id = null; - string custom_id = null; - while (reader.MoveToNextAttribute ()) { - if (reader.LocalName == "name") - name = reader.Value; - if (reader.LocalName == "type") - type = reader.Value; - if (reader.LocalName == "id") { - string[] values = reader.Value.Split ('/'); - if (values.Length != 2) { - id = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); - } else { - if (values [0] != "@+id" && values [0] != "@id" && !values [0].Contains ("android:")) { - custom_id = values [0].Replace ("@", "").Replace ("+", ""); - } - id = values [1]; + continue; + } + if (reader.HasAttributes) { + string name = null; + string type = null; + string id = null; + string custom_id = null; + while (reader.MoveToNextAttribute ()) { + if (reader.LocalName == "name") + name = reader.Value; + if (reader.LocalName == "type") + type = reader.Value; + if (reader.LocalName == "id") { + string[] values = reader.Value.Split ('/'); + if (values.Length != 2) { + id = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); + } else { + if (values [0] != "@+id" && values [0] != "@id" && !values [0].Contains ("android:")) { + custom_id = values [0].Replace ("@", "").Replace ("+", ""); } - - } - if (reader.LocalName == "inflatedId") { - string inflateId = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); - var r = new R () { - ResourceTypeName = "id", - Identifier = inflateId, - Id = -1, - }; - Log.LogDebugMessage ($"Adding 1 {r}"); - resources[r.ResourceTypeName].Add (r); + id = values [1]; } + } - if (name?.Contains ("android:") ?? false) - continue; - if (id?.Contains ("android:") ?? false) - continue; - // Move the reader back to the element node. - reader.MoveToElement (); - if (!string.IsNullOrEmpty (name)) { - CreateResourceField (type ?? elementName, name, resources); - } - if (!string.IsNullOrEmpty (custom_id) && !resources.ContainsKey (custom_id)) { - resources.Add (custom_id, new SortedSet (new RComparer ())); - custom_types.Add (custom_id); - } - if (!string.IsNullOrEmpty (id)) { - CreateResourceField (custom_id ?? "id", id.Replace ("-", "_").Replace (".", "_"), resources); + if (reader.LocalName == "inflatedId") { + string inflateId = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); + var r = new R () { + ResourceTypeName = "id", + Identifier = inflateId, + Id = -1, + }; + Log.LogDebugMessage ($"Adding 1 {r}"); + resources[r.ResourceTypeName].Add (r); } } + if (name?.Contains ("android:") ?? false) + continue; + if (id?.Contains ("android:") ?? false) + continue; + // Move the reader back to the element node. + reader.MoveToElement (); + if (!string.IsNullOrEmpty (name)) { + CreateResourceField (type ?? elementName, name, resources); + } + if (!string.IsNullOrEmpty (custom_id) && !resources.ContainsKey (custom_id)) { + resources.Add (custom_id, new SortedSet (new RComparer ())); + custom_types.Add (custom_id); + } + if (!string.IsNullOrEmpty (id)) { + CreateResourceField (custom_id ?? "id", id.Replace ("-", "_").Replace (".", "_"), resources); + } } } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index ba56eff5b92..65f767b5325 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -118,7 +118,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. --> + Condition="Exists('$(MSBuildThisFileDirectory)Xamarin.Installer.Common.props') And '$(DesignTimeBuild)' != 'true'"/> @@ -361,7 +361,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - + @@ -2865,14 +2865,14 @@ because xbuild doesn't support framework reference assemblies. + Condition="Exists('$(MSBuildThisFileDirectory)Xamarin.Android.Common.Debugging.targets') And '$(DesignTimeBuild)' != 'true' "/> + Condition="Exists('$(MSBuildThisFileDirectory)Xamarin.Installer.Common.targets') And '$(DesignTimeBuild)' != 'true' "/>