From ca4ae3873a6b541a06168ad8c0a4c1ca18c732a9 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 28 Sep 2021 10:20:44 +0100 Subject: [PATCH 01/18] First Pass at using Resource Designer assembly [WIP] Context #6310 Ignore Java.Interop-Tests IntermediateDir Try StrongNaming. Based on code in https://github.com/brutaldev/StrongNameSigner/blob/master/src/Brutal.Dev.StrongNameSigner/SigningHelper.cs Use ICSharpCode.Decompiler to read Resource Designer Assembly Fix breakage Fix error with Aapt2 R.txt Use latest Xamarin.Forms for dotnet tests Disable StrongNaming for now Removed unused code and logging Remove StrongNaming support Revert "Remove StrongNaming support" This reverts commit 7f90638f1788adfa37c4ec4ab3fed9fc48569cb5. Use a cstom snk for the designer strong name Update apkdesc Change to Microsoft.Android.Resource.Designer new test Move CryptoConvert to src-ThirdParty Add StrongNameSigner code and TPN Fix missing file Fix another build error Fix a test Update and Fix the UnitTest update docs Switch to _Microsoft.Android.Resource.Designer.dll update apkdesc update apkdesc --- .../guides/building-apps/build-properties.md | 28 ++ .../installers/create-installers.targets | 1 + .../ThirdPartyNotices/StrongNameSigner.cs | 33 ++ .../CryptoConvert.cs | 338 +++++++++++++++ .../StrongNameSigner/SigningHelper.cs | 35 ++ .../FixLegacyResourceDesignerStep.cs | 163 ++++++++ .../MonoDroid.Tuner/LinkDesignerBase.cs | 20 +- .../Linker/MonoDroid.Tuner/Linker.cs | 2 + .../Linker/MonoDroid.Tuner/LinkerOptions.cs | 1 + .../Android/Xamarin.Android.Aapt2.targets | 2 +- .../Android/Xamarin.Android.Designer.targets | 2 +- .../Xamarin.Android.Resource.Designer.targets | 217 ++++++++++ ...oft.Android.Sdk.AssemblyResolution.targets | 8 + .../Microsoft.Android.Sdk.BuildOrder.targets | 14 +- ...soft.Android.Sdk.DefaultProperties.targets | 2 + .../Microsoft.Android.Sdk.ILLink.targets | 7 +- .../Microsoft.Android.Sdk.Publish.targets | 1 + .../Properties/Resources.Designer.cs | 9 + .../Properties/Resources.resx | 4 + .../Resources/Resource.Designer.snk | Bin 0 -> 596 bytes .../Tasks/Aapt2Link.cs | 7 +- .../Tasks/AppendCustomMetadataToItemGroup.cs | 5 + .../Tasks/ConvertCustomView.cs | 6 +- .../Tasks/FilterAssemblies.cs | 2 + .../Tasks/GenerateLibraryResources.cs | 3 +- .../Tasks/GeneratePackageManagerJava.cs | 2 +- .../Tasks/GenerateResourceCaseMap.cs | 121 ++++++ .../Tasks/GenerateResourceDesigner.cs | 32 +- .../Tasks/GenerateResourceDesignerAssembly.cs | 350 ++++++++++++++++ ...nerateResourceDesignerIntermediateClass.cs | 53 +++ .../Tasks/GenerateRtxt.cs | 48 +++ .../Tasks/LinkAssemblies.cs | 3 + .../Tasks/LinkAssembliesNoShrink.cs | 40 +- .../Tasks/ResolveLibraryProjectImports.cs | 8 +- .../AndroidUpdateResourcesTest.cs | 112 +++-- .../Xamarin.Android.Build.Tests/AotTests.cs | 7 + .../Xamarin.Android.Build.Tests/BuildTest.cs | 30 +- .../DesignerTests.cs | 6 + .../IncrementalBuildTest.cs | 5 + .../PackagingTest.cs | 1 + .../Tasks/GenerateResourceCaseMapTests.cs | 51 +++ .../Tasks/ManagedResourceParserTests.cs | 62 ++- .../Utilities/BaseTest.cs | 27 ++ .../Xamarin.Android.Build.Tests/XASdkTests.cs | 82 +++- .../Xamarin.Android.Build.Tests.csproj | 1 + .../Android/KnownPackages.cs | 15 + .../Android/XamarinAndroidCommonProject.cs | 6 +- .../Android/XamarinAndroidProjectLanguage.cs | 2 +- .../Xamarin.ProjectTools/Common/DotNetCLI.cs | 4 +- .../BuildReleaseArm64SimpleDotNet.apkdesc | 5 +- .../BuildReleaseArm64SimpleLegacy.apkdesc | 16 +- .../BuildReleaseArm64XFormsDotNet.apkdesc | 9 +- .../BuildReleaseArm64XFormsLegacy.apkdesc | 85 ++-- .../Utilities/FileResourceParser.cs | 389 ++++++++++++++++++ .../Utilities/ManagedResourceParser.cs | 126 +----- .../Utilities/MonoAndroidHelper.cs | 44 +- .../ResourceDesignerImportGenerator.cs | 1 + .../Utilities/ResourceIdentifier.cs | 18 +- .../Utilities/ResourceParser.cs | 12 +- .../Utilities/RtxtParser.cs | 156 +++++++ .../Utilities/RtxtWriter.cs | 23 ++ .../Xamarin.Android.Build.Tasks.csproj | 9 + .../Xamarin.Android.Build.Tasks.targets | 4 + .../Xamarin.Android.Common.targets | 64 ++- .../Xamarin.Android.DesignTime.targets | 1 + .../Xamarin.Android.Legacy.targets | 7 +- .../MSBuildDeviceIntegration.csproj | 1 + .../Tests/InstallAndRunTests.cs | 86 ++++ .../Tests/InstantRunTest.cs | 1 + .../Java.Interop-Tests.csproj | 1 + .../Mono.Android-Test.Shared.projitems | 1 - .../Mono.Android-Tests.csproj | 1 + .../Mono.Android-TestsMultiDex.csproj | 2 +- 73 files changed, 2739 insertions(+), 301 deletions(-) create mode 100644 build-tools/xaprepare/xaprepare/ThirdPartyNotices/StrongNameSigner.cs create mode 100644 src-ThirdParty/Mono.Security.Cryptography/CryptoConvert.cs create mode 100644 src-ThirdParty/StrongNameSigner/SigningHelper.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs create mode 100644 src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets create mode 100644 src/Xamarin.Android.Build.Tasks/Resources/Resource.Designer.snk create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerAssembly.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerIntermediateClass.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GenerateResourceCaseMapTests.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs diff --git a/Documentation/guides/building-apps/build-properties.md b/Documentation/guides/building-apps/build-properties.md index ee48b5653fe..72b17d2806d 100644 --- a/Documentation/guides/building-apps/build-properties.md +++ b/Documentation/guides/building-apps/build-properties.md @@ -1364,6 +1364,34 @@ To suppress the default AOT profiles, set the property to `false`. Added in Xamarin.Android 10.1. +## AndroidUseDesignerAssembly + +A bool property which controls if the build system will generate an +`_Microsoft.Android.Resource.Designer.dll` as apposed to a `Resource.Designer.cs` file. The benefits of this are smaller applications and +faster startup time. + +The default value is `true` in .NET 8. + +This setting is not backward compatible with Classic Xamarin.Android. +As a Nuget Author it is recommended that you ship three versions of +the assembly if you want to maintain backward compatibility. +One for MonoAndroid, one for net6.0-android and +one for net8.0-android. You can do this by using [Xamarin.Legacy.Sdk](https://www.nuget.org/packages/Xamarin.Legacy.Sdk). + +``` +monoandroid90;net6.0-android;net8.0-android +``` + +Alternatively turn this setting off until such time as both Classic and +net7.0-android have been deprecated. + +.NET 8 Projects which choose to turn this setting off will not be able to +consume references which do use it. If you try to use an assembly +which does have this feature enabled in a project that does not, you will +get a `XA1031` build error. + +Added in .NET 8. Unsupported in Classic Xamarin.Android. + ## AndroidUseInterpreter A boolean property that causes the `.apk` to contain the mono diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index 51ff5bb9a1d..3e589147ceb 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -303,6 +303,7 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.CSharp.targets" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.D8.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Designer.targets" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Resource.Designer.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.DesignTime.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.EmbeddedResource.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.FSharp.targets" ExcludeFromAndroidNETSdk="true" /> diff --git a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/StrongNameSigner.cs b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/StrongNameSigner.cs new file mode 100644 index 00000000000..45ab44b28b4 --- /dev/null +++ b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/StrongNameSigner.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Xamarin.Android.Prepare +{ + [TPN] + class StrongNameSigner_TPN : ThirdPartyNotice + { + static readonly Uri url = new Uri ("https://github.com/brutaldev/StrongNameSigner/"); + + public override string LicenseFile => string.Empty; + public override string Name => "brutaldev/StrongNameSigner"; + public override Uri SourceUrl => url; + public override string LicenseText => @" +Copyright (c) Werner van Deventer (werner@brutaldev.com). All rights reserved. + +Licensed under the Apache License, Version 2.0 (the 'License'); you +may not use this file except in compliance with the License. You may +obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an 'AS IS' BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing permissions +and limitations under the License. +"; + + public override bool Include (bool includeExternalDeps, bool includeBuildDeps) => includeExternalDeps; + } +} diff --git a/src-ThirdParty/Mono.Security.Cryptography/CryptoConvert.cs b/src-ThirdParty/Mono.Security.Cryptography/CryptoConvert.cs new file mode 100644 index 00000000000..5a5eecc1468 --- /dev/null +++ b/src-ThirdParty/Mono.Security.Cryptography/CryptoConvert.cs @@ -0,0 +1,338 @@ +// +// CryptoConvert.cs - Crypto Conversion Routines +// +// Author: +// Sebastien Pouliot +// +// (C) 2003 Motus Technologies Inc. (http://www.motus.com) +// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Original source can be found at +// https://github.com/mono/mono/blob/e2c5f4b0ad1a6b21ca0735f0b35b8611d4ad87b3/mcs/class/Mono.Security/Mono.Security.Cryptography/CryptoConvert.cs#L4 + +using System; +using System.Security.Cryptography; + +namespace Mono.Security.Cryptography +{ + internal static class CryptoConvert + { + static private int ToInt32LE(byte[] bytes, int offset) + { + return (bytes[offset + 3] << 24) | (bytes[offset + 2] << 16) | (bytes[offset + 1] << 8) | bytes[offset]; + } + + static private uint ToUInt32LE(byte[] bytes, int offset) + { + return (uint)((bytes[offset + 3] << 24) | (bytes[offset + 2] << 16) | (bytes[offset + 1] << 8) | bytes[offset]); + } + + static private byte[] GetBytesLE(int val) + { + return new byte[] { + (byte) (val & 0xff), + (byte) ((val >> 8) & 0xff), + (byte) ((val >> 16) & 0xff), + (byte) ((val >> 24) & 0xff) + }; + } + + static private byte[] Trim(byte[] array) + { + for (int i = 0; i < array.Length; i++) + { + if (array[i] != 0x00) + { + byte[] result = new byte[array.Length - i]; + Buffer.BlockCopy(array, i, result, 0, result.Length); + return result; + } + } + +#pragma warning disable S1168 // Empty arrays and collections should be returned instead of null + return null; +#pragma warning restore S1168 // Empty arrays and collections should be returned instead of null + } + + private static RSA FromCapiPrivateKeyBlob(byte[] blob, int offset) + { + var rsap = new RSAParameters(); + + try + { + if ((blob[offset] != 0x07) || // PRIVATEKEYBLOB (0x07) + (blob[offset + 1] != 0x02) || // Version (0x02) + (blob[offset + 2] != 0x00) || // Reserved (word) + (blob[offset + 3] != 0x00) || + (ToUInt32LE(blob, offset + 8) != 0x32415352)) // DWORD magic = RSA2 + { + throw new CryptographicException("Invalid blob header"); + } + + //// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) + //// int algId = ToInt32LE (blob, offset+4); + + //// DWORD bitlen + int bitLen = ToInt32LE(blob, offset + 12); + + //// DWORD public exponent + byte[] exp = new byte[4]; + Buffer.BlockCopy(blob, offset + 16, exp, 0, 4); + Array.Reverse(exp); + rsap.Exponent = Trim(exp); + + int pos = offset + 20; + //// BYTE modulus[rsapubkey.bitlen/8]; + int byteLen = (bitLen >> 3); + rsap.Modulus = new byte[byteLen]; + Buffer.BlockCopy(blob, pos, rsap.Modulus, 0, byteLen); + Array.Reverse(rsap.Modulus); + pos += byteLen; + + //// BYTE prime1[rsapubkey.bitlen/16]; + int byteHalfLen = (byteLen >> 1); + rsap.P = new byte[byteHalfLen]; + Buffer.BlockCopy(blob, pos, rsap.P, 0, byteHalfLen); + Array.Reverse(rsap.P); + pos += byteHalfLen; + + //// BYTE prime2[rsapubkey.bitlen/16]; + rsap.Q = new byte[byteHalfLen]; + Buffer.BlockCopy(blob, pos, rsap.Q, 0, byteHalfLen); + Array.Reverse(rsap.Q); + pos += byteHalfLen; + + //// BYTE exponent1[rsapubkey.bitlen/16]; + rsap.DP = new byte[byteHalfLen]; + Buffer.BlockCopy(blob, pos, rsap.DP, 0, byteHalfLen); + Array.Reverse(rsap.DP); + pos += byteHalfLen; + + //// BYTE exponent2[rsapubkey.bitlen/16]; + rsap.DQ = new byte[byteHalfLen]; + Buffer.BlockCopy(blob, pos, rsap.DQ, 0, byteHalfLen); + Array.Reverse(rsap.DQ); + pos += byteHalfLen; + + //// BYTE coefficient[rsapubkey.bitlen/16]; + rsap.InverseQ = new byte[byteHalfLen]; + Buffer.BlockCopy(blob, pos, rsap.InverseQ, 0, byteHalfLen); + Array.Reverse(rsap.InverseQ); + pos += byteHalfLen; + + // ok, this is hackish but CryptoAPI support it so... + // note: only works because CRT is used by default + // http://bugzilla.ximian.com/show_bug.cgi?id=57941 + rsap.D = new byte[byteLen]; // must be allocated + if (pos + byteLen + offset <= blob.Length) + { + //// BYTE privateExponent[rsapubkey.bitlen/8]; + Buffer.BlockCopy(blob, pos, rsap.D, 0, byteLen); + Array.Reverse(rsap.D); + } + } + catch (Exception e) + { + throw new CryptographicException("Invalid blob.", e); + } + + RSA rsa = null; + try + { + rsa = RSA.Create(); + rsa.ImportParameters(rsap); + } + catch (CryptographicException) + { + // this may cause problem when this code is run under + // the SYSTEM identity on Windows (e.g. ASP.NET). See + // http://bugzilla.ximian.com/show_bug.cgi?id=77559 + bool throws = false; + try + { + var csp = new CspParameters + { + Flags = CspProviderFlags.UseMachineKeyStore + }; + +#pragma warning disable S4426 // Cryptographic keys should be robust + rsa = new RSACryptoServiceProvider(csp); +#pragma warning restore S4426 // Cryptographic keys should be robust + rsa.ImportParameters(rsap); + } + catch + { + throws = true; + } + + if (throws) + { + // rethrow original, not the latter, exception if this fails + throw; + } + } + return rsa; + } + + private static RSA FromCapiPublicKeyBlob(byte[] blob, int offset) + { + try + { + if ((blob[offset] != 0x06) || // PUBLICKEYBLOB (0x06) + (blob[offset + 1] != 0x02) || // Version (0x02) + (blob[offset + 2] != 0x00) || // Reserved (word) + (blob[offset + 3] != 0x00) || + (ToUInt32LE(blob, offset + 8) != 0x31415352)) // DWORD magic = RSA1 + { + throw new CryptographicException("Invalid blob header"); + } + + //// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) + //// int algId = ToInt32LE (blob, offset+4); + + // DWORD bitlen + int bitLen = ToInt32LE(blob, offset + 12); + + //// DWORD public exponent + var rsap = new RSAParameters + { + Exponent = new byte[3] + }; + + rsap.Exponent[0] = blob[offset + 18]; + rsap.Exponent[1] = blob[offset + 17]; + rsap.Exponent[2] = blob[offset + 16]; + + int pos = offset + 20; + //// BYTE modulus[rsapubkey.bitlen/8]; + int byteLen = bitLen >> 3; + rsap.Modulus = new byte[byteLen]; + Buffer.BlockCopy(blob, pos, rsap.Modulus, 0, byteLen); + Array.Reverse(rsap.Modulus); + + RSA rsa = null; + try + { + rsa = RSA.Create(); + rsa.ImportParameters(rsap); + } + catch (CryptographicException) + { + // this may cause problem when this code is run under + // the SYSTEM identity on Windows (e.g. ASP.NET). See + // http://bugzilla.ximian.com/show_bug.cgi?id=77559 + var csp = new CspParameters + { + Flags = CspProviderFlags.UseMachineKeyStore + }; + +#pragma warning disable S4426 // Cryptographic keys should be robust + rsa = new RSACryptoServiceProvider(csp); +#pragma warning restore S4426 // Cryptographic keys should be robust + rsa.ImportParameters(rsap); + } + + return rsa; + } + catch (Exception e) + { + throw new CryptographicException("Invalid blob.", e); + } + } + + // PRIVATEKEYBLOB + // PUBLICKEYBLOB + static public RSA FromCapiKeyBlob(byte[] blob) + { + return FromCapiKeyBlob(blob, 0); + } + + static public RSA FromCapiKeyBlob(byte[] blob, int offset) + { + if (blob == null) + { + throw new ArgumentNullException(nameof(blob)); + } + + if (offset >= blob.Length) + { + throw new ArgumentException("blob is too small."); + } + + switch (blob[offset]) + { + case 0x00: + // this could be a public key inside an header + // like "sn -e" would produce + if (blob[offset + 12] == 0x06) + { + return FromCapiPublicKeyBlob(blob, offset + 12); + } + break; + case 0x06: + return FromCapiPublicKeyBlob(blob, offset); + case 0x07: + return FromCapiPrivateKeyBlob(blob, offset); + } + throw new CryptographicException("Unknown blob format."); + } + + static public byte[] ToCapiPublicKeyBlob(RSA rsa) + { + var p = rsa.ExportParameters(false); + int keyLength = p.Modulus.Length; // in bytes + byte[] blob = new byte[20 + keyLength]; + + blob[0] = 0x06; // Type - PUBLICKEYBLOB (0x06) + blob[1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02) + // [2], [3] // RESERVED - Always 0 + blob[5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN) + blob[8] = 0x52; // Magic - RSA1 (ASCII in hex) + blob[9] = 0x53; + blob[10] = 0x41; + blob[11] = 0x31; + + byte[] bitlen = GetBytesLE(keyLength << 3); + blob[12] = bitlen[0]; // bitlen + blob[13] = bitlen[1]; + blob[14] = bitlen[2]; + blob[15] = bitlen[3]; + + // public exponent (DWORD) + int pos = 16; + int n = p.Exponent.Length; + while (n > 0) + { + blob[pos++] = p.Exponent[--n]; + } + + // modulus + pos = 20; + byte[] part = p.Modulus; + int len = part.Length; + Array.Reverse(part, 0, len); + Buffer.BlockCopy(part, 0, blob, pos, len); + + return blob; + } + } +} diff --git a/src-ThirdParty/StrongNameSigner/SigningHelper.cs b/src-ThirdParty/StrongNameSigner/SigningHelper.cs new file mode 100644 index 00000000000..260e1c92147 --- /dev/null +++ b/src-ThirdParty/StrongNameSigner/SigningHelper.cs @@ -0,0 +1,35 @@ +// Original source can be found at +// https://github.com/brutaldev/StrongNameSigner/blob/c38d42ab8d1444504720a62736b310303236cd85/src/Brutal.Dev.StrongNameSigner/SigningHelper.cs#L437 +using System; +using Mono.Security.Cryptography; + + +namespace Brutal.Dev.StrongNameSigner { + /// + /// Static helper class for easily getting assembly information and strong-name signing .NET assemblies. + /// + public static class SigningHelper + { + internal static byte[] GetPublicKey (byte[] keyBlob) + { + using var rsa = CryptoConvert.FromCapiKeyBlob(keyBlob); + var cspBlob = CryptoConvert.ToCapiPublicKeyBlob(rsa); + var publicKey = new byte[12 + cspBlob.Length]; + Buffer.BlockCopy(cspBlob, 0, publicKey, 12, cspBlob.Length); + // The first 12 bytes are documented at: + // http://msdn.microsoft.com/library/en-us/cprefadd/html/grfungethashfromfile.asp + // ALG_ID - Signature + publicKey[1] = 36; + // ALG_ID - Hash + publicKey[4] = 4; + publicKey[5] = 128; + // Length of Public Key (in bytes) + publicKey[8] = (byte)(cspBlob.Length >> 0); + publicKey[9] = (byte)(cspBlob.Length >> 8); + publicKey[10] = (byte)(cspBlob.Length >> 16); + publicKey[11] = (byte)(cspBlob.Length >> 24); + + return publicKey; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs new file mode 100644 index 00000000000..8a88408c42d --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +using Java.Interop.Tools.Cecil; + +using Mono.Linker; +using Mono.Linker.Steps; + +using Mono.Tuner; +#if ILLINK +using Microsoft.Android.Sdk.ILLink; +#endif // ILLINK + +namespace MonoDroid.Tuner +{ + public class FixLegacyResourceDesignerStep : LinkDesignerBase + { + internal const string DesignerAssemblyName = "_Microsoft.Android.Resource.Designer"; + internal const string DesignerAssemblyNamespace = "Microsoft.Android.Resource.Designer"; +#if ILLINK + protected override void Process () + { + cache = Context; + } +#else // ILLINK + public FixLegacyResourceDesignerStep (IMetadataResolver cache) + { + this.cache = cache; + } + + readonly +#endif // ILLINK + IMetadataResolver cache; + AssemblyDefinition designerAssembly = null; + TypeDefinition designerType = null; + Dictionary lookup; + + protected override void EndProcess () + { + if (designerAssembly != null) { + LogMessage ($" Setting Action on {designerAssembly.Name} to Link."); + Annotations.SetAction (designerAssembly, AssemblyAction.Link); + } + } + + protected override void LoadDesigner () + { + if (designerAssembly != null) + return; + var designerNameAssembly = AssemblyNameReference.Parse ($"{DesignerAssemblyName}, Version=1.0.0.0"); + try { + designerAssembly = Resolve (designerNameAssembly); + } catch (Mono.Cecil.AssemblyResolutionException) { + LogMessage ($" Could not resolve assembly {DesignerAssemblyName}."); + } catch (System.IO.FileNotFoundException) { + LogMessage ($" Assembly {DesignerAssemblyName} did not exist."); + } + if (designerAssembly == null) { + return; + } + designerType = designerAssembly.MainModule.GetTypes ().FirstOrDefault (x => x.FullName == $"{DesignerAssemblyNamespace}.Resource"); + if (designerType == null) { + LogMessage ($" Did not find {DesignerAssemblyNamespace}.Resource type. It was probably linked out."); + return; + } + lookup = BuildResourceDesignerPropertyLookup (designerType); + return; + } + + internal override bool ProcessAssemblyDesigner (AssemblyDefinition assembly) + { + if (designerAssembly == null || designerType == null) { + LogMessage ($" Not using {DesignerAssemblyName}"); + return false; + } + + if (!FindResourceDesigner (assembly, mainApplication: false, out TypeDefinition designer, out CustomAttribute designerAttribute)) { + LogMessage ($" {assembly.Name.Name} has no designer. "); + return false; + } + + LogMessage ($" {assembly.Name.Name} has a designer. "); + LogMessage ($" BaseType: {designer.BaseType.FullName}. "); + if (designer.BaseType.FullName == $"{DesignerAssemblyNamespace}.Resource") { + LogMessage ($" {assembly.Name.Name} has already been processed. "); + return false; + } + + LogMessage ($" Adding reference {designerAssembly.Name.Name}."); + assembly.MainModule.AssemblyReferences.Add (designerAssembly.Name); + var importedDesignerType = assembly.MainModule.ImportReference (designerType.Resolve ()); + + LogMessage ($" FixupAssemblyTypes {assembly.Name.Name}."); + // now replace all ldsfld with a call to the property get_ method. + FixupAssemblyTypes (assembly, designer); + + LogMessage ($" ClearDesignerClass {assembly.Name.Name}."); + // then clean out the designer. + ClearDesignerClass (designer, completely: true); + designer.BaseType = importedDesignerType; + return true; + } + + Dictionary BuildResourceDesignerPropertyLookup (TypeDefinition type) + { + LogMessage ($" Building Designer Lookups for {type.FullName}"); + var output = new Dictionary (StringComparer.Ordinal); + foreach (TypeDefinition definition in type.NestedTypes) + { + foreach (PropertyDefinition property in definition.Properties) + { + string key = $"{definition.Name}::{property.Name}"; + if (!output.ContainsKey (key)) { + LogMessage ($" Adding {key}"); + output.Add(key, property.GetMethod); + } + } + } + return output; + } + + protected override void FixBody (MethodBody body, TypeDefinition designer) + { + // replace + // IL_0068: ldsfld int32 Xamarin.Forms.Platform.Android.Resource/Layout::Toolbar + // with + // call int32 Xamarin.Forms.Platform.Android.Resource/Layout::get_Toolbar() + string designerFullName = $"{designer.FullName}/"; + var processor = body.GetILProcessor (); + Dictionary instructions = new Dictionary(); + foreach (var i in body.Instructions) + { + if (i.OpCode != OpCodes.Ldsfld) + continue; + string line = i.ToString (); + int idx = line.IndexOf (designerFullName, StringComparison.Ordinal); + if (idx >= 0) { + string key = line.Substring (idx + designerFullName.Length); + LogMessage ($"Looking for {key}."); + if (lookup.TryGetValue (key, out MethodDefinition method)) { + var importedMethod = designer.Module.ImportReference (method); + var newIn = Instruction.Create (OpCodes.Call, importedMethod); + instructions.Add (i, newIn); + } else { + LogMessage ($"DEBUG! Failed to find {key}!"); + } + } + } + if (instructions.Count > 0) + LogMessage ($" Fixing up {body.Method.FullName}"); + foreach (var i in instructions) + { + LogMessage ($" Replacing {i.Key}"); + LogMessage ($" With {i.Value}"); + processor.Replace(i.Key, i.Value); + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs index 928fdfd6e4f..f03fa12d0fc 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs @@ -67,20 +67,24 @@ protected bool FindResourceDesigner (AssemblyDefinition assembly, bool mainAppli return false; } - protected void ClearDesignerClass (TypeDefinition designer) + protected void ClearDesignerClass (TypeDefinition designer, bool completely = false) { LogMessage ($" TryRemoving {designer.FullName}"); // for each of the nested types clear all but the // int[] fields. - for (int i = designer.NestedTypes.Count -1; i >= 0; i--) { - var nestedType = designer.NestedTypes [i]; - RemoveFieldsFromType (nestedType, designer.Module); - if (nestedType.Fields.Count == 0) { - // no fields we do not need this class at all. - designer.NestedTypes.RemoveAt (i); + if (!completely) { + for (int i = designer.NestedTypes.Count -1; i >= 0; i--) { + var nestedType = designer.NestedTypes [i]; + RemoveFieldsFromType (nestedType, designer.Module); + if (nestedType.Fields.Count == 0) { + // no fields we do not need this class at all. + designer.NestedTypes.RemoveAt (i); + } } + RemoveUpdateIdValues (designer); + } else { + designer.NestedTypes.Clear (); } - RemoveUpdateIdValues (designer); designer.Fields.Clear (); designer.Properties.Clear (); designer.CustomAttributes.Clear (); diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/Linker.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/Linker.cs index cca2056cf35..45c3a3feeb3 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/Linker.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/Linker.cs @@ -111,6 +111,8 @@ static Pipeline CreatePipeline (LinkerOptions options) pipeline.AppendStep (new RemoveResources (options.I18nAssemblies)); // remove collation tables // end monodroid specific + if (options.UseDesignerAssembly) + pipeline.AppendStep (new FixLegacyResourceDesignerStep (cache)); pipeline.AppendStep (new FixAbstractMethodsStep (cache)); pipeline.AppendStep (new MonoDroidMarkStep (cache)); pipeline.AppendStep (new SweepStep ()); diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkerOptions.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkerOptions.cs index 0cd81bb8641..1886d50915e 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkerOptions.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkerOptions.cs @@ -26,5 +26,6 @@ class LinkerOptions public bool PreserveJniMarshalMethods { get; set; } public bool DeterministicOutput { get; set; } public bool LinkResources { get; set; } + public bool UseDesignerAssembly { get; set; } } } 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 8827e1ceb51..d1bfde205de 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 @@ -154,7 +154,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. --no-version-vectors $(AndroidAapt2LinkExtraArgs) + + + + + + + + + + False + + + + + <_DesignerAssemblyName>_Microsoft.Android.Resource.Designer + + <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' And Exists ('$(IntermediateOutputPath)$(_DesignerAssemblyName).dll') ">$(IntermediateOutputPath) + <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' And '$(_OuterIntermediateOutputPath)' != '' And Exists ('$(_OuterIntermediateOutputPath)$(_DesignerAssemblyName).dll') ">$(_OuterIntermediateOutputPath) + + <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' And '$(_OuterIntermediateOutputPath)' != '' ">$(_OuterIntermediateOutputPath) + <_DesignerIntermediateOutputPath Condition=" '$(_DesignerIntermediateOutputPath)' == '' ">$(IntermediateOutputPath) + <_GenerateResourceDesignerAssemblyOutput>$(_DesignerIntermediateOutputPath)$(_DesignerAssemblyName).dll + <_GenerateResourceDesignerClassFile Condition=" '$(Language)' == 'F#' ">$(_DesignerIntermediateOutputPath)_$(_DesignerAssemblyName).fs + <_GenerateResourceDesignerClassFile Condition=" '$(_GenerateResourceDesignerClassFile)' == '' ">$(_DesignerIntermediateOutputPath)_$(_DesignerAssemblyName).cs + <_GenerateResourceCaseMapFile>$(_DesignerIntermediateOutputPath)case_map.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ErrorItems Include="@(_MonoAndroidReferencePath)" Condition=" '%(_MonoAndroidReferencePath.HasResourceDesignerAssemblyReference)' == 'True' "/> + <_ErrorItems Include="@(_MonoAndroidReferenceDependencyPaths)" Condition=" '%(_MonoAndroidReferenceDependencyPaths.HasResourceDesignerAssemblyReference)' == 'True' "/> + + + + + + <_BuildResourceDesignerDependsOn> + _SetupDesignerProperties; + _GenerateResourceCaseMap; + _GenerateRtxt; + _GenerateResourceDesignerIntermediateClass; + _GenerateResourceDesignerAssembly; + _AddResourceDesignerFiles; + + + + + + + PreserveNewest + + + + + + + + + + + + + $(_DesignerAssemblyName).dll + PreserveNewest + true + true + + + + + + + \ No newline at end of file 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 e15b10a264f..c4a7a91b861 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 @@ -67,6 +67,14 @@ _ResolveAssemblies MSBuild target. + + + True + PreserveNewest + false + android + + <_DebugSymbolsIntermediatePath Remove="@(_DebugSymbolsIntermediatePath)" /> <_DebugSymbolsIntermediatePath Include="$([System.IO.Path]::ChangeExtension ($(_OuterIntermediateAssembly), '.pdb'))" /> 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 b9305f91637..fa15917a912 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 @@ -107,6 +107,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. + _CreatePropertiesCache; _SeparateAppExtensionReferences; $(ResolveReferencesDependsOn); _ConvertAndroidMamMappingFileToXml; @@ -116,17 +117,25 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. $(CoreResolveReferencesDependsOn); - UpdateAndroidInterfaceProxies; UpdateAndroidResources; + _BuildResourceDesigner; + UpdateAndroidInterfaceProxies; _SetAndroidGenerateManagedBindings; AddBindingsToCompile; + _CheckForInvalidDesignerConfig; + + $(DesignTimeResolveAssemblyReferencesDependsOn); + _BuildResourceDesigner; + <_UpdateAndroidResourcesDependsOn> $(CoreResolveReferencesDependsOn); _CreatePropertiesCache; _CheckForDeletedResourceFile; _ComputeAndroidResourcePaths; _UpdateAndroidResgen; + _CreateAar; + _BuildResourceDesigner; _SetupMSBuildAllProjects; @@ -134,6 +143,8 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. _AddAndroidDefines; _IncludeLayoutBindingSources; AddLibraryJarsToBind; + _BuildResourceDesigner; + _AddResourceDesignerFiles; $(CompileDependsOn); _CheckAndroidHttpClientHandlerType; @@ -170,6 +181,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. _BeforeGetAndroidDependencies; _SetLatestTargetFrameworkVersion; _ResolveSdks; + _ResolveMonoAndroidSdks; _ResolveAndroidTooling; $(GetAndroidDependenciesDependsOn); diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index 687dc79e266..43ed246a334 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -10,6 +10,8 @@ true Xamarin.Android.Net.AndroidMessageHandler Xamarin.Android.Net.AndroidClientHandler + true + false true $(AndroidGenerateResourceDesigner) false diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets index f28c5b6d9d5..7400de192ff 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets @@ -88,7 +88,12 @@ This file contains the .NET 5-specific targets to customize ILLink AfterStep="CleanStep" Type="MonoDroid.Tuner.GetAssembliesStep" /> - + <_TrimmerCustomSteps + Condition=" '$(AndroidUseDesignerAssembly)' == 'true' " + Include="$(_AndroidLinkerCustomStepAssembly)" + BeforeStep="MarkStep" + Type="MonoDroid.Tuner.FixLegacyResourceDesignerStep" + /> <_PreserveLists Include="$(MSBuildThisFileDirectory)..\PreserveLists\*.xml" /> <_AndroidFilesToPublish Include="$(OutputPath)*.%(_AndroidPackageFormats.Identity)" /> <_AndroidFilesToPublish Include="$(AndroidProguardMappingFile)" Condition="Exists ('$(AndroidProguardMappingFile)')" /> + <_AndroidFilesToPublish Include="$(_GenerateResourceDesignerAssemblyOutput)" Condition="Exists('$(_GenerateResourceDesignerAssemblyOutput)')" /> diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index b2a969da7cc..05f4c4e0c4c 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -728,6 +728,15 @@ public static string XA1028 { } } + /// + /// Looks up a localized string similar to The 'AndroidEnableProguard' MSBuild property is set to 'true' and the 'AndroidLinkTool' MSBuild property is empty, so 'AndroidLinkTool' will default to 'proguard'.. + /// + public static string XA1031 { + get { + return ResourceManager.GetString("XA1031", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in Xamarin.Android once .NET 6 is released.. /// diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index ac48bbe6967..a526aa6c63b 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -487,6 +487,10 @@ Please change the value to an assembly-qualifed type name which inherits from '{ Could not resolve '{0}'. Please check your `AndroidHttpClientHandlerType` setting. The following are literal names and should not be translated: 'AndroidHttpClientHandlerType', {0} - The value of the property. + + Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file. + The following are literal names and should not be translated: '_Microsoft.Android.Resource.Desinger', 'AndroidUseDesignerAssembly', 'true' +{0} - The name of the assembly Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in Xamarin.Android once .NET 6 is released. diff --git a/src/Xamarin.Android.Build.Tasks/Resources/Resource.Designer.snk b/src/Xamarin.Android.Build.Tasks/Resources/Resource.Designer.snk new file mode 100644 index 0000000000000000000000000000000000000000..7f3d225c9d23ae363ae3378adb74e2b0c860d59e GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098026=^U^~-OCvXK3hrS`Mi9$2T05eInu z%u!T#dB{ERX+i@+0*f`VmqMtp0n(;Ep79;#Oid*rH=5Acn+qM0=?#T6V!VZwa=&_- zLLFfKy>c6dkp(~}mbQL`5AWqjP3S9QiCLe+&9xa)oph2omoO&;feli8Ts_@j62^nO z7Cl?z7W;b)ejklVInG->T>)KEqpH0%2f!3eQ8SuOv@$%+#Q-}zD_7L~QDXlK2qSOT z24oe49RNY9lAOTnYv0|oaEwef7a-~u-y!blIRFO1%#hwDDQ)E2T|t29h~-CuQt6Zn zR37YYxD;QuBAz+3qrUE%i@shj@FTCg_90|@0X!NF`MNrkkDQaf_*_)x?hGG}+9p3~ zV6K6qJcZk;15>|w)RygGHeO*t=4qbQghEyJmQ=n4;cJBNHLt~AmUha-*FoU+Zfv6^ z{$!G9kW=?cIA#qcn8R;@j?BdH(~!v{;ZWiZ+`})IHMoLSmH~KKlc6`)DZh+XL)tXE z8#zV{t#Ux;jU-=zTsAkE0MY9SbDI~@c0B2NR|MN1;U5y1uQpnS%oZDZZ=gUlT#dQX z_#Q1UGzz!bmMO36?&OQ??;+oTK_ tempFiles = new List (); SortedSet rulesFiles = new SortedSet (); Dictionary apks = new Dictionary (); + string resourceSymbolsTextFileTemp; protected override int GetRequiredDaemonInstances () { @@ -93,6 +94,8 @@ public async override System.Threading.Tasks.Task RunTaskAsync () try { assemblyMap.Load (Path.Combine (WorkingDirectory, AssemblyIdentityMapFile)); + resourceSymbolsTextFileTemp = GetTempFile (); + await this.WhenAll (ManifestFiles, ProcessManifest); ProcessOutput (); @@ -132,6 +135,8 @@ public async override System.Threading.Tasks.Task RunTaskAsync () } Files.CopyIfStringChanged (sb.ToString (), ProguardRuleOutput); } + if (!string.IsNullOrEmpty (ResourceSymbolsTextFile)) + Files.CopyIfChanged (resourceSymbolsTextFileTemp, GetFullPath (ResourceSymbolsTextFile)); } finally { lock (tempFiles) { foreach (var temp in tempFiles) { @@ -253,7 +258,7 @@ string [] GenerateCommandLineCommands (string ManifestFile, string currentAbi, s if (!string.IsNullOrEmpty (ResourceSymbolsTextFile)) { cmd.Add ("--output-text-symbols"); - cmd.Add (GetFullPath (ResourceSymbolsTextFile)); + cmd.Add (GetFullPath (resourceSymbolsTextFileTemp)); } if (ProtobufFormat) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/AppendCustomMetadataToItemGroup.cs b/src/Xamarin.Android.Build.Tasks/Tasks/AppendCustomMetadataToItemGroup.cs index ffd28e90201..9ab1d323596 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/AppendCustomMetadataToItemGroup.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/AppendCustomMetadataToItemGroup.cs @@ -35,6 +35,11 @@ public override bool RunTask () foreach (var item in Inputs) { var fn = Path.GetFileNameWithoutExtension (item.ItemSpec); output.Add (item); + var md = item.GetMetadata ("HasResourceDesignerAssemblyReference"); + if (string.IsNullOrEmpty (md)) { + var b = MonoAndroidHelper.HasResourceDesignerAssemblyReference (item); + item.SetMetadata ("HasResourceDesignerAssemblyReference", MonoAndroidHelper.HasResourceDesignerAssemblyReference (item).ToString ()); + } List metaDataList; if (!metaData.TryGetValue (fn, out metaDataList)) continue; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ConvertCustomView.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ConvertCustomView.cs index ea7a65b7a57..9e88ff78d2f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ConvertCustomView.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ConvertCustomView.cs @@ -31,7 +31,7 @@ public class ConvertCustomView : AndroidTask { public override bool RunTask () { - var acw_map = MonoAndroidHelper.LoadAcwMapFile (AcwMapFile); + var acw_map = MonoAndroidHelper.LoadMapFile (BuildEngine4, AcwMapFile, StringComparer.Ordinal); var customViewMap = MonoAndroidHelper.LoadCustomViewMapFile (BuildEngine4, CustomViewMapFile); var processed = new HashSet (); @@ -119,8 +119,8 @@ bool TryFixCustomClassAttribute (XAttribute attr, Dictionary acw bool TryFixFragment (XAttribute attr, Dictionary acwMap) { - // Looks for any: - // ParseFile (StreamReader reader) while (!reader.EndOfStream) { var line = reader.ReadLine (); var items = line.Split (Delimiter, 4); - yield return items; + if (items.Length == 4) + yield return items; } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index e8638b29761..a87f24a5832 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -471,7 +471,7 @@ void GetRequiredTokens (string assemblyFilePath, out int android_runtime_jnienv_ } if (android_runtime_jnienv_class_token == -1 || jnienv_initialize_method_token == -1 || jnienv_registerjninatives_method_token == -1) { - throw new InvalidOperationException ($"Unable to find the required Android.Runtime.JNIEnvInit method tokens"); + throw new InvalidOperationException ($"Unable to find the required Android.Runtime.JNIEnvInit method tokens for {assemblyFilePath}"); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs new file mode 100644 index 00000000000..9717be99f74 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceCaseMap.cs @@ -0,0 +1,121 @@ +// Copyright (C) 2021 Microsoft, Inc. All rights reserved. +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.Android.Build.Tasks; + +namespace Xamarin.Android.Tasks +{ + public class GenerateResourceCaseMap : AndroidTask + { + public override string TaskPrefix => "GRCM"; + public ITaskItem[] Resources { get; set; } + + [Required] + public string ResourceDirectory { get; set; } + + [Required] + public string ProjectDir { get; set; } + + public ITaskItem[] AdditionalResourceDirectories { get; set; } + + [Required] + public ITaskItem OutputFile { get; set; } + + private Dictionary resource_fixup = new Dictionary (StringComparer.OrdinalIgnoreCase); + + public override bool RunTask () + { + // ResourceDirectory may be a relative path, and + // we need to compare it to absolute paths + ResourceDirectory = Path.GetFullPath (ResourceDirectory); + + // Create our capitalization maps so we can support mixed case resources + foreach (var item in Resources) { + var path = Path.GetFullPath (item.ItemSpec); + if (!path.StartsWith (ResourceDirectory, StringComparison.OrdinalIgnoreCase)) { + Log.LogDebugMessage ($"Skipping {item}. Path is not include the '{ResourceDirectory}'"); + continue; + } + + var name = path.Substring (ResourceDirectory.Length).TrimStart ('/', '\\'); + var logical_name = item.GetMetadata ("LogicalName").Replace ('\\', '/'); + if (string.IsNullOrEmpty (logical_name)) + logical_name = Path.GetFileName (path); + + AddRename (name.Replace ('/', Path.DirectorySeparatorChar), logical_name.Replace ('/', Path.DirectorySeparatorChar)); + } + foreach (var additionalDir in AdditionalResourceDirectories ?? Array.Empty()) { + var dir = Path.Combine (ProjectDir, Path.GetDirectoryName (additionalDir.ItemSpec)); + var file = Path.Combine (dir, "__res_name_case_map.txt"); + if (!File.Exists (file)) { + // .NET 6 .aar files place the file in a sub-directory + file = Path.Combine (dir, ".net", "__res_name_case_map.txt"); + if (!File.Exists (file)) + continue; + } + foreach (var line in File.ReadLines (file)) { + if (string.IsNullOrEmpty (line)) + continue; + string [] tok = line.Split (';'); + AddRename (tok [1].Replace ('/', Path.DirectorySeparatorChar), tok [0].Replace ('/', Path.DirectorySeparatorChar)); + } + } + + if (MonoAndroidHelper.SaveMapFile (BuildEngine4, Path.GetFullPath (OutputFile.ItemSpec), resource_fixup)) { + Log.LogDebugMessage ($"Writing to: {OutputFile.ItemSpec}"); + } else { + Log.LogDebugMessage ($"Up to date: {OutputFile.ItemSpec}"); + } + + return !Log.HasLoggedErrors; + } + + private void AddRename (string android, string user) + { + var from = android; + var to = user; + + if (from.Contains ('.')) + from = from.Substring (0, from.LastIndexOf ('.')); + if (to.Contains ('.')) + to = to.Substring (0, to.LastIndexOf ('.')); + + from = NormalizeAlternative (from); + to = NormalizeAlternative (to); + + string curTo; + + if (resource_fixup.TryGetValue (from, out curTo)) { + if (string.Compare (to, curTo, StringComparison.OrdinalIgnoreCase) != 0) { + var ext = Path.GetExtension (android); + var dir = Path.GetDirectoryName (user); + + Log.LogDebugMessage ("Resource target names differ; got '{0}', expected '{1}'.", + Path.Combine (dir, Path.GetFileName (to) + ext), + Path.Combine (dir, Path.GetFileName (curTo) + ext)); + } + return; + } + Log.LogDebugMessage ($"Adding map from '{from}' to '{to}'."); + resource_fixup.Add (from, to); + } + + static string NormalizeAlternative (string value) + { + int s = value.IndexOfAny (new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); + + if (s < 0) + return value; + + int a = value.IndexOf ('-'); + + return + ResourceParser.GetNestedTypeName (value.Substring (0, (a < 0 || a >= s) ? s : a)).ToLowerInvariant () + + value.Substring (s); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs index ba7fbe053a3..efb8fa465f5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs @@ -53,6 +53,8 @@ public class GenerateResourceDesigner : AndroidTask public string ResourceFlagFile { get; set; } + public string CaseMapFile { get; set; } + private Dictionary resource_fixup = new Dictionary (StringComparer.OrdinalIgnoreCase); public override bool RunTask () @@ -73,35 +75,7 @@ public override bool RunTask () var javaPlatformDirectory = Path.GetDirectoryName (JavaPlatformJarPath); - // Create our capitalization maps so we can support mixed case resources - foreach (var item in Resources) { - var path = Path.GetFullPath (item.ItemSpec); - if (!path.StartsWith (ResourceDirectory, StringComparison.OrdinalIgnoreCase)) - continue; - - var name = path.Substring (ResourceDirectory.Length).TrimStart ('/', '\\'); - var logical_name = item.GetMetadata ("LogicalName").Replace ('\\', '/'); - if (string.IsNullOrEmpty (logical_name)) - logical_name = Path.GetFileName (path); - - AddRename (name.Replace ('/', Path.DirectorySeparatorChar), logical_name.Replace ('/', Path.DirectorySeparatorChar)); - } - if (AdditionalResourceDirectories != null) { - foreach (var additionalDir in AdditionalResourceDirectories) { - var dir = Path.Combine (ProjectDir, Path.GetDirectoryName (additionalDir.ItemSpec)); - var file = Path.Combine (dir, "__res_name_case_map.txt"); - if (!File.Exists (file)) { - // .NET 6 .aar files place the file in a sub-directory - file = Path.Combine (dir, ".net", "__res_name_case_map.txt"); - if (!File.Exists (file)) - continue; - } - foreach (var line in File.ReadAllLines (file).Where (l => !string.IsNullOrEmpty (l))) { - string [] tok = line.Split (';'); - AddRename (tok [1].Replace ('/', Path.DirectorySeparatorChar), tok [0].Replace ('/', Path.DirectorySeparatorChar)); - } - } - } + resource_fixup = MonoAndroidHelper.LoadMapFile (BuildEngine4, CaseMapFile, StringComparer.OrdinalIgnoreCase); // Parse out the resources from the R.java file CodeTypeDeclaration resources; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerAssembly.cs new file mode 100644 index 00000000000..4ca7ea3f0f1 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerAssembly.cs @@ -0,0 +1,350 @@ +// Copyright (C) 2011 Xamarin, Inc. All rights reserved. +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.Android.Build.Tasks; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Java.Interop.Tools.Cecil; +using Brutal.Dev.StrongNameSigner; +using MonoDroid.Tuner; + +namespace Xamarin.Android.Tasks +{ + public class GenerateResourceDesignerAssembly : AndroidTask + { + public override string TaskPrefix => "GRDA"; + + [Required] + public ITaskItem RTxtFile { get; set; } + + public ITaskItem ResourceMap { get; set; } + + [Required] + public bool IsApplication { get; set; } + + [Required] + public bool DesignTimeBuild { get; set; } + + [Required] + public ITaskItem OutputFile { get; set; } + + [Required] + public string TargetFrameworkVersion { get; set; } + + [Required] + public string TargetFrameworkIdentifier { get; set; } + + [Required] + public string ProjectDir { get; set; } + + [Required] + public ITaskItem[] Resources { get; set; } + + [Required] + public string ResourceDirectory { get; set; } + public string CaseMapFile { get; set; } + public ITaskItem[] AdditionalResourceDirectories { get; set; } + public ITaskItem[] FrameworkDirectories { get; set; } + public bool Deterministic { get; set; } + public string AssemblyName { get; set; } + TypeReference intArray; + TypeReference intRef; + TypeReference objectRef; + Dictionary resource_fixup = new Dictionary (StringComparer.OrdinalIgnoreCase); + + public override bool RunTask () + { + using (var res = new DirectoryAssemblyResolver (this.CreateTaskLogger (), loadDebugSymbols: false)) { + Run(res); + } + return !Log.HasLoggedErrors; + } + + bool Run(DirectoryAssemblyResolver res) + { + foreach (var dir in FrameworkDirectories) { + if (Directory.Exists (dir.ItemSpec)) + res.SearchDirectories.Add (dir.ItemSpec); + } + // ResourceDirectory may be a relative path, and + // we need to compare it to absolute paths + ResourceDirectory = Path.GetFullPath (ResourceDirectory); + + string assemblyName = Path.GetFileNameWithoutExtension (OutputFile.ItemSpec); + + resource_fixup = MonoAndroidHelper.LoadMapFile (BuildEngine4, CaseMapFile, StringComparer.OrdinalIgnoreCase); + // Generate an assembly which contains all the values in the provided + // R.txt file. + var mp = new ModuleParameters (); + mp.AssemblyResolver = res; + mp.Kind = ModuleKind.Dll; + var assembly = AssemblyDefinition.CreateAssembly ( + new AssemblyNameDefinition (assemblyName, new Version (1, 0)), + assemblyName, + mp); + + var module = assembly.MainModule; + + module.AssemblyReferences.Clear (); + var netstandardAsm = AssemblyNameReference.Parse ("netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"); + module.AssemblyReferences.Add(netstandardAsm); + var netstandardDef = module.AssemblyResolver.Resolve(netstandardAsm); + + if (!IsApplication) { + MethodReference referenceAssemblyConstructor = ImportCustomAttributeConstructor ("System.Runtime.CompilerServices.ReferenceAssemblyAttribute", module, netstandardDef.MainModule); + module.Assembly.CustomAttributes.Add (new CustomAttribute (referenceAssemblyConstructor)); + } else { + // Add the InternalsVisibleToAttribute so the app can access ResourceConstant + if (!string.IsNullOrEmpty (AssemblyName)) { + MethodReference internalsVisibleToAttributeConstructor = ImportCustomAttributeConstructor ("System.Runtime.CompilerServices.InternalsVisibleToAttribute", module, netstandardDef.MainModule); + var ar = new CustomAttribute (internalsVisibleToAttributeConstructor); + ar.ConstructorArguments.Add (new CustomAttributeArgument (module.TypeSystem.String, AssemblyName)); + module.Assembly.CustomAttributes.Add (ar); + } + } + + MethodReference targetFrameworkConstructor = ImportCustomAttributeConstructor ("System.Runtime.Versioning.TargetFrameworkAttribute", module, netstandardDef.MainModule); + + var attr = new CustomAttribute (targetFrameworkConstructor); + attr.ConstructorArguments.Add (new CustomAttributeArgument (module.TypeSystem.String, $".NETStandard,Version=v2.1")); + attr.Properties.Add (new CustomAttributeNamedArgument ("FrameworkDisplayName", new CustomAttributeArgument (module.TypeSystem.String, ""))); + module.Assembly.CustomAttributes.Add (attr); + + var att = TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.BeforeFieldInit; + + intArray = new ArrayType (module.TypeSystem.Int32); + intRef = module.TypeSystem.Int32; + objectRef = module.TypeSystem.Object; + + // The Property Based class. + var resourceDesigner = new TypeDefinition ( + FixLegacyResourceDesignerStep.DesignerAssemblyNamespace, + "Resource", + att, + objectRef + ); + CreateCtor (resourceDesigner, module); + module.Types.Add (resourceDesigner); + TypeDefinition constDesigner = null; + if (IsApplication) { + // The Constant based class + TypeAttributes attrib = string.IsNullOrEmpty (AssemblyName) ? TypeAttributes.Public : TypeAttributes.Public; + constDesigner = new TypeDefinition ( + FixLegacyResourceDesignerStep.DesignerAssemblyNamespace, + "ResourceConstant", + attrib | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit, + objectRef + ); + CreateCtor (constDesigner, module); + module.Types.Add (constDesigner); + } + + DateTime lastWriteTimeUtc = DateTime.MinValue; + if (File.Exists (OutputFile.ItemSpec)) + lastWriteTimeUtc = File.GetLastWriteTimeUtc (OutputFile.ItemSpec); + + if (File.Exists (RTxtFile.ItemSpec)) { + if (File.GetLastWriteTimeUtc (RTxtFile.ItemSpec) < lastWriteTimeUtc) { + Log.LogDebugMessage ($"{RTxtFile.ItemSpec} has not changed since {OutputFile.ItemSpec} was generated."); + return !Log.HasLoggedErrors; + } + var parser = new RtxtParser (); + var resources = parser.Parse (RTxtFile.ItemSpec, Log, resource_fixup); + foreach (var r in resources) { + switch (r.Type) { + case RType.Integer: + if (IsApplication) + CreateIntField (r.ResourceTypeName, r.Identifier, r.Id, constDesigner, module); + CreateIntProperty (r.ResourceTypeName, r.Identifier, r.Id, resourceDesigner, module); + break; + case RType.Array: + if (IsApplication) + CreateIntArrayField (r.ResourceTypeName, r.Identifier, r.Ids, constDesigner, module); + CreateIntArrayProperty (r.ResourceTypeName, r.Identifier, r.Ids, resourceDesigner, module); + break; + } + } + } + // Add a return to each of the static constructor + foreach(var c in staticConstructors) { + var il = c.Value.Body.GetILProcessor (); + il.Emit(OpCodes.Ret); + } + StrongNameAssembly (assembly.Name); + var wp = new WriterParameters () { + DeterministicMvid = Deterministic, + }; + var s = MemoryStreamPool.Shared.Rent (); + try { + assembly.Write (s, wp); + s.Position = 0; + if (Files.CopyIfStreamChanged (s, OutputFile.ItemSpec)) { + Log.LogDebugMessage ($"Updated '{OutputFile.ItemSpec}'."); + } else { + Log.LogDebugMessage ($"'{OutputFile.ItemSpec}' was up to date."); + } + } finally { + MemoryStreamPool.Shared.Return (s); + } + return !Log.HasLoggedErrors; + } + + MethodReference ImportCustomAttributeConstructor (string type, ModuleDefinition module, ModuleDefinition sourceModule = null) + { + var tr = module.ImportReference ((sourceModule ?? module).ExportedTypes.First(x => x.FullName == type).Resolve ()); + var tv = tr.Resolve(); + return module.ImportReference (tv.Methods.First(x => x.IsConstructor)); + } + + void CreateIntProperty (string resourceClass, string propertyName, int value, TypeDefinition resourceDesigner, ModuleDefinition module, + MethodAttributes attributes = MethodAttributes.Public, TypeAttributes typeAttributes = TypeAttributes.NestedPublic) + { + TypeDefinition nestedType = CreateResourceClass (resourceDesigner, resourceClass, module, typeAttributes); + PropertyDefinition p = CreateProperty (propertyName, value, module, attributes); + nestedType.Properties.Add (p); + nestedType.Methods.Insert (Math.Max(0, nestedType.Methods.Count () -1), p.GetMethod); + } + + void CreateIntField (string resourceClass, string fieldName, int value, TypeDefinition resourceDesigner, ModuleDefinition module, + FieldAttributes attributes = FieldAttributes.Public, TypeAttributes typeAttributes = TypeAttributes.NestedPublic) + { + TypeDefinition nestedType = CreateResourceClass (resourceDesigner, resourceClass, module, typeAttributes); + FieldDefinition p = CreateField (fieldName, value, module, attributes); + nestedType.Fields.Add (p); + } + + void CreateIntArrayProperty (string resourceClass, string propertyName, int[] values, TypeDefinition resourceDesigner, ModuleDefinition module, + MethodAttributes attributes = MethodAttributes.Public, TypeAttributes typeAttributes = TypeAttributes.NestedPublic) + { + TypeDefinition nestedType = CreateResourceClass (resourceDesigner, resourceClass, module, typeAttributes); + PropertyDefinition p = CreateArrayProperty (propertyName, values, module, attributes); + nestedType.Properties.Add (p); + nestedType.Methods.Insert (Math.Max(0, nestedType.Methods.Count () -1), p.GetMethod); + } + + void CreateIntArrayField (string resourceClass, string fieldName, int[] values, TypeDefinition resourceDesigner, ModuleDefinition module, + FieldAttributes attributes = FieldAttributes.Public, TypeAttributes typeAttributes = TypeAttributes.NestedPublic) + { + TypeDefinition nestedType = CreateResourceClass (resourceDesigner, resourceClass, module, typeAttributes); + FieldDefinition p = CreateArrayField (fieldName, values, module, attributes); + nestedType.Fields.Add (p); + MethodDefinition ctor = GetOrCreateStaticCtor (nestedType, module); + ILProcessor il = ctor.Body.GetILProcessor (); + il.Emit (OpCodes.Ldc_I4, values.Length); // store array size + il.Emit (OpCodes.Newarr, intRef); //create a new array + il.Emit (OpCodes.Stsfld, p); + int index = 0; + foreach (int value in values) { + il.Emit (OpCodes.Ldsfld, p); + il.Emit (OpCodes.Ldc_I4, index++); // index + il.Emit (OpCodes.Ldc_I4, value); // value + il.Emit (OpCodes.Stelem_I4); + } + } + + Dictionary resourceClasses = new Dictionary (StringComparer.OrdinalIgnoreCase); + Dictionary staticConstructors = new Dictionary (); + + void CreateCtor (TypeDefinition type, ModuleDefinition module) + { + var ctor = new MethodDefinition (".ctor", MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, module.TypeSystem.Void); + var ctoril = ctor.Body.GetILProcessor (); + ctoril.Emit (OpCodes.Ldarg_0); + var o = module.TypeSystem.Object.Resolve (); + ctoril.Emit (OpCodes.Call, module.ImportReference (o.Methods.First (x => x.IsConstructor))); + ctoril.Emit (OpCodes.Ret); + type.Methods.Add (ctor); + } + + MethodDefinition GetOrCreateStaticCtor (TypeDefinition type, ModuleDefinition module) + { + string key = type.FullName + ".cctor"; + if (staticConstructors.ContainsKey (key)) + return staticConstructors[key]; + var ctor = new MethodDefinition (".cctor", MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Static, module.TypeSystem.Void); + type.Methods.Add (ctor); + type.IsBeforeFieldInit = false; + staticConstructors.Add (key, ctor); + return ctor; + } + + TypeDefinition CreateResourceClass (TypeDefinition resourceDesigner, string className, ModuleDefinition module, TypeAttributes attributes = TypeAttributes.NestedPublic) + { + string name = ResourceParser.GetNestedTypeName (className); + string key = resourceDesigner.Name + name; + if (resourceClasses.ContainsKey (key)) { + return resourceClasses[key]; + } + var resourceClass = new TypeDefinition (string.Empty, name, attributes | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed, objectRef); + CreateCtor (resourceClass, module); + resourceDesigner.NestedTypes.Add (resourceClass); + resourceClasses[key] = resourceClass; + return resourceClass; + } + + PropertyDefinition CreateProperty (string propertyName, int value, ModuleDefinition module, MethodAttributes attributes = MethodAttributes.Public) + { + var p = new PropertyDefinition (propertyName, PropertyAttributes.None, intRef); + var getter = new MethodDefinition ($"get_{propertyName}", attributes | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Static, intRef); + p.GetMethod = getter; + p.SetMethod = null; + var il = p.GetMethod.Body.GetILProcessor (); + il.Emit (OpCodes.Ldc_I4, value); + il.Emit (OpCodes.Ret); + return p; + } + + FieldDefinition CreateField (string fieldName, int value, ModuleDefinition module, FieldAttributes attributes = FieldAttributes.Public) + { + var f = new FieldDefinition (fieldName, attributes | FieldAttributes.Literal | FieldAttributes.Static | FieldAttributes.HasDefault, intRef); + f.Constant = value; + return f; + } + + FieldDefinition CreateArrayField (string fieldName, int[] values, ModuleDefinition module, FieldAttributes attributes = FieldAttributes.Public) + { + var f = new FieldDefinition (fieldName, attributes | FieldAttributes.Static | FieldAttributes.HasDefault, intArray); + f.Constant = values; + return f; + } + + PropertyDefinition CreateArrayProperty (string propertyName, int[] values, ModuleDefinition module, MethodAttributes attributes = MethodAttributes.Public) + { + var p = new PropertyDefinition (propertyName, PropertyAttributes.None, intArray); + var getter = new MethodDefinition ($"get_{propertyName}", attributes | MethodAttributes.Static, intArray); + p.GetMethod = getter; + p.SetMethod = null; + var il = p.GetMethod.Body.GetILProcessor (); + il.Emit (OpCodes.Ldc_I4, values.Length); + il.Emit (OpCodes.Newarr, intRef); + int index = 0; + foreach (int value in values) { + il.Emit (OpCodes.Dup); + il.Emit (OpCodes.Ldc_I4, index++); + il.Emit (OpCodes.Ldc_I4, value); + il.Emit (OpCodes.Stelem_I4); + } + il.Emit (OpCodes.Ret); + return p; + } + + void StrongNameAssembly (AssemblyNameDefinition name) + { + using (Stream stream = typeof (GenerateResourceDesignerAssembly).Assembly.GetManifestResourceStream ("Resource.Designer.snk")) { + byte[] publicKey = new byte[stream.Length]; + stream.Read (publicKey, 0, publicKey.Length); + name.HashAlgorithm = AssemblyHashAlgorithm.SHA1; + name.PublicKey = SigningHelper.GetPublicKey (publicKey); + name.HasPublicKey = true; + name.Attributes |= AssemblyAttributes.PublicKey; + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerIntermediateClass.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerIntermediateClass.cs new file mode 100644 index 00000000000..9247993a554 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerIntermediateClass.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using System.CodeDom.Compiler; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.Android.Build.Tasks; +using MonoDroid.Tuner; + +namespace Xamarin.Android.Tasks +{ + public class GenerateResourceDesignerIntermediateClass : AndroidTask + { + public override string TaskPrefix => "GRDIC"; + + private const string ResourceDesigner = $"{FixLegacyResourceDesignerStep.DesignerAssemblyNamespace}.Resource"; + private const string ResourceDesignerConstants = $"{FixLegacyResourceDesignerStep.DesignerAssemblyNamespace}.ResourceConstant"; + + private const string CSharpTemplate = @"// This is an Auto Generated file DO NOT EDIT +using System; + +namespace %NAMESPACE% { + public partial class Resource : %BASECLASS% { + } +} +"; + private const string FSharpTemplate = @"// This is an Auto Generated file DO NOT EDIT +namespace %NAMESPACE% + +type Resource = %BASECLASS% +"; + + public string Namespace { get; set; } + public bool IsApplication { get; set; } = false; + public ITaskItem OutputFile { get; set; } + public override bool RunTask () + { + string ns = IsApplication ? ResourceDesignerConstants : ResourceDesigner; + var extension = Path.GetExtension (OutputFile.ItemSpec); + var language = string.Compare (extension, ".fs", StringComparison.OrdinalIgnoreCase) == 0 ? "F#" : CodeDomProvider.GetLanguageFromExtension (extension); + //bool isVB = string.Equals (extension, ".vb", StringComparison.OrdinalIgnoreCase); + bool isFSharp = string.Equals (language, "F#", StringComparison.OrdinalIgnoreCase); + bool isCSharp = string.Equals (language, "C#", StringComparison.OrdinalIgnoreCase); + string template = ""; + if (isCSharp) + template = CSharpTemplate.Replace ("%NAMESPACE%", Namespace).Replace ("%BASECLASS%", ns); + else if (isFSharp) + template = FSharpTemplate.Replace ("%NAMESPACE%", Namespace).Replace ("%BASECLASS%", ns); + + Files.CopyIfStringChanged (template, OutputFile.ItemSpec); + return !Log.HasLoggedErrors; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs new file mode 100644 index 00000000000..a9927347626 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateRtxt.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2022 Microsoft Ltd, Inc. All rights reserved. +using System; +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.Android.Build.Tasks; + +namespace Xamarin.Android.Tasks +{ + public class GenerateRtxt : AndroidTask + { + public override string TaskPrefix => "GR"; + + [Required] + public string RTxtFile { get; set; } + + [Required] + public string ResourceDirectory { get; set; } + public string[] AdditionalResourceDirectories { get; set; } + + [Required] + public string JavaPlatformJarPath { get; set; } + + public string ResourceFlagFile { get; set; } + public string CaseMapFile { get; set; } + + public override bool RunTask () + { + // Parse the Resource files and then generate an R.txt file + var writer = new RtxtWriter (); + + var resource_fixup = MonoAndroidHelper.LoadMapFile (BuildEngine4, CaseMapFile, StringComparer.OrdinalIgnoreCase); + + var javaPlatformDirectory = Path.GetDirectoryName (JavaPlatformJarPath); + var parser = new FileResourceParser () { Log = Log, JavaPlatformDirectory = javaPlatformDirectory, ResourceFlagFile = ResourceFlagFile}; + var resources = parser.Parse (ResourceDirectory, AdditionalResourceDirectories, resource_fixup); + + // only update if it changed. + writer.Write (RTxtFile, resources); + + return !Log.HasLoggedErrors; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssemblies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssemblies.cs index 55c7bf7d804..67c72c382da 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssemblies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssemblies.cs @@ -58,6 +58,8 @@ public class LinkAssemblies : AndroidTask, ML.ILogger public bool LinkResources { get; set; } + public bool UseDesignerAssembly { get; set; } + IEnumerable GetRetainAssemblies (DirectoryAssemblyResolver res) { List retainList = null; @@ -109,6 +111,7 @@ bool Execute (DirectoryAssemblyResolver res) options.PreserveJniMarshalMethods = PreserveJniMarshalMethods; options.DeterministicOutput = Deterministic; options.LinkResources = LinkResources; + options.UseDesignerAssembly = UseDesignerAssembly; var skiplist = new List (); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs index 25da6cbde08..5d4c65c8509 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs @@ -38,6 +38,8 @@ public class LinkAssembliesNoShrink : AndroidTask public bool AddKeepAlives { get; set; } + public bool UseDesignerAssembly { get; set; } + public bool Deterministic { get; set; } public override bool RunTask () @@ -64,6 +66,9 @@ public override bool RunTask () var cache = new TypeDefinitionCache (); var fixAbstractMethodsStep = new FixAbstractMethodsStep (resolver, cache, Log); var addKeepAliveStep = new AddKeepAlivesStep (resolver, cache, Log, UsingAndroidNETSdk); + var fixLegacyResourceDesignerStep = new FixLegacyResourceDesignerStep (resolver, cache, Log); + if (UseDesignerAssembly) + fixLegacyResourceDesignerStep.Load (); for (int i = 0; i < SourceFiles.Length; i++) { var source = SourceFiles [i]; var destination = DestinationFiles [i]; @@ -91,8 +96,12 @@ public override bool RunTask () if (assemblyDefinition == null) assemblyDefinition = resolver.GetAssembly (source.ItemSpec); - if (fixAbstractMethodsStep.FixAbstractMethods (assemblyDefinition) || - (AddKeepAlives && addKeepAliveStep.AddKeepAlives (assemblyDefinition))) { + bool save = fixAbstractMethodsStep.FixAbstractMethods (assemblyDefinition); + if (UseDesignerAssembly) + save |= fixLegacyResourceDesignerStep.ProcessAssemblyDesigner (assemblyDefinition); + if (AddKeepAlives) + save |= addKeepAliveStep.AddKeepAlives (assemblyDefinition); + if (save) { Log.LogDebugMessage ($"Saving modified assembly: {destination.ItemSpec}"); writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols; assemblyDefinition.Write (destination.ItemSpec, writerParameters); @@ -119,6 +128,33 @@ void CopyIfChanged (ITaskItem source, ITaskItem destination) } } + class FixLegacyResourceDesignerStep : MonoDroid.Tuner.FixLegacyResourceDesignerStep + { + readonly DirectoryAssemblyResolver resolver; + readonly TaskLoggingHelper logger; + + public FixLegacyResourceDesignerStep (DirectoryAssemblyResolver resolver, TypeDefinitionCache cache, TaskLoggingHelper logger) + : base (cache) + { + this.resolver = resolver; + this.logger = logger; + } + + public void Load () { + LoadDesigner (); + } + + public override void LogMessage (string message) + { + logger.LogDebugMessage ("{0}", message); + } + + public override AssemblyDefinition Resolve (AssemblyNameReference name) + { + return resolver.Resolve (name); + } + } + class FixAbstractMethodsStep : MonoDroid.Tuner.FixAbstractMethodsStep { readonly DirectoryAssemblyResolver resolver; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs index f675f9f1bc9..f55838abac1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs @@ -352,6 +352,7 @@ void Extract ( string importsDir = Path.Combine (outDirForDll, ImportsDirectory); string resDir = Path.Combine (importsDir, "res"); string resDirArchive = Path.Combine (resDir, "..", "res.zip"); + string rTxt = Path.Combine (importsDir, "R.txt"); string assetsDir = Path.Combine (importsDir, "assets"); string proguardFile = Path.Combine (importsDir, "proguard.txt"); @@ -367,7 +368,7 @@ void Extract ( AddJar (jars, Path.GetFullPath (file)); } } - if (Directory.Exists (resDir)) { + if (Directory.Exists (resDir) || File.Exists (rTxt)) { var skipProcessing = aarFile.GetMetadata (AndroidSkipResourceProcessing); if (string.IsNullOrEmpty (skipProcessing)) { skipProcessing = "True"; @@ -424,8 +425,9 @@ void Extract ( Log.LogErrorFromException (new PathTooLongException ($"Error extracting resources from \"{aarFile.ItemSpec}\"", ex)); } } - if (Directory.Exists (resDir)) { - CreateResourceArchive (resDir, resDirArchive); + if (Directory.Exists (resDir) || File.Exists (rTxt)) { + if (Directory.Exists (resDir)) + CreateResourceArchive (resDir, resDirArchive); var skipProcessing = aarFile.GetMetadata (AndroidSkipResourceProcessing); if (string.IsNullOrEmpty (skipProcessing)) { skipProcessing = "True"; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index 6858b962cae..00add1baf48 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -18,8 +18,11 @@ namespace Xamarin.Android.Build.Tests public class AndroidUpdateResourcesTest : BaseTest { [Test] - public void CheckMultipleLibraryProjectReferenceAlias ([Values (true, false)] bool withGlobal) + public void CheckMultipleLibraryProjectReferenceAlias ([Values (true, false)] bool withGlobal, [Values (true, false)] bool useDesignerAssembly) { + if (useDesignerAssembly && !Builder.UseDotNet) { + Assert.Ignore ($"Skipping, {useDesignerAssembly} not supported in Legacy."); + } var path = Path.Combine (Root, "temp", TestName); var library1 = new XamarinAndroidLibraryProject () { ProjectName = "Library1", @@ -38,6 +41,9 @@ public void CheckMultipleLibraryProjectReferenceAlias ([Values (true, false)] bo }, }, }; + library1.SetProperty ("AndroidUseDesignerAssembly", "false"); + library2.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); + proj.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); using (var builder1 = CreateDllBuilder (Path.Combine (path, library1.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false)) { builder1.ThrowOnBuildFailure = false; Assert.IsTrue (builder1.Build (library1), "Library should have built."); @@ -47,10 +53,12 @@ public void CheckMultipleLibraryProjectReferenceAlias ([Values (true, false)] bo using (var b = CreateApkBuilder (Path.Combine (path, proj.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false)) { b.ThrowOnBuildFailure = false; Assert.IsTrue (b.Build (proj), "Project should have built."); - string resource_designer_cs = GetResourceDesignerPath (b, proj); - string [] text = File.ReadAllLines (resource_designer_cs); - Assert.IsTrue (text.Count (x => x.Contains ("Library1.Resource.String.library_name")) == 2, "library_name resource should be present exactly once for each library"); - Assert.IsTrue (text.Count (x => x == "extern alias Lib1A;" || x == "extern alias Lib1B;") <= 1, "No more than one extern alias should be present for each library."); + if (!useDesignerAssembly) { + string resource_designer_cs = GetResourceDesignerPath (b, proj); + string [] text = GetResourceDesignerLines (proj, resource_designer_cs); + Assert.IsTrue (text.Count (x => x.Contains ("Library1.Resource.String.library_name")) == 2, "library_name resource should be present exactly once for each library"); + Assert.IsTrue (text.Count (x => x == "extern alias Lib1A;" || x == "extern alias Lib1B;") <= 1, "No more than one extern alias should be present for each library."); + } } } } @@ -92,6 +100,7 @@ public void DesignTimeBuild ([Values(false, true)] bool isRelease, [Values (fals IsRelease = isRelease, }; lib.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", useManagedParser.ToString ()); + lib.SetProperty ("AndroidUseDesignerAssembly", "false"); lib.AndroidUseAapt2 = useAapt2; var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, @@ -101,6 +110,7 @@ public void DesignTimeBuild ([Values(false, true)] bool isRelease, [Values (fals }; var intermediateOutputPath = Path.Combine (path, proj.ProjectName, proj.IntermediateOutputPath); proj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", useManagedParser.ToString ()); + proj.SetProperty ("AndroidUseDesignerAssembly", "false"); proj.AndroidUseAapt2 = useAapt2; using (var l = CreateDllBuilder (Path.Combine (path, lib.ProjectName), false, false)) { using (var b = CreateApkBuilder (Path.Combine (path, proj.ProjectName), false, false)) { @@ -528,13 +538,20 @@ public void CheckResourceDesignerIsCreated (bool isRelease, ProjectLanguage lang using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); // Intermediate designer file support is not compatible with F# projects using Xamarin.Android.FSharp.ResourceProvider. - var outputFile = isFSharp ? Path.Combine (Root, b.ProjectDirectory, "Resources", "Resource.designer" + proj.Language.DefaultDesignerExtension) - : Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "Resource.designer" + proj.Language.DefaultDesignerExtension); - Assert.IsTrue (File.Exists (outputFile), "Resource.designer{1} should have been created in {0}", - isFSharp ? Path.Combine (Root, b.ProjectDirectory, "Resources") : proj.IntermediateOutputPath, - proj.Language.DefaultDesignerExtension); + string outputFile; + if (Builder.UseDotNet) { + outputFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "__Microsoft.Android.Resource.Designer" + proj.Language.DefaultDesignerExtension); + Assert.IsTrue (File.Exists (outputFile), $"{outputFile} should have been created in {proj.IntermediateOutputPath}"); + } else { + outputFile = isFSharp ? Path.Combine (Root, b.ProjectDirectory, "Resources", "Resource.designer" + proj.Language.DefaultDesignerExtension) + : Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "Resource.designer" + proj.Language.DefaultDesignerExtension); + Assert.IsTrue (File.Exists (outputFile), "Resource.designer{1} should have been created in {0}", + isFSharp ? Path.Combine (Root, b.ProjectDirectory, "Resources") : proj.IntermediateOutputPath, + proj.Language.DefaultDesignerExtension); + } + Assert.IsTrue (b.Clean (proj), "Clean should have succeeded."); - if (!isFSharp) { + if (!isFSharp || Builder.UseDotNet) { Assert.IsFalse (File.Exists (outputFile), "Resource.designer{1} should have been cleaned in {0}", proj.IntermediateOutputPath, proj.Language.DefaultDesignerExtension); } @@ -597,13 +614,12 @@ public void CheckOldResourceDesignerIsNotUsed ([Values (true, false)] bool isRel var fi = new FileInfo (Path.Combine (Root, b.ProjectDirectory, designer)); Assert.IsFalse (fi.Length > new [] { 0xef, 0xbb, 0xbf, 0x0d, 0x0a }.Length, "{0} should not contain anything.", designer); + var designerFile = Builder.UseDotNet ? "__Microsoft.Android.Resource.Designer" : "Resource.designer" ; var outputFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, - "Resource.designer" + proj.Language.DefaultDesignerExtension); - Assert.IsTrue (File.Exists (outputFile), "Resource.designer{1} should have been created in {0}", - proj.IntermediateOutputPath, proj.Language.DefaultDesignerExtension); + designerFile + proj.Language.DefaultDesignerExtension); + Assert.IsTrue (File.Exists (outputFile), $"{designerFile}{proj.Language.DefaultDesignerExtension} should have been created in {proj.IntermediateOutputPath}"); Assert.IsTrue (b.Clean (proj), "Clean should have succeeded."); - Assert.IsFalse (File.Exists (outputFile), "Resource.designer{1} should have been cleaned in {0}", - proj.IntermediateOutputPath, proj.Language.DefaultDesignerExtension); + Assert.IsFalse (File.Exists (outputFile), $"{designerFile}{proj.Language.DefaultDesignerExtension} should have been cleaned in {proj.IntermediateOutputPath}"); } } @@ -625,13 +641,56 @@ public void CheckOldResourceDesignerWithWrongCasingIsRemoved ([Values (true, fal Assert.IsFalse (File.Exists (Path.Combine (Root, b.ProjectDirectory, "Resources", "Resource.designer" + proj.Language.DefaultDesignerExtension)), "{0} should not exists", designer.Include ()); + var designerFile = Builder.UseDotNet ? "__Microsoft.Android.Resource.Designer" : "Resource.designer" ; var outputFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, - "Resource.designer" + proj.Language.DefaultDesignerExtension); - Assert.IsTrue (File.Exists (outputFile), "Resource.designer{1} should have been created in {0}", - proj.IntermediateOutputPath, proj.Language.DefaultDesignerExtension); + designerFile + proj.Language.DefaultDesignerExtension); + Assert.IsTrue (File.Exists (outputFile), $"{designerFile}{proj.Language.DefaultDesignerExtension} should have been created in {proj.IntermediateOutputPath}"); Assert.IsTrue (b.Clean (proj), "Clean should have succeeded."); - Assert.IsFalse (File.Exists (outputFile), "Resource.designer{1} should have been cleaned in {0}", - proj.IntermediateOutputPath, proj.Language.DefaultDesignerExtension); + Assert.IsFalse (File.Exists (outputFile), $"{designerFile}{proj.Language.DefaultDesignerExtension} should have been cleaned in {proj.IntermediateOutputPath}"); + } + } + + [Test] + public void CheckThatXA1031IsRaisedForInvalidConfiguration ([Values (true, false)] bool isRelease) + { + if (!Builder.UseDotNet) + Assert.Ignore ("Test uses designer assembly which does not work on Legacy projects."); + string path = Path.Combine (Root, "temp", TestName); + var foo = new BuildItem.Source ("Foo.cs") { + TextContent = () => @"using System; +namespace Lib1 { + public class Foo { + public static string GetFoo () { + return ""Foo""; + } + } +}" + }; + var library = new XamarinAndroidLibraryProject () { + IsRelease = isRelease, + ProjectName = "Lib1", + Sources = { foo }, + }; + library.SetProperty ("AndroidUseDesignerAssembly", "True"); + + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, + ProjectName = "App1", + References = { + new BuildItem.ProjectReference ($"..\\{library.ProjectName}\\{library.ProjectName}.csproj", library.ProjectName, library.ProjectGuid), + }, + }; + proj.SetProperty ("AndroidUseDesignerAssembly", "False"); + proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "Console.WriteLine (Lib1.Foo.GetFoo ());"); + using (var lb = CreateDllBuilder (Path.Combine (path, library.ProjectName))) { + lb.ThrowOnBuildFailure = false; + Assert.IsTrue (lb.Build (library), "Library project should have built."); + using (var pb = CreateApkBuilder (Path.Combine (path, proj.ProjectName))) { + pb.ThrowOnBuildFailure = false; + Assert.IsFalse (pb.Build (proj), "Application project build should have failed."); + StringAssertEx.ContainsText (pb.LastBuildOutput, "XA1031: "); + StringAssertEx.ContainsText (pb.LastBuildOutput, "1 Error(s)"); + } } } @@ -785,8 +844,10 @@ public void CheckFilesAreRemoved () { } [Test] - public void CheckDontUpdateResourceIfNotNeeded () + public void CheckDontUpdateResourceIfNotNeeded ([Values (true, false)] bool useDesignerAssembly) { + if (!Builder.UseDotNet && useDesignerAssembly) + Assert.Ignore ("Test uses designer assembly which does not work on Legacy projects."); var path = Path.Combine ("temp", TestName); var target = Builder.UseDotNet ? "_CreateAar" : "_CreateManagedLibraryResourceArchive"; var foo = new BuildItem.Source ("Foo.cs") { @@ -824,6 +885,7 @@ public string GetFoo () { }, }; libProj.SetProperty ("Deterministic", "true"); + libProj.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); var appProj = new XamarinAndroidApplicationProject () { IsRelease = true, ProjectName = "App1", @@ -831,6 +893,7 @@ public string GetFoo () { new BuildItem.ProjectReference (@"..\Lib1\Lib1.csproj", libProj.ProjectName, libProj.ProjectGuid), }, }; + appProj.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); using (var libBuilder = CreateDllBuilder (Path.Combine (path, libProj.ProjectName), false, false)) { Assert.IsTrue (libBuilder.Build (libProj), "Library project should have built"); using (var appBuilder = CreateApkBuilder (Path.Combine (path, appProj.ProjectName), false, false)) { @@ -864,7 +927,7 @@ public string GetFoo () { appBuilder.BuildLogFile = "build2.log"; Assert.IsTrue (appBuilder.Build (appProj, doNotCleanupOnUpdate: true, saveProject: false), "Application Build should have succeeded."); string resource_designer_cs = GetResourceDesignerPath (appBuilder, appProj); - string text = File.ReadAllText (resource_designer_cs); + string text = GetResourceDesignerText (appProj, resource_designer_cs); StringAssert.Contains ("theme_devicedefault_background2", text, "Resource.designer.cs was not updated."); appBuilder.Output.AssertTargetIsNotSkipped ("_UpdateAndroidResgen"); appBuilder.Output.AssertTargetIsNotSkipped ("_CreateBaseApk"); @@ -904,6 +967,7 @@ public void BuildAppWithManagedResourceParser() ProjectName = "App1", }; appProj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + appProj.SetProperty ("AndroidUseDesignerAssembly", "false"); using (var appBuilder = CreateApkBuilder (Path.Combine (path, appProj.ProjectName))) { Assert.IsTrue (appBuilder.DesignTimeBuild (appProj), "DesignTime Application Build should have succeeded."); Assert.IsFalse (appProj.CreateBuildOutput (appBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), @@ -961,6 +1025,7 @@ public void BuildAppWithManagedResourceParserAndLibraries () }, }; libProj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + libProj.SetProperty ("AndroidUseDesignerAssembly", "false"); var appProj = new XamarinAndroidApplicationProject () { IsRelease = true, ProjectName = "App1", @@ -978,6 +1043,7 @@ public void BuildAppWithManagedResourceParserAndLibraries () }, }; appProj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + appProj.SetProperty ("AndroidUseDesignerAssembly", "false"); using (var libBuilder = CreateDllBuilder (Path.Combine (path, libProj.ProjectName), false, false)) { libBuilder.AutomaticNuGetRestore = false; Assert.IsTrue (libBuilder.RunTarget (libProj, "Restore"), "Library project should have restored."); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index f9641bff999..6a8ccadba77 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -276,6 +276,13 @@ public void BuildAMassiveApp () AotAssemblies = true, IsRelease = true, }; + if (Builder.UseDotNet) { + app1.PackageReferences.Clear (); + app1.PackageReferences.Add (KnownPackages.XamarinForms_5_0_0_2515); + app1.PackageReferences.Add (KnownPackages.XamarinFormsMaps_5_0_0_2515); + app1.PackageReferences.Add (KnownPackages.Xamarin_Build_Download_0_11_3); + + } //NOTE: BuildingInsideVisualStudio prevents the projects from being built as dependencies sb.BuildingInsideVisualStudio = false; app1.Imports.Add (new Import ("foo.targets") { 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 3e777babfde..e5a7d05a09c 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 @@ -477,8 +477,11 @@ public void CheckItemMetadata ([Values (true, false)] bool isRelease) // Context https://bugzilla.xamarin.com/show_bug.cgi?id=29706 [Test] - public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isRelease) + public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isRelease, [Values (false, true)] bool useDesignerAssembly) { + if (useDesignerAssembly && !Builder.UseDotNet) { + Assert.Ignore ($"Skipping, {useDesignerAssembly} not supported in Legacy."); + } var illegalSeperator = IsWindows ? "/" : @"\"; var dll = new XamarinAndroidLibraryProject () { ProjectName = "Library1", @@ -503,20 +506,18 @@ public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isReleas new BuildItem ("ProjectReference","..\\Library1\\Library1.csproj"), }, }; + if (!useDesignerAssembly) + dll.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); + proj.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); var path = Path.Combine ("temp", TestName); using (var b = CreateDllBuilder (Path.Combine (path, dll.ProjectName))) { Assert.IsTrue (b.Build (dll), "Build should have succeeded."); using (var builder = CreateApkBuilder (Path.Combine (path, proj.ProjectName), isRelease)) { Assert.IsTrue (builder.Build (proj), "Build should have succeeded"); - string resource_designer_cs; - if (Builder.UseDotNet) { - resource_designer_cs = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "Resource.designer.cs"); - } else { - resource_designer_cs = Path.Combine (Root, builder.ProjectDirectory, "Resources", "Resource.designer.cs"); - } - var contents = File.ReadAllText (resource_designer_cs); - StringAssert.Contains ("public const int foo = ", contents); - StringAssert.Contains ("public const int foo2 = ", contents); + string resource_designer_cs = GetResourceDesignerPath (builder, proj); + var contents = GetResourceDesignerText (proj, resource_designer_cs); + StringAssert.Contains ("public const int foo =", contents); + StringAssert.Contains ("public const int foo2 =", contents); } } } @@ -2020,8 +2021,11 @@ public void LibraryReferenceWithHigherTFVShouldDisplayWarning ([Values (true, fa } [Test] - public void AllResourcesInClassLibrary ([Values (true, false)] bool useAapt2) + public void AllResourcesInClassLibrary ([Values (true, false)] bool useAapt2, [Values (false, true)] bool useDesignerAssembly) { + if (useDesignerAssembly && !Builder.UseDotNet) { + Assert.Ignore ($"Skipping, {useDesignerAssembly} not supported in Legacy."); + } AssertAaptSupported (useAapt2); var path = Path.Combine ("temp", TestName); @@ -2035,6 +2039,7 @@ public void AllResourcesInClassLibrary ([Values (true, false)] bool useAapt2) } }; lib.SetProperty ("AndroidApplication", "False"); + lib.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); lib.AndroidUseAapt2 = useAapt2; if (Builder.UseDotNet) { lib.RemoveProperty ("OutputType"); @@ -2054,6 +2059,7 @@ public void AllResourcesInClassLibrary ([Values (true, false)] bool useAapt2) }, } }; + app.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); app.AndroidResources.Clear (); // No Resources if (Builder.UseDotNet) { app.SetProperty (KnownProperties.OutputType, "Exe"); @@ -2075,7 +2081,7 @@ public void AllResourcesInClassLibrary ([Values (true, false)] bool useAapt2) var resource_designer_cs = GetResourceDesignerPath (appBuilder, app); FileAssert.Exists (resource_designer_cs); - var contents = File.ReadAllText (resource_designer_cs); + var contents = GetResourceDesignerText (app, resource_designer_cs); Assert.AreNotEqual ("", contents); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/DesignerTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/DesignerTests.cs index 925e80472c4..63c6603fed7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/DesignerTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/DesignerTests.cs @@ -93,10 +93,14 @@ public CustomTextView(Context context, IAttributeSet attributes) : base(context, " }); + lib.SetProperty ("AndroidUseDesignerAssembly", "False"); + proj.SetProperty ("AndroidUseDesignerAssembly", "False"); + using (var libb = CreateDllBuilder (Path.Combine (path, lib.ProjectName), false, false)) using (var appb = CreateApkBuilder (Path.Combine (path, proj.ProjectName), false, false)) { // Save the library project, but don't build it yet libb.Save (lib); + appb.BuildLogFile = "build1.log"; appb.Target = target; Assert.IsTrue (appb.Build (proj, parameters: DesignerParameters), $"build should have succeeded for target `{target}`"); Assert.IsTrue (appb.Output.AreTargetsAllBuilt ("_UpdateAndroidResgen"), "_UpdateAndroidResgen should have run completely."); @@ -111,6 +115,7 @@ public CustomTextView(Context context, IAttributeSet attributes) : base(context, // Build the library project now Assert.IsTrue (libb.Build (lib, doNotCleanupOnUpdate: true), "library build should have succeeded."); appb.Target = "Build"; + appb.BuildLogFile = "build2.log"; Assert.IsTrue (appb.Build (proj, doNotCleanupOnUpdate: true), "app build should have succeeded."); Assert.IsTrue (appb.Output.AreTargetsAllBuilt ("_UpdateAndroidResgen"), "_UpdateAndroidResgen should have run completely."); Assert.IsTrue (appb.Output.AreTargetsAllBuilt ("_Foo"), "_Foo should have run completely"); @@ -120,6 +125,7 @@ public CustomTextView(Context context, IAttributeSet attributes) : base(context, Assert.IsNull (doc.Element ("LinearLayout").Element ("unnamedproject.CustomTextView"), "unnamedproject.CustomTextView should have been replaced with a $(Hash).CustomTextView"); appb.Target = target; + appb.BuildLogFile = "build3.log"; Assert.IsTrue (appb.Build (proj, parameters: DesignerParameters, doNotCleanupOnUpdate: true), $"build should have succeeded for target `{target}`"); Assert.IsTrue (appb.Output.AreTargetsAllSkipped ("_UpdateAndroidResgen"), "_UpdateAndroidResgen should have been skipped."); Assert.IsTrue (appb.Output.AreTargetsAllBuilt ("_Foo"), "_Foo should have run completely"); 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 3aa68042cdd..24fe06606b7 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 @@ -156,6 +156,7 @@ public void IncrementalCleanDuringClean () IsRelease = true, }; proj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + proj.SetProperty ("AndroidUseDesignerAssembly", "False"); using (var b = CreateApkBuilder (path)) { b.Target = "Compile"; Assert.IsTrue(b.Build (proj), "DesignTime Build should have succeeded"); @@ -830,6 +831,7 @@ public void ResolveLibraryProjectImports ([Values (true, false)] bool useAapt2) FileAssert.Exists (stamp); File.Delete (stamp); + b.BuildLogFile = "build2.log"; Assert.IsTrue (b.Build (proj), "second build should have succeeded."); var actual = ReadCache (cacheFile); CollectionAssert.AreEqual (actual.Jars.Select (j => j.ItemSpec), @@ -843,6 +845,7 @@ public void ResolveLibraryProjectImports ([Values (true, false)] bool useAapt2) }; proj.OtherBuildItems.Add (aar); + b.BuildLogFile = "build3.log"; Assert.IsTrue (b.Build (proj), "third build should have succeeded."); actual = ReadCache (cacheFile); Assert.AreEqual (expected.Jars.Length + 1, actual.Jars.Length, @@ -856,6 +859,7 @@ public void ResolveLibraryProjectImports ([Values (true, false)] bool useAapt2) } // Build with no changes, checking we are skipping targets appropriately + b.BuildLogFile = "build4.log"; Assert.IsTrue (b.Build (proj), "fourth build should have succeeded."); var targets = new List { "_UpdateAndroidResgen", @@ -1274,6 +1278,7 @@ public void AndroidResourceChange () // AndroidResource change proj.LayoutMain += $"{Environment.NewLine}"; proj.Touch ("Resources\\layout\\Main.axml"); + builder.BuildLogFile = "build2.log"; Assert.IsTrue (builder.Build (proj), "second build should succeed"); builder.Output.AssertTargetIsSkipped ("_ResolveLibraryProjectImports"); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index 3601da8a073..f69eeb8b5c1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -95,6 +95,7 @@ public void CheckIncludedAssemblies ([Values (false, true)] bool usesAssemblySto "System.Runtime.InteropServices.dll", "System.Linq.dll", "UnnamedProject.dll", + "_Microsoft.Android.Resource.Designer.dll", } : new [] { "Java.Interop.dll", diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GenerateResourceCaseMapTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GenerateResourceCaseMapTests.cs new file mode 100644 index 00000000000..8cfd159b009 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GenerateResourceCaseMapTests.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Build.Utilities; +using NUnit.Framework; +using Xamarin.Android.Tasks; +using Xamarin.ProjectTools; + +namespace Xamarin.Android.Build.Tests { + [TestFixture] + [Category ("Node-5")] + [Parallelizable (ParallelScope.Children)] + public class GenerateResourceCaseMapTests : BaseTest { + + public void CreateResourceDirectory (string path) + { + Directory.CreateDirectory (Path.Combine (Root, path)); + Directory.CreateDirectory (Path.Combine (Root, path, "res", "drawable")); + Directory.CreateDirectory (Path.Combine (Root, path, "res", "values")); + using (var stream = typeof (XamarinAndroidCommonProject).Assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Base.Icon.png")) { + var icon_binary_mdpi = new byte [stream.Length]; + stream.Read (icon_binary_mdpi, 0, (int)stream.Length); + File.WriteAllBytes (Path.Combine (Root, path, "res", "drawable", "IMALLCAPS.png"), icon_binary_mdpi); + } + } + + [Test] + public void CaseMapAllCapsWorks () + { + var path = Path.Combine ("temp", TestName + " Some Space"); + CreateResourceDirectory (path); + var task = new GenerateResourceCaseMap () { + BuildEngine = new MockBuildEngine (TestContext.Out) + }; + task.ProjectDir = Path.Combine (Root, path); + task.ResourceDirectory = Path.Combine (Root, path, "res") + Path.DirectorySeparatorChar; + task.Resources = new TaskItem [] { + new TaskItem (Path.Combine (Root, path, "res", "values", "strings.xml"), new Dictionary () { + { "LogicalName", "values\\strings.xml" }, + }), + new TaskItem (Path.Combine (Root, path, "res", "drawable", "IMALLCAPS.png")), + }; + task.OutputFile = new TaskItem (Path.Combine (Root, path, "case_map.txt")); + + Assert.IsTrue (task.Execute (), "Task should have run successfully."); + FileAssert.Exists (task.OutputFile.ItemSpec, $"'{task.OutputFile}' should have been created."); + var content1 = File.ReadAllText (task.OutputFile.ItemSpec); + StringAssert.Contains ($"drawable{Path.DirectorySeparatorChar}IMALLCAPS;IMALLCAPS", content1, "File should contain 'IMALLCAPS'"); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/ManagedResourceParserTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/ManagedResourceParserTests.cs index 55737bd0610..7a6f89c90b2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/ManagedResourceParserTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/ManagedResourceParserTests.cs @@ -230,7 +230,7 @@ int string app_name 0x7f110000 int string foo 0x7f110002 int string hello 0x7f110003 int string menu_settings 0x7f110004 -int[] styleable CustomFonts { 0x10100D2, 0x7F040000, 0x7F040000, 0x7F040001 } +int[] styleable CustomFonts { 0x010100d2, 0x7f040000, 0x7f040000, 0x7f040001 } int styleable CustomFonts_android_scrollX 0 int styleable CustomFonts_customFont 1 int styleable CustomFonts_customFont 2 @@ -309,6 +309,7 @@ void BuildLibraryWithResources (string path) var libraryStrings = library.AndroidResources.FirstOrDefault (r => r.Include () == @"Resources\values\Strings.xml"); + library.SetProperty ("AndroidUseDesignerAssembly", "false"); library.AndroidResources.Clear (); library.AndroidResources.Add (libraryStrings); library.AndroidResources.Add (new AndroidItem.AndroidResource (Path.Combine ("Resources", "animator", "slide_in_bottom.xml")) { TextContent = () => Animator }); @@ -355,6 +356,25 @@ void CompareFilesIgnoreRuntimeInfoString (string file1, string file2) } } + GenerateResourceCaseMap CreateCaseMapTask (string path) + { + var task = new GenerateResourceCaseMap () { + BuildEngine = new MockBuildEngine (TestContext.Out) + }; + task.ProjectDir = Path.Combine (Root, path); + task.ResourceDirectory = Path.Combine (Root, path, "res") + Path.DirectorySeparatorChar; + task.Resources = new TaskItem [] { + new TaskItem (Path.Combine (Root, path, "res", "values", "strings.xml"), new Dictionary () { + { "LogicalName", "values\\strings.xml" }, + }), + }; + task.AdditionalResourceDirectories = new TaskItem [] { + new TaskItem (Path.Combine (Root, path, "lp", "res")), + }; + task.OutputFile = new TaskItem (Path.Combine (Root, path, "case_map.txt")); + return task; + } + GenerateResourceDesigner CreateTask (string path) { var task = new GenerateResourceDesigner { @@ -375,6 +395,7 @@ GenerateResourceDesigner CreateTask (string path) task.AdditionalResourceDirectories = new TaskItem [] { new TaskItem (Path.Combine (Root, path, "lp", "res")), }; + task.CaseMapFile = Path.Combine (Root, path, "case_map.txt"); task.IsApplication = true; task.JavaPlatformJarPath = Path.Combine (AndroidSdkDirectory, "platforms", "android-27", "android.jar"); return task; @@ -400,6 +421,8 @@ public void GenerateDesignerFileWithÜmläüts () { var path = Path.Combine ("temp", TestName + " Some Space"); CreateResourceDirectory (path); + var mapTask = CreateCaseMapTask (path); + Assert.IsTrue (mapTask.Execute (), "Map Task should have executed successfully."); var task = CreateTask (path); Assert.IsTrue (task.Execute (), "Task should have executed successfully."); AssertResourceDesigner (task, "GenerateDesignerFileExpected.cs"); @@ -411,6 +434,8 @@ public void GenerateDesignerFileFromRtxt ([Values (false, true)] bool withLibrar { var path = Path.Combine ("temp", TestName + " Some Space"); CreateResourceDirectory (path); + var mapTask = CreateCaseMapTask (path); + Assert.IsTrue (mapTask.Execute (), "Map Task should have executed successfully."); var task = CreateTask (path); task.RTxtFile = Path.Combine (Root, path, "R.txt"); File.WriteAllText (task.RTxtFile, Rtxt); @@ -444,6 +469,8 @@ public void UpdateLayoutIdIsIncludedInDesigner ([Values(true, false)] bool useRt { var path = Path.Combine ("temp", TestName + " Some Space"); CreateResourceDirectory (path); + var mapTask = CreateCaseMapTask (path); + Assert.IsTrue (mapTask.Execute (), "Map Task should have executed successfully."); if (useRtxt) File.WriteAllText (Path.Combine (Root, path, "R.txt"), Rtxt); IBuildEngine engine = new MockBuildEngine (TestContext.Out); @@ -465,6 +492,7 @@ public void UpdateLayoutIdIsIncludedInDesigner ([Values(true, false)] bool useRt new TaskItem (Path.Combine (Root, path, "lp", "res")), }; task.ResourceFlagFile = Path.Combine (Root, path, "AndroidResgen.flag"); + task.CaseMapFile = Path.Combine (Root, path, "case_map.txt"); File.WriteAllText (task.ResourceFlagFile, string.Empty); task.IsApplication = true; task.JavaPlatformJarPath = Path.Combine (AndroidSdkDirectory, "platforms", "android-27", "android.jar"); @@ -484,6 +512,38 @@ public void UpdateLayoutIdIsIncludedInDesigner ([Values(true, false)] bool useRt Directory.Delete (Path.Combine (Root, path), recursive: true); } + [Test] + [Category ("SmokeTests")] + public void RtxtGeneratorOutput () + { + var path = Path.Combine ("temp", TestName); + int platform = AndroidSdkResolver.GetMaxInstalledPlatform (); + string resPath = Path.Combine (Root, path, "res"); + string rTxt = Path.Combine (Root, path, "R.txt"); + string expectedrTxt = Path.Combine (Root, path, "expectedR.txt"); + CreateResourceDirectory (path); + File.WriteAllText (expectedrTxt, Rtxt); + List errors = new List (); + List messages = new List (); + IBuildEngine engine = new MockBuildEngine (TestContext.Out, errors: errors, messages: messages); + var generateRtxt = new GenerateRtxt () { + BuildEngine = engine, + RTxtFile = rTxt, + ResourceDirectory = resPath, + JavaPlatformJarPath = Path.Combine (AndroidSdkDirectory, "platforms", $"android-{platform}", "android.jar"), + ResourceFlagFile = Path.Combine (Root, path, "res.flag"), + AdditionalResourceDirectories = new string[] { + Path.Combine (Root, path, "lp", "res"), + }, + }; + Assert.IsTrue (generateRtxt.Execute (), "Task should have succeeded."); + FileAssert.Exists (rTxt, $"{rTxt} should have been created."); + + CompareFilesIgnoreRuntimeInfoString (rTxt, expectedrTxt); + + Directory.Delete (Path.Combine (Root, path), recursive: true); + } + [Test] [Category ("SmokeTests")] public void CompareAapt2AndManagedParserOutput () diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs index d773e523ceb..a8f678a4d9a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs @@ -12,6 +12,8 @@ using Xamarin.ProjectTools; using Microsoft.Android.Build.Tasks; using System.Runtime.CompilerServices; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.CSharp; namespace Xamarin.Android.Build.Tests { @@ -556,12 +558,37 @@ protected string GetResourceDesignerPath (ProjectBuilder builder, XamarinAndroid string path; if (Builder.UseDotNet) { path = Path.Combine (Root, builder.ProjectDirectory, project.IntermediateOutputPath); + if (string.Compare (project.GetProperty ("AndroidUseDesignerAssembly"), "True", ignoreCase: true) == 0) { + return Path.Combine (path, "_Microsoft.Android.Resource.Designer.dll"); + } } else { path = Path.Combine (Root, builder.ProjectDirectory, "Resources"); } return Path.Combine (path, "Resource.designer" + project.Language.DefaultDesignerExtension); } + protected string GetResourceDesignerText (XamarinAndroidProject project, string path) + { + if (Builder.UseDotNet) { + if (string.Compare (project.GetProperty ("AndroidUseDesignerAssembly"), "True", ignoreCase: true) == 0) { + var decompiler = new CSharpDecompiler (path, new DecompilerSettings () { }); + return decompiler.DecompileWholeModuleAsString (); + } + } + return File.ReadAllText (path); + } + + protected string[] GetResourceDesignerLines (XamarinAndroidProject project, string path) + { + if (Builder.UseDotNet) { + if (string.Compare (project.GetProperty ("AndroidUseDesignerAssembly"), "True", ignoreCase: true) == 0) { + var decompiler = new CSharpDecompiler (path, new DecompilerSettings () { }); + return decompiler.DecompileWholeModuleAsString ().Split (Environment.NewLine[0]); + } + } + return File.ReadAllLines (path); + } + /// /// Asserts that a AndroidManifest.xml file contains the expected //application/@android:extractNativeLibs value. /// diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs index 81f094ee126..462dcc7228b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs @@ -28,23 +28,41 @@ public class XASdkTests : BaseTest static readonly object [] DotNetBuildLibrarySource = new object [] { new object [] { - /* isRelease */ false, - /* duplicateAar */ false, + /* isRelease */ false, + /* duplicateAar */ false, + /* useDesignerAssembly */ false, }, new object [] { - /* isRelease */ false, - /* duplicateAar */ true, + /* isRelease */ false, + /* duplicateAar */ true, + /* useDesignerAssembly */ false, }, new object [] { - /* isRelease */ true, - /* duplicateAar */ false, + /* isRelease */ true, + /* duplicateAar */ false, + /* useDesignerAssembly */ false, + }, + new object [] { + /* isRelease */ false, + /* duplicateAar */ false, + /* useDesignerAssembly */ true, + }, + new object [] { + /* isRelease */ false, + /* duplicateAar */ true, + /* useDesignerAssembly */ true, + }, + new object [] { + /* isRelease */ true, + /* duplicateAar */ false, + /* useDesignerAssembly */ true, }, }; [Test] [Category ("SmokeTests")] [TestCaseSource (nameof (DotNetBuildLibrarySource))] - public void DotNetBuildLibrary (bool isRelease, bool duplicateAar) + public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesignerAssembly) { var path = Path.Combine ("temp", TestName); var env_var = "MY_ENVIRONMENT_VAR"; @@ -70,6 +88,7 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar) libC.OtherBuildItems.Add (new AndroidItem.AndroidAsset ("Assets\\bar\\bar.txt") { BinaryContent = () => Array.Empty (), }); + libC.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); var activity = libC.Sources.FirstOrDefault (s => s.Include () == "MainActivity.cs"); if (activity != null) libC.Sources.Remove (activity); @@ -141,6 +160,7 @@ public Foo () BinaryContent = () => Array.Empty (), }); libB.AddReference (libC); + libB.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); activity = libB.Sources.FirstOrDefault (s => s.Include () == "MainActivity.cs"); if (activity != null) @@ -190,6 +210,7 @@ public Foo () // Test a duplicate @(AndroidLibrary) item with the same path of LibraryB.aar appA.OtherBuildItems.Add (new AndroidItem.AndroidLibrary (aarPath)); } + appA.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); var appBuilder = CreateDotNetBuilder (appA, Path.Combine (path, appA.ProjectName)); Assert.IsTrue (appBuilder.Build (), $"{appA.ProjectName} should succeed"); @@ -223,11 +244,13 @@ public Foo () Assert.AreEqual (env_val, actual, $"{env_var} should be {env_val}"); // Check Resource.designer.cs - var resource_designer_cs = Path.Combine (intermediate, "Resource.designer.cs"); - FileAssert.Exists (resource_designer_cs); - var resource_designer_text = File.ReadAllText (resource_designer_cs); - StringAssert.Contains ("public const int MyLayout", resource_designer_text); - StringAssert.Contains ("global::LibraryB.Resource.Drawable.IMALLCAPS = global::AppA.Resource.Drawable.IMALLCAPS", resource_designer_text); + if (!useDesignerAssembly) { + var resource_designer_cs = Path.Combine (intermediate, "Resource.designer.cs"); + FileAssert.Exists (resource_designer_cs); + var resource_designer_text = File.ReadAllText (resource_designer_cs); + StringAssert.Contains ("public const int MyLayout", resource_designer_text); + StringAssert.Contains ("global::LibraryB.Resource.Drawable.IMALLCAPS = global::AppA.Resource.Drawable.IMALLCAPS", resource_designer_text); + } } [Test] @@ -443,6 +466,7 @@ public void GenerateResourceDesigner_false() }; // Turn off Resource.designer.cs and remove usage of it proj.SetProperty ("AndroidGenerateResourceDesigner", "false"); + proj.SetProperty ("AndroidUseDesignerAssembly", "false"); proj.MainActivity = proj.DefaultMainActivity .Replace ("Resource.Layout.Main", "0") .Replace ("Resource.Id.myButton", "0"); @@ -1037,16 +1061,18 @@ public void DotNetIncremental ([Values (true, false)] bool isRelease, [Values (" }; appA.AddReference (libB); var appBuilder = CreateDotNetBuilder (appA, Path.Combine (path, appA.ProjectName)); + appBuilder.BuildLogFile = Path.Combine (Root, path, appA.ProjectName, "build1.log"); Assert.IsTrue (appBuilder.Build (runtimeIdentifier: runtimeIdentifier), $"{appA.ProjectName} should succeed"); - appBuilder.AssertTargetIsNotSkipped ("CoreCompile"); + appBuilder.AssertTargetIsNotSkipped ("CoreCompile", occurrence: 1); if (isRelease) { appBuilder.AssertTargetIsNotSkipped ("_RemoveRegisterAttribute"); appBuilder.AssertTargetIsNotSkipped ("_AndroidAot"); } // Build again, no changes + appBuilder.BuildLogFile = Path.Combine (Root, path, appA.ProjectName, "build2.log"); Assert.IsTrue (appBuilder.Build (runtimeIdentifier: runtimeIdentifier), $"{appA.ProjectName} should succeed"); - appBuilder.AssertTargetIsSkipped ("CoreCompile"); + appBuilder.AssertTargetIsSkipped ("CoreCompile", occurrence: 2); if (isRelease) { appBuilder.AssertTargetIsSkipped ("_RemoveRegisterAttribute"); appBuilder.AssertTargetIsSkipped ("_AndroidAotCompilation"); @@ -1114,6 +1140,34 @@ public Foo () { helper.AssertContainsEntry ($"assemblies/{libC.ProjectName}.dll"); } + [Test] + public void DotNetDesignTimeBuild () + { + var proj = new XASdkProject (); + proj.SetProperty ("AndroidUseDesignerAssembly", "true"); + var builder = CreateDotNetBuilder (proj); + var parameters = new [] { "BuildingInsideVisualStudio=true"}; + builder.BuildLogFile = "update.log"; + Assert.IsTrue (builder.Build ("Compile", parameters: parameters), $"{proj.ProjectName} should succeed"); + builder.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 1); + builder.AssertTargetIsNotSkipped ("_GenerateRtxt"); + builder.AssertTargetIsNotSkipped ("_GenerateResourceDesignerIntermediateClass"); + builder.AssertTargetIsNotSkipped ("_GenerateResourceDesignerAssembly", occurrence: 1); + parameters = new [] { "BuildingInsideVisualStudio=true" }; + builder.BuildLogFile = "build1.log"; + Assert.IsTrue (builder.Build ("SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed"); + builder.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 2); + builder.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 1); + builder.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 1); + builder.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly", occurrence: 2); + builder.BuildLogFile = "build2.log"; + Assert.IsTrue (builder.Build ("SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed 2"); + builder.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 3); + builder.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 2); + builder.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 2); + builder.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly"); + } + [Test] public void SignAndroidPackage () { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj index be74e205c2d..8fab24d3966 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj @@ -59,6 +59,7 @@ + diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs index 3cac7b400be..6fb9b090e2e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs @@ -203,11 +203,21 @@ public static class KnownPackages Version = "4.7.0.1142", TargetFramework = "MonoAndroid10.0", }; + public static Package XamarinForms_5_0_0_2515 = new Package { + Id = "Xamarin.Forms", + Version = "5.0.0.2515", + TargetFramework = "MonoAndroid10.0", + }; public static Package XamarinFormsMaps_4_7_0_1142 = new Package { Id = "Xamarin.Forms.Maps", Version = "4.7.0.1142", TargetFramework = "MonoAndroid10.0", }; + public static Package XamarinFormsMaps_5_0_0_2515 = new Package { + Id = "Xamarin.Forms.Maps", + Version = "5.0.0.2515", + TargetFramework = "MonoAndroid10.0", + }; public static Package XamarinFormsMaps_4_0_0_425677 = new Package { Id = "Xamarin.Forms.Maps", Version = "4.0.0.425677", @@ -474,6 +484,11 @@ public static class KnownPackages Id = "Xamarin.Build.Download", Version = "0.11.2", }; + + public static Package Xamarin_Build_Download_0_11_3 = new Package { + Id = "Xamarin.Build.Download", + Version = "0.11.3", + }; // NOTE: old version required for some tests public static Package Xamarin_Build_Download_0_4_11 = new Package { Id = "Xamarin.Build.Download", diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs index cb964c0963b..51a4772a395 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs @@ -54,8 +54,12 @@ protected XamarinAndroidCommonProject (string debugConfigurationName = "Debug", AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\drawable-xxhdpi\\Icon.png") { BinaryContent = () => icon_binary_xxhdpi }); AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\drawable-xxxhdpi\\Icon.png") { BinaryContent = () => icon_binary_xxxhdpi }); //AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\drawable-nodpi\\Icon.png") { BinaryContent = () => icon_binary }); + if (Builder.UseDotNet) { + // set our default + SetProperty ("AndroidUseDesignerAssembly", "True"); + } } - + public override string ProjectTypeGuid { get { return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProjectLanguage.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProjectLanguage.cs index 7c77da35bbc..4365ce6bab1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProjectLanguage.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProjectLanguage.cs @@ -34,7 +34,7 @@ public override string DefaultExtension { get { return ".fs"; } } public override string DefaultDesignerExtension { - get { return ".cs"; } + get { return Builder.UseDotNet ? ".fs" : ".cs"; } } public override string DefaultProjectExtension { get { return ".fsproj"; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs index b2f383bcedd..9b64f3d7922 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs @@ -147,13 +147,15 @@ List GetDefaultCommandLineArgs (string verb, string target = null, strin if (string.IsNullOrEmpty (BuildLogFile)) BuildLogFile = Path.Combine (testDir, "build.log"); - var binlog = string.IsNullOrEmpty (target) ? "msbuild" : target; + var binlog = string.IsNullOrEmpty (target) ? Path.GetFileNameWithoutExtension (string.IsNullOrEmpty (BuildLogFile) ? "msbuild" : BuildLogFile) : target; var arguments = new List { verb, $"\"{projectOrSolution}\"", "/noconsolelogger", $"/flp1:LogFile=\"{BuildLogFile}\";Encoding=UTF-8;Verbosity={Verbosity}", $"/bl:\"{Path.Combine (testDir, $"{binlog}.binlog")}\"", + "-m:1", + "-nr:false", "/p:_DisableParallelAot=true", }; if (!string.IsNullOrEmpty (target)) { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index 7ca259a29f0..d747a184fe7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -4,6 +4,9 @@ "AndroidManifest.xml": { "Size": 3032 }, + "assemblies/_Microsoft.Android.Resource.Designer.dll": { + "Size": 1028 + }, "assemblies/Java.Interop.dll": { "Size": 58924 }, @@ -35,7 +38,7 @@ "Size": 3628 }, "classes.dex": { - "Size": 18968 + "Size": 19020 }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 93552 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc index cb7562922f1..a881ffe9a94 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc @@ -5,22 +5,22 @@ "Size": 2604 }, "assemblies/Java.Interop.dll": { - "Size": 68913 + "Size": 68923 }, "assemblies/Mono.Android.dll": { - "Size": 265169 + "Size": 265142 }, "assemblies/mscorlib.dll": { - "Size": 769018 + "Size": 769035 }, "assemblies/System.Core.dll": { - "Size": 28199 + "Size": 28216 }, "assemblies/System.dll": { - "Size": 9180 + "Size": 9191 }, "assemblies/UnnamedProject.dll": { - "Size": 2882 + "Size": 2896 }, "classes.dex": { "Size": 370828 @@ -32,7 +32,7 @@ "Size": 750976 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 332936 + "Size": 333128 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 4039176 @@ -41,7 +41,7 @@ "Size": 66184 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 21256 + "Size": 21248 }, "META-INF/ANDROIDD.RSA": { "Size": 1213 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index 87875ce958d..6ae5c9740f2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -4,6 +4,9 @@ "AndroidManifest.xml": { "Size": 3568 }, + "assemblies/_Microsoft.Android.Resource.Designer.dll": { + "Size": 1945 + }, "assemblies/FormsViewGroup.dll": { "Size": 7314 }, @@ -185,10 +188,10 @@ "Size": 528450 }, "assemblies/Xamarin.Forms.Platform.Android.dll": { - "Size": 384799 + "Size": 337827 }, "assemblies/Xamarin.Forms.Platform.dll": { - "Size": 56878 + "Size": 11087 }, "assemblies/Xamarin.Forms.Xaml.dll": { "Size": 60774 @@ -197,7 +200,7 @@ "Size": 40159 }, "classes.dex": { - "Size": 3090508 + "Size": 3141008 }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 93552 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc index ac496de717d..6e7516a240e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc @@ -4,116 +4,119 @@ "AndroidManifest.xml": { "Size": 3140 }, + "assemblies/_Microsoft.Android.Resource.Designer.dll": { + "Size": 133020 + }, "assemblies/FormsViewGroup.dll": { - "Size": 7215 + "Size": 7230 }, "assemblies/Java.Interop.dll": { - "Size": 69956 + "Size": 69966 }, "assemblies/Mono.Android.dll": { - "Size": 572709 + "Size": 572672 }, "assemblies/Mono.Security.dll": { - "Size": 68432 + "Size": 68450 }, "assemblies/mscorlib.dll": { - "Size": 915408 + "Size": 915425 }, "assemblies/System.Core.dll": { - "Size": 164046 + "Size": 164059 }, "assemblies/System.dll": { - "Size": 388864 + "Size": 388883 }, "assemblies/System.Drawing.Common.dll": { - "Size": 12365 + "Size": 12370 }, "assemblies/System.Net.Http.dll": { - "Size": 110693 + "Size": 110718 }, "assemblies/System.Numerics.dll": { - "Size": 15683 + "Size": 15705 }, "assemblies/System.Runtime.Serialization.dll": { - "Size": 186660 + "Size": 186683 }, "assemblies/System.ServiceModel.Internals.dll": { - "Size": 26594 + "Size": 26604 }, "assemblies/System.Xml.dll": { - "Size": 395656 + "Size": 395668 }, "assemblies/UnnamedProject.dll": { - "Size": 116899 + "Size": 116994 }, "assemblies/Xamarin.AndroidX.Activity.dll": { - "Size": 7697 + "Size": 7711 }, "assemblies/Xamarin.AndroidX.AppCompat.AppCompatResources.dll": { - "Size": 6648 + "Size": 6664 }, "assemblies/Xamarin.AndroidX.AppCompat.dll": { - "Size": 125328 + "Size": 125346 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 7367 + "Size": 7380 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { - "Size": 18272 + "Size": 18289 }, "assemblies/Xamarin.AndroidX.Core.dll": { - "Size": 131930 + "Size": 131944 }, "assemblies/Xamarin.AndroidX.DrawerLayout.dll": { - "Size": 15426 + "Size": 15444 }, "assemblies/Xamarin.AndroidX.Fragment.dll": { - "Size": 43135 + "Size": 43150 }, "assemblies/Xamarin.AndroidX.Legacy.Support.Core.UI.dll": { - "Size": 6715 + "Size": 6728 }, "assemblies/Xamarin.AndroidX.Lifecycle.Common.dll": { - "Size": 7062 + "Size": 7078 }, "assemblies/Xamarin.AndroidX.Lifecycle.LiveData.Core.dll": { - "Size": 7193 + "Size": 7207 }, "assemblies/Xamarin.AndroidX.Lifecycle.ViewModel.dll": { - "Size": 4873 + "Size": 4886 }, "assemblies/Xamarin.AndroidX.Loader.dll": { - "Size": 13585 + "Size": 13596 }, "assemblies/Xamarin.AndroidX.RecyclerView.dll": { - "Size": 102327 + "Size": 102349 }, "assemblies/Xamarin.AndroidX.SavedState.dll": { - "Size": 6268 + "Size": 6294 }, "assemblies/Xamarin.AndroidX.SwipeRefreshLayout.dll": { - "Size": 11271 + "Size": 11284 }, "assemblies/Xamarin.AndroidX.ViewPager.dll": { - "Size": 19424 + "Size": 19438 }, "assemblies/Xamarin.Forms.Core.dll": { - "Size": 524736 + "Size": 524743 }, "assemblies/Xamarin.Forms.Platform.Android.dll": { - "Size": 384872 + "Size": 384885 }, "assemblies/Xamarin.Forms.Platform.dll": { "Size": 56878 }, "assemblies/Xamarin.Forms.Xaml.dll": { - "Size": 55801 + "Size": 55807 }, "assemblies/Xamarin.Google.Android.Material.dll": { - "Size": 43497 + "Size": 43514 }, "classes.dex": { - "Size": 3482812 + "Size": 3533300 }, "lib/arm64-v8a/libmono-btls-shared.so": { "Size": 1613872 @@ -122,7 +125,7 @@ "Size": 750976 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 332936 + "Size": 333128 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 4039176 @@ -131,7 +134,7 @@ "Size": 66184 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 107024 + "Size": 107144 }, "META-INF/android.support.design_material.version": { "Size": 12 @@ -140,7 +143,7 @@ "Size": 1213 }, "META-INF/ANDROIDD.SF": { - "Size": 75858 + "Size": 75981 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -251,7 +254,7 @@ "Size": 10 }, "META-INF/MANIFEST.MF": { - "Size": 75731 + "Size": 75854 }, "META-INF/proguard/androidx-annotations.pro": { "Size": 339 @@ -1883,5 +1886,5 @@ "Size": 341040 } }, - "PackageSize": 9521310 + "PackageSize": 9672959 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs new file mode 100644 index 00000000000..73168a69c01 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/FileResourceParser.cs @@ -0,0 +1,389 @@ +using System; +using System.CodeDom; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.Build.Utilities; +using Microsoft.Android.Build.Tasks; + +namespace Xamarin.Android.Tasks +{ + class FileResourceParser : ResourceParser + { + public string JavaPlatformDirectory { get; set; } + + public string ResourceFlagFile { get; set; } + + Dictionary arrayMapping = new Dictionary (); + Dictionary> foofoo = new Dictionary> (); + List custom_types = new List (); + XDocument publicXml; + + string[] publicXmlFiles = new string[] { + "public.xml", + "public-final.xml", + "public-staging.xml", + }; + + protected XDocument LoadPublicXml () { + string publicXmlPath = Path.Combine (JavaPlatformDirectory, "data", "res", "values"); + foreach (var file in publicXmlFiles) { + if (File.Exists (Path.Combine (publicXmlPath, file))) { + return XDocument.Load (Path.Combine (publicXmlPath, file)); + } + } + return null; + } + + public IList Parse (string resourceDirectory, IEnumerable additionalResourceDirectories, Dictionary resourceMap) + { + Log.LogDebugMessage ($"Parsing Directory {resourceDirectory}"); + string publicXmlPath = Path.Combine (JavaPlatformDirectory, "data", "res", "values"); + publicXml = LoadPublicXml (); + var result = new List (); + Dictionary> resources = new Dictionary> (); + foreach (var knownType in RtxtParser.knownTypes) { + if (knownType == "styleable") { + resources.Add (knownType, new List ()); + continue; + } + resources.Add (knownType, new SortedSet (new RComparer ())); + } + foreach (var dir in Directory.EnumerateDirectories (resourceDirectory, "*", SearchOption.TopDirectoryOnly)) { + foreach (var file in Directory.EnumerateFiles (dir, "*.*", SearchOption.AllDirectories)) { + ProcessResourceFile (file, resources); + } + } + foreach (var dir in additionalResourceDirectories ?? Array.Empty()) { + Log.LogDebugMessage ($"Processing Directory {dir}"); + if (Directory.Exists (dir)) { + foreach (var file in Directory.EnumerateFiles (dir, "*.*", SearchOption.AllDirectories)) { + ProcessResourceFile (file, resources); + } + } else { + Log.LogDebugMessage ($"Skipping non-existent directory: {dir}"); + } + } + + // now generate the Id's we need in a specific order + List declarationIds = new List (); + declarationIds.Add ("attr"); + declarationIds.Add ("drawable"); + declarationIds.Add ("mipmap"); + declarationIds.Add ("font"); + declarationIds.Add ("layout"); + declarationIds.Add ("anim"); + declarationIds.Add ("animator"); + declarationIds.Add ("transition"); + declarationIds.Add ("xml"); + declarationIds.Add ("raw"); + declarationIds.Add ("dimen"); + declarationIds.Add ("string"); + declarationIds.Add ("array"); + declarationIds.Add ("plurals"); + declarationIds.Add ("bool"); + declarationIds.Add ("color"); + declarationIds.Add ("integer"); + declarationIds.Add ("menu"); + declarationIds.Add ("id"); + // custom types + foreach (var customClass in custom_types) { + declarationIds.Add (customClass); + } + + declarationIds.Add ("interpolator"); + declarationIds.Add ("style"); + declarationIds.Add ("styleable"); + + declarationIds.Sort ((a, b) => { + return string.Compare (a, b, StringComparison.OrdinalIgnoreCase); + }); + + string itemPackageId = "0x7f"; + int typeid = 1; + + foreach (var t in declarationIds) { + int itemid = 0; + if (!resources.ContainsKey(t)) { + continue; + } + if (resources[t].Count () == 0) { + continue; + } + foreach (R r in resources[t].OrderBy(x => x.ToSortedString(), StringComparer.Ordinal)) { + + int id = Convert.ToInt32 (itemPackageId + typeid.ToString ("X2") + itemid.ToString ("X4"), fromBase: 16); + if (r.Type == RType.Integer && r.Id == -1) { + itemid++; + r.UpdateId (id); + } else { + if (foofoo.ContainsKey (r.Identifier)) { + var items = foofoo[r.Identifier]; + if (r.Ids != null) { + // do something special cos its an array we need to replace *some* its. + int[] newIds = new int[r.Ids.Length]; + for (int i = 0; i < r.Ids.Length; i++) { + // we need to lookup the ID's for these from the ones generated. + newIds[i] = r.Ids[i]; + if (r.Ids[i] == -1) + newIds[i] = GetId (result, items[i]); + } + r.UpdateIds (newIds); + } + } + } + result.Add (r); + } + typeid++; + } + + result.Sort (new RComparer ()); + + return result; + } + + class RComparer : IComparer { + public int Compare(R a, R b) { + return string.Compare (a.ToSortedString (), b.ToSortedString (), StringComparison.Ordinal); + } + } + + HashSet resourceNamesToUseDirectly = new HashSet () { + "integer-array", + "string-array", + "declare-styleable", + "add-resource", + }; + + int GetId (ICollection resources, string identifier) + { + foreach (R r in resources) { + if (r.Identifier == identifier) { + return r.Id; + } + } + return -1; + } + + void ProcessResourceFile (string file, Dictionary> resources) + { + Log.LogDebugMessage ($"{nameof(ProcessResourceFile)} {file}"); + var fileName = Path.GetFileNameWithoutExtension (file); + if (string.IsNullOrEmpty (fileName)) + return; + if (fileName.EndsWith (".9", StringComparison.OrdinalIgnoreCase)) + fileName = Path.GetFileNameWithoutExtension (fileName); + var path = Directory.GetParent (file).Name; + var ext = Path.GetExtension (file); + switch (ext) { + case ".xml": + case ".axml": + if (string.Compare (path, "raw", StringComparison.OrdinalIgnoreCase) == 0) + goto default; + try { + ProcessXmlFile (file, resources); + } catch (XmlException ex) { + Log.LogCodedWarning ("XA1000", Properties.Resources.XA1000, file, ex); + } + break; + default: + break; + } + CreateResourceField (path, fileName, resources); + } + + void CreateResourceField (string root, string id, Dictionary> resources) { + var i = root.IndexOf ('-'); + var item = i < 0 ? root : root.Substring (0, i); + item = resourceNamesToUseDirectly.Contains (root) ? root : item; + switch (item.ToLowerInvariant ()) { + case "animation": + item = "anim"; + break; + case "array": + case "string-array": + case "integer-array": + item = "array"; + break; + case "enum": + case "flag": + item = "id"; + break; + } + var r = new R () { + ResourceTypeName = item, + Identifier = id, + Id = -1, + }; + if (!resources.ContainsKey (item)) { + Log.LogDebugMessage ($"Ignoring path:{item}"); + return; + } + resources[item].Add (r); + } + + void ProcessStyleable (XmlReader reader, Dictionary> resources) + { + Log.LogDebugMessage ($"{nameof(ProcessStyleable)}"); + string topName = null; + int fieldCount = 0; + List fields = new List (); + List attribs = new List (); + if (reader.HasAttributes) { + while (reader.MoveToNextAttribute ()) { + if (reader.Name.Replace ("android:", "") == "name") + topName = reader.Value; + } + } + while (reader.Read ()) { + if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) + continue; + string name = null; + if (string.IsNullOrEmpty (topName)) { + if (reader.HasAttributes) { + while (reader.MoveToNextAttribute ()) { + if (reader.Name.Replace ("android:", "") == "name") + topName = reader.Value; + } + } + } + if (!reader.IsStartElement ()) + continue; + if (reader.HasAttributes) { + while (reader.MoveToNextAttribute ()) { + if (reader.Name.Replace ("android:", "") == "name") + name = reader.Value; + } + } + reader.MoveToElement (); + if (reader.LocalName == "attr") { + attribs.Add (name); + } + } + var field = new R () { + ResourceTypeName = "styleable", + Identifier = topName, + Type = RType.Array, + }; + if (!arrayMapping.ContainsKey (field)) { + foofoo.Add (field.Identifier, new List ()); + attribs.Sort (StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < attribs.Count; i++) { + string name = attribs [i]; + if (!name.StartsWith ("android:", StringComparison.OrdinalIgnoreCase)) { + var r = new R () { + ResourceTypeName = "attr", + Identifier = $"{name}", + Id = -1, + }; + resources [r.ResourceTypeName].Add (r); + fields.Add (r); + } else { + // this is an android:xxx resource, we should not calculate the id + // we should get it from "somewhere" maybe the pubic.xml + name = name.Replace ("android:", string.Empty); + var element = publicXml?.XPathSelectElement ($"/resources/public[@name='{name}']") ?? null; + int value = Convert.ToInt32 (element?.Attribute ("id")?.Value ?? "0x0", fromBase: 16); + var r = new R () { + ResourceTypeName = "attr", + Identifier = $"{name}", + Id = value, + }; + fields.Add (r); + } + } + if (field.Type != RType.Array) + return; + arrayMapping.Add (field, fields.ToArray ()); + + field.Ids = new int [attribs.Count]; + for (int idx =0; idx < field.Ids.Length; idx++) + field.Ids[idx] = fields[idx].Id; + resources [field.ResourceTypeName].Add (field); + int id = 0; + foreach (string r in attribs) { + foofoo[field.Identifier].Add (r.Replace (":", "_")); + resources [field.ResourceTypeName].Add (new R () { + ResourceTypeName = field.ResourceTypeName, + Identifier = $"{field.Identifier}_{r.Replace (":", "_")}", + Id = id++, + }); + } + } + } + + 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; + if (elementName == "declare-styleable" || elementName == "configVarying" || elementName == "add-resource") { + ProcessStyleable (reader.ReadSubtree (), resources); + 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 ("+", ""); + } + id = values [1]; + } + + } + 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/Utilities/ManagedResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs index fa735737a36..bcb01245334 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs @@ -14,7 +14,7 @@ namespace Xamarin.Android.Tasks { - class ManagedResourceParser : ResourceParser + class ManagedResourceParser : FileResourceParser { class CompareTuple : IComparer<(int Key, CodeMemberField Value)> { @@ -37,10 +37,6 @@ public int Compare((int Key, CodeMemberField Value) x, (int Key, CodeMemberField XDocument publicXml; - public string JavaPlatformDirectory { get; set; } - - public string ResourceFlagFile { get; set; } - void SortMembers (CodeTypeDeclaration decl, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase) { CodeTypeMember [] members = new CodeTypeMember [decl.Members.Count]; @@ -87,10 +83,7 @@ public CodeTypeDeclaration Parse (string resourceDirectory, string rTxtFile, IEn transition = CreateClass ("Transition"); xml = CreateClass ("Xml"); - string publicXmlPath = Path.Combine (JavaPlatformDirectory, "data", "res", "values", "public.xml"); - if (File.Exists (publicXmlPath)) { - publicXml = XDocument.Load (publicXmlPath); - } + publicXml = LoadPublicXml (); var resModifiedDate = !string.IsNullOrEmpty (ResourceFlagFile) && File.Exists (ResourceFlagFile) ? File.GetLastWriteTimeUtc (ResourceFlagFile) @@ -296,104 +289,17 @@ public CodeTypeDeclaration Parse (string resourceDirectory, string rTxtFile, IEn void ProcessRtxtFile (string file) { - var lines = System.IO.File.ReadLines (file); - int lineNumber = 0; - foreach (var line in lines) { - lineNumber++; - var items = line.Split (new char [] { ' ' }, 4); - if (items.Length < 4) { - Log.LogDebugMessage ($"'{file}:{lineNumber}' ignoring contents '{line}', it does not have the correct number of elements."); - continue; - } - int value = items [1] != "styleable" ? Convert.ToInt32 (items [3], 16) : -1; - string itemName = items [2]; - switch (items [1]) { - case "anim": - CreateIntField (animation, itemName, value); - break; - case "animator": - CreateIntField (animator, itemName, value); - break; - case "attr": - CreateIntField (attrib, itemName, value); - break; - case "array": - CreateIntField (arrays, itemName, value); - break; - case "bool": - CreateIntField (boolean, itemName, value); - break; - case "color": - CreateIntField (colors, itemName, value); - break; - case "dimen": - CreateIntField (dimension, itemName, value); - break; - case "drawable": - CreateIntField (drawable, itemName, value); - break; - case "font": - CreateIntField (font, itemName, value); - break; - case "id": - CreateIntField (ids, itemName, value); - break; - case "integer": - CreateIntField (ints, itemName, value); - break; - case "interpolator": - CreateIntField (interpolators, itemName, value); - break; - case "layout": - CreateIntField (layout, itemName, value); - break; - case "menu": - CreateIntField (menu, itemName, value); - break; - case "mipmap": - CreateIntField (mipmaps, itemName, value); - break; - case "plurals": - CreateIntField (plurals, itemName, value); - break; - case "raw": - CreateIntField (raw, itemName, value); - break; - case "string": - CreateIntField (strings, itemName, value); - break; - case "style": - CreateIntField (style, itemName, value); - break; - case "styleable": - switch (items [0]) { - case "int": - CreateIntField (styleable, itemName, Convert.ToInt32 (items [3], 10)); + var parser = new RtxtParser (); + var resources = parser.Parse (file, Log, map); + foreach (var r in resources) { + var cl = CreateClass (r.ResourceTypeName); + switch (r.Type) { + case RType.Integer: + CreateIntField (cl, r.Identifier, r.Id); break; - case "int[]": - var arrayValues = items [3].Trim (new char [] { '{', '}' }) - .Replace (" ", "") - .Split (new char [] { ',' }); - CreateIntArrayField (styleable, itemName, arrayValues.Length, - arrayValues.Select (x => string.IsNullOrEmpty (x) ? -1 : Convert.ToInt32 (x, 16)).ToArray ()); + case RType.Array: + CreateIntArrayField (cl, r.Identifier, r.Ids.Length, r.Ids); break; - } - break; - case "transition": - CreateIntField (transition, itemName, value); - break; - case "xml": - CreateIntField (xml, itemName, value); - break; - // for custom views - default: - CodeTypeDeclaration customClass; - if (!custom_types.TryGetValue (items [1], out customClass)) { - customClass = CreateClass (items [1]); - custom_types.Add (items [1], customClass); - } - CreateIntField (customClass, itemName, value); - break; } } } @@ -441,15 +347,22 @@ CodeTypeDeclaration CreateResourceClass () return decl; } + Dictionary classMapping = new Dictionary (StringComparer.OrdinalIgnoreCase); + CodeTypeDeclaration CreateClass (string type) { - var t = new CodeTypeDeclaration (ResourceParser.GetNestedTypeName (type)) { + var typeName = ResourceParser.GetNestedTypeName (type); + if (classMapping.ContainsKey (typeName)) { + return classMapping [typeName]; + } + var t = new CodeTypeDeclaration (typeName) { IsPartial = true, TypeAttributes = TypeAttributes.Public, }; t.Members.Add (new CodeConstructor () { Attributes = MemberAttributes.Private, }); + classMapping.Add (typeName, t); return t; } @@ -608,7 +521,6 @@ void CreateResourceField (string root, string fieldName, XmlReader element = nul void ProcessStyleable (XmlReader reader) { string topName = null; - int fieldCount = 0; List fields = new List (); List attribs = new List (); while (reader.Read ()) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 5e41b62be37..19088a10f6b 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -325,6 +325,28 @@ public static bool HasMonoAndroidReference (MetadataReader reader) return false; } + public static bool HasResourceDesignerAssemblyReference (ITaskItem assembly) + { + if (!File.Exists (assembly.ItemSpec)) { + return false; + } + using var pe = new PEReader (File.OpenRead (assembly.ItemSpec)); + var reader = pe.GetMetadataReader (); + return HasResourceDesignerAssemblyReference (reader); + } + + public static bool HasResourceDesignerAssemblyReference (MetadataReader reader) + { + foreach (var handle in reader.AssemblyReferences) { + var reference = reader.GetAssemblyReference (handle); + var name = reader.GetString (reference.Name); + if (string.CompareOrdinal (name, "_Microsoft.Android.Resource.Designer") == 0) { + return true; + } + } + return false; + } + public static bool IsReferenceAssembly (string assembly) { using (var stream = File.OpenRead (assembly)) @@ -388,12 +410,26 @@ internal static IEnumerable GetFrameworkAssembliesToTreatAsUserAssemb } #endif - public static Dictionary LoadAcwMapFile (string acwPath) + public static bool SaveMapFile (IBuildEngine4 engine, string mapFile, Dictionary map) { - var acw_map = new Dictionary (); - if (!File.Exists (acwPath)) + engine?.RegisterTaskObjectAssemblyLocal (mapFile, map, RegisteredTaskObjectLifetime.Build); + using (var writer = MemoryStreamPool.Shared.CreateStreamWriter ()) { + foreach (var i in map.OrderBy (x => x.Key)) { + writer.WriteLine ($"{i.Key};{i.Value}"); + } + writer.Flush (); + return Files.CopyIfStreamChanged (writer.BaseStream, mapFile); + } + } + public static Dictionary LoadMapFile (IBuildEngine4 engine, string mapFile, StringComparer comparer) + { + var cachedMap = engine?.GetRegisteredTaskObjectAssemblyLocal> (mapFile, RegisteredTaskObjectLifetime.Build); + if (cachedMap != null) + return cachedMap; + var acw_map = new Dictionary (comparer); + if (!File.Exists (mapFile)) return acw_map; - foreach (var s in File.ReadLines (acwPath)) { + foreach (var s in File.ReadLines (mapFile)) { var items = s.Split (new char[] { ';' }, count: 2); if (!acw_map.ContainsKey (items [0])) acw_map.Add (items [0], items [1]); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceDesignerImportGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceDesignerImportGenerator.cs index 8e7ddacfd3e..d9bcf2ecf69 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceDesignerImportGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceDesignerImportGenerator.cs @@ -47,6 +47,7 @@ public void CreateImportMethods (IEnumerable libraries) var reader = pe.GetMetadataReader (); var resourceDesignerName = GetResourceDesignerClass (reader); if (string.IsNullOrEmpty (resourceDesignerName)) { + Log.LogDebugMessage ($"Could not find 'ResourceDesignerAttribute' in {assemblyPath}"); continue; } string aliasMetaData = assemblyPath.GetMetadata ("Aliases"); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceIdentifier.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceIdentifier.cs index eb96d4f5aa0..7edfc38faf5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceIdentifier.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceIdentifier.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text.RegularExpressions; +using Microsoft.Android.Build.Tasks; using Microsoft.Build.Utilities; namespace Xamarin.Android.Tasks @@ -42,5 +43,20 @@ public static string CreateValidIdentifier (string identifier) return result; } + + internal static string GetResourceName (string type, string name, Dictionary map, TaskLoggingHelper log) + { + string mappedValue; + string key = string.Format ("{0}{1}{2}", type, Path.DirectorySeparatorChar, name).ToLowerInvariant (); + + if (map.TryGetValue (key, out mappedValue)) { + log.LogDebugMessage (" - Remapping resource: {0}.{1} -> {2}", type, name, mappedValue); + return ResourceIdentifier.CreateValidIdentifier (mappedValue.Substring (mappedValue.LastIndexOf (Path.DirectorySeparatorChar) + 1)); + } + + log.LogDebugMessage (" - Not remapping resource: {0}.{1}", type, name); + + return ResourceIdentifier.CreateValidIdentifier (name); + } } -} \ No newline at end of file +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs index d85b97299e9..64cedf71129 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs @@ -40,17 +40,7 @@ internal static string GetNestedTypeName (string name) internal string GetResourceName (string type, string name, Dictionary map) { - string mappedValue; - string key = string.Format ("{0}{1}{2}", type, Path.DirectorySeparatorChar, name).ToLowerInvariant (); - - if (map.TryGetValue (key, out mappedValue)) { - Log.LogDebugMessage (" - Remapping resource: {0}.{1} -> {2}", type, name, mappedValue); - return ResourceIdentifier.CreateValidIdentifier (mappedValue.Substring (mappedValue.LastIndexOf (Path.DirectorySeparatorChar) + 1)); - } - - Log.LogDebugMessage (" - Not remapping resource: {0}.{1}", type, name); - - return ResourceIdentifier.CreateValidIdentifier (name); + return ResourceIdentifier.GetResourceName (type, name, map, Log); } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs new file mode 100644 index 00000000000..4584601c1b5 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Utilities; + +namespace Xamarin.Android.Tasks +{ + public enum RType { + Integer, + Array, + } + public enum ResourceType { + System, + Custom, + } + public struct R : IComparable { + public RType Type; + public int Id; + public int [] Ids; + public string Identifier; + public string ResourceTypeName; + public ResourceType ResourceType; + + public string Key => $"{ResourceTypeName}:{Identifier}"; + + public override string ToString () + { + if (Type == RType.Integer) { + if (ResourceTypeName == "styleable") + return $"int {ResourceTypeName} {Identifier} {Id}"; + return $"int {ResourceTypeName} {Identifier} 0x{Id.ToString ("x8")}"; + } + return $"int[] {ResourceTypeName} {Identifier} {{ {String.Join (", ", Ids.Select (x => $"0x{x.ToString ("x8")}"))} }}"; + } + + public string ToSortedString () + { + return $"{ResourceTypeName}_{Identifier}"; + } + + public int CompareTo(R other) + { + return String.Compare (ToSortedString (), other.ToSortedString (), StringComparison.OrdinalIgnoreCase); + } + + public void UpdateId (int newId) + { + Id = newId; + } + + public void UpdateIds (int [] newIds) + { + Ids = newIds; + } + } + + public class RtxtParser { + + static readonly char[] EmptyChar = new char [] { ' ' }; + static readonly char[] CurlyBracketsChar = new char [] { '{', '}' }; + static readonly char[] CommaChar = new char [] { ',' }; + + TaskLoggingHelper log; + Dictionary map; + + public static HashSet knownTypes = new HashSet () { + "anim", + "animator", + "attr", + "array", + "bool", + "color", + "dimen", + "drawable", + "font", + "id", + "integer", + "interpolator", + "layout", + "menu", + "mipmap", + "plurals", + "raw", + "string", + "style", + "styleable", + "transition", + "xml", + }; + + public IEnumerable Parse (string file, TaskLoggingHelper logger, Dictionary mapping) + { + log = logger; + map = mapping; + var result = new List (); + if (File.Exists (file)) + ProcessRtxtFile (file, result); + return result; + } + + void ProcessRtxtFile (string file, IList result) + { + int lineNumber = 0; + foreach (var line in File.ReadLines (file)) { + lineNumber++; + var items = line.Split (EmptyChar, 4); + if (items.Length < 4) { + log.LogDebugMessage ($"'{file}:{lineNumber}' ignoring contents '{line}', it does not have the correct number of elements."); + continue; + } + int value = items [1] != "styleable" ? Convert.ToInt32 (items [3], 16) : -1; + string itemName = ResourceIdentifier.GetResourceName(items [1], items [2], map, log); + if (knownTypes.Contains (items [1])) { + if (items [1] != "styleable") { + result.Add (new R () { + ResourceTypeName = items [1], + Identifier = itemName, + Id = value, + }); + continue; + } + switch (items [0]) { + case "int": + result.Add (new R () { + ResourceTypeName = items [1], + Identifier = itemName, + Id = Convert.ToInt32 (items [3], 10), + }); + break; + case "int[]": + var arrayValues = items [3].Trim (CurlyBracketsChar) + .Replace (" ", "") + .Split (CommaChar); + + result.Add (new R () { + ResourceTypeName = items [1], + Type = RType.Array, + Identifier = itemName, + Ids = arrayValues.Select (x => string.IsNullOrEmpty (x) ? -1 : Convert.ToInt32 (x, 16)).ToArray (), + }); + break; + } + + } + result.Add (new R () { + ResourceTypeName = items[1], + ResourceType = ResourceType.Custom, + Identifier = itemName, + Id = value, + }); + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs new file mode 100644 index 00000000000..cc2e7a70991 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Linq; +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Utilities; + +namespace Xamarin.Android.Tasks +{ + /// Write a list of Item to a file + /// + public class RtxtWriter { + public void Write (string file, IList items) + { + var sb = new StringBuilder (); + foreach (var item in items) { + sb.AppendLine (item.ToString ()); + } + Files.CopyIfStringChanged (sb.ToString (), file); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index ee9e29a5c39..dd902240461 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -348,6 +348,12 @@ Utilities\%(Filename)%(Extension) + + Utilities\%(Filename)%(Extension) + + + Utilities\%(Filename)%(Extension) + @@ -407,6 +413,9 @@ JavaInteropTypeManager.java + + Resource.Designer.snk + diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets index 7cb21493b26..cd4782e7bba 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets @@ -88,6 +88,10 @@ PreserveNewest Xamarin.Android.Designer.targets + + PreserveNewest + Xamarin.Android.Resource.Designer.targets + PreserveNewest Xamarin.Android.Aapt.targets diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index af4d1456749..8be69cc1c2c 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -57,6 +57,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. + @@ -375,6 +376,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. + @@ -574,11 +576,11 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. + Condition=" '$(Language)' == 'C#' and '$(ManagedDesignTimeBuild)' != 'true' "> - + @@ -998,6 +1000,7 @@ because xbuild doesn't support framework reference assemblies. <_PropertyCacheItems Include="AndroidSupportedAbis=$(AndroidSupportedAbis)" /> <_PropertyCacheItems Include="AndroidManifestPlaceholders=$(AndroidManifestPlaceholders)" /> <_PropertyCacheItems Include="ProjectFullPath=$(MSBuildProjectFullPath)" /> + <_PropertyCacheItems Include="AndroidUseDesignerAssembly=$(AndroidUseDesignerAssembly)" /> - + DependsOnTargets="_CreatePropertiesCache;_ExtractLibraryProjectImports;_ValidateAndroidPackageProperties;_GenerateResourceCaseMap;_BeforeManagedUpdateAndroidResgen"> @@ -1080,11 +1084,11 @@ because xbuild doesn't support framework reference assemblies. - + @@ -1244,6 +1248,7 @@ because xbuild doesn't support framework reference assemblies. _GenerateAndroidResourceDir; _IncludeLayoutBindingSources; _DefineBuildTargetAbis; + _GenerateResourceCaseMap; <_UpdateAndroidResgenInputs> @(_AndroidMSBuildAllProjects); @@ -1265,7 +1270,7 @@ because xbuild doesn't support framework reference assemblies. + + + + + + - - + + - - - - + + + + @@ -1460,6 +1489,7 @@ because xbuild doesn't support framework reference assemblies. DestinationFiles="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" TargetName="$(TargetName)" AddKeepAlives="$(AndroidAddKeepAlives)" + UseDesignerAssembly="$(AndroidUseDesignerAssembly)" Deterministic="$(Deterministic)" UsingAndroidNETSdk="$(UsingAndroidNETSdk)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.DesignTime.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.DesignTime.targets index 2102d915d28..00f3f2cfdd5 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.DesignTime.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.DesignTime.targets @@ -42,6 +42,7 @@ This file is used by all project types, including binding projects. true true + True False <_AndroidLibraryImportsCache Condition=" '$(DesignTimeBuild)' == 'true' And !Exists ('$(_AndroidLibraryImportsCache)') ">$(_AndroidLibraryImportsDesignTimeCache) <_AndroidLibraryProjectImportsCache Condition=" '$(DesignTimeBuild)' == 'true' And !Exists ('$(_AndroidLibraryProjectImportsCache)') ">$(_AndroidLibraryProjectImportsDesignTimeCache) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets index b08a0d94736..800cabe865b 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets @@ -108,8 +108,8 @@ projects. .NET 5 projects will not import this file. $(CoreResolveReferencesDependsOn); - UpdateAndroidInterfaceProxies; UpdateAndroidResources; + UpdateAndroidInterfaceProxies; $(DeferredBuildDependsOn); @@ -300,6 +300,10 @@ projects. .NET 5 projects will not import this file. Include="$(OutDir)$(TargetFileName)" Condition="Exists ('$(OutDir)$(TargetFileName)')" /> + + diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index f79b85b3222..53188b11db7 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -706,6 +706,67 @@ public void RunWithLLVMEnabled () Path.Combine (Root, builder.ProjectDirectory, "startup-logcat.log"))); } + [Test] + public void ResourceDesignerWithNuGetReference ([Values ("net6.0-android32.0", "net7.0-android33.0")] string dotnetTargetFramework) + { + AssertHasDevices (); + + string path = Path.Combine (Root, "temp", TestName); + + if (!Builder.UseDotNet) { + Assert.Ignore ("Skipping. Test not relevant under Classic."); + } + // Build a NuGet Package + var nuget = new XASdkProject (outputType: "Library") { + Sdk = "Xamarin.Legacy.Sdk/0.2.0-alpha2", + ProjectName = "Test.Nuget.Package", + IsRelease = true, + ExtraNuGetConfigSources = { + // Projects targeting net6.0 require ref/runtime packs on NuGet.org + "https://api.nuget.org/v3/index.json", + "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json", + }, + }; + nuget.Sources.Clear (); + nuget.Sources.Add (new AndroidItem.AndroidResource ("Resources/values/Strings.xml") { + TextContent = () => @" + Library Resource From Nuget +", + }); + nuget.SetProperty ("PackageName", "Test.Nuget.Package"); + var legacyTargetFrameworkVersion = "13.0"; + var legacyTargetFramework = $"monoandroid{legacyTargetFrameworkVersion}"; + nuget.SetProperty ("TargetFramework", value: ""); + nuget.SetProperty ("TargetFrameworks", value: $"{dotnetTargetFramework};{legacyTargetFramework}"); + + string directory = Path.Combine ("temp", TestName, "Test.Nuget.Package"); + var dotnet = CreateDotNetBuilder (nuget, directory); + Assert.IsTrue (dotnet.Pack (), "`dotnet pack` should succeed"); + + // Build an app which references it. + var proj = new XamarinAndroidApplicationProject () { + IsRelease = true, + }; + proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86", "x86_64"); + proj.OtherBuildItems.Add (new BuildItem ("None", "NuGet.config") { + TextContent = () => @" + + + + +", + }); + proj.PackageReferences.Add (new Package { + Id = "Test.Nuget.Package", + Version = "1.0.0", + }); + builder = CreateApkBuilder (Path.Combine (path, proj.ProjectName)); + Assert.IsTrue (builder.Install (proj, doNotCleanupOnUpdate: true), "Install should have succeeded."); + string resource_designer = GetResourceDesignerPath (builder, proj); + var contents = GetResourceDesignerText (proj, resource_designer); + StringAssert.Contains ("public const int library_resouce_from_nuget =", contents); + } + [Test] public void SingleProject_ApplicationId () { @@ -841,5 +902,30 @@ public MyLayout (Android.Content.Context context, Android.Util.IAttributeSet att Path.Combine (Root, builder.ProjectDirectory, "startup-logcat.log")); Assert.IsTrue (didStart, "Activity should have started."); } + + DotNetCLI CreateDotNetBuilder (string relativeProjectDir = null) + { + if (string.IsNullOrEmpty (relativeProjectDir)) { + relativeProjectDir = Path.Combine ("temp", TestName); + } + string fullProjectDirectory = Path.Combine (Root, relativeProjectDir); + TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjectDirectory; + + new XASdkProject ().CopyNuGetConfig (relativeProjectDir); + return new DotNetCLI (Path.Combine (fullProjectDirectory, $"{TestName}.csproj")); + } + + DotNetCLI CreateDotNetBuilder (XASdkProject project, string relativeProjectDir = null) + { + if (string.IsNullOrEmpty (relativeProjectDir)) { + relativeProjectDir = Path.Combine ("temp", TestName); + } + string fullProjectDirectory = Path.Combine (Root, relativeProjectDir); + TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjectDirectory; + var files = project.Save (); + project.Populate (relativeProjectDir, files); + project.CopyNuGetConfig (relativeProjectDir); + return new DotNetCLI (project, Path.Combine (fullProjectDirectory, project.ProjectFilePath)); + } } } diff --git a/tests/MSBuildDeviceIntegration/Tests/InstantRunTest.cs b/tests/MSBuildDeviceIntegration/Tests/InstantRunTest.cs index d3ff4f02248..6605cba3a8d 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstantRunTest.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstantRunTest.cs @@ -56,6 +56,7 @@ public void TargetsSkipped ([Values(false, true)] bool useManagedResourceGenerat UseLatestPlatformSdk = true, }; proj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", useManagedResourceGenerator.ToString ()); + proj.SetProperty ("AndroidUseDesignerAssembly", "False"); var b = CreateApkBuilder ($"temp/InstantRunTargetsSkipped_{useManagedResourceGenerator}", cleanupOnDispose: false); Assert.IsTrue (b.Build (proj), "1 build should have succeeded."); diff --git a/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.csproj b/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.csproj index 84fbd2ae182..80c5cb93874 100644 --- a/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.csproj +++ b/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.csproj @@ -59,6 +59,7 @@ + diff --git a/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems b/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems index 16b42acd14b..185f6e9fe7c 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems +++ b/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems @@ -13,7 +13,6 @@ - diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests.csproj b/tests/Mono.Android-Tests/Mono.Android-Tests.csproj index 1d4a287f573..f976680d4e3 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Tests.csproj +++ b/tests/Mono.Android-Tests/Mono.Android-Tests.csproj @@ -29,6 +29,7 @@ <_ASANScript>..\..\build-tools\wrap.sh\asan.sh <_UBSANScript>..\..\build-tools\wrap.sh\ubsan.sh <_MonoAndroidTestPackage>Mono.Android_Tests + True diff --git a/tests/Mono.Android-Tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj b/tests/Mono.Android-Tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj index 848607e2899..b7146ae1ca7 100644 --- a/tests/Mono.Android-Tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj +++ b/tests/Mono.Android-Tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj @@ -24,6 +24,7 @@ <_SkipJniAddNativeMethodRegistrationAttributeScan>True <_MonoAndroidTestPackage>Mono.Android_TestsMultiDex -MultiDex + True @@ -67,7 +68,6 @@ - From 1d11baee2313c2620d61722698add29dd1ff8875 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 7 Dec 2022 17:05:07 +0000 Subject: [PATCH 02/18] Fix test failures --- src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs | 2 +- .../Xamarin.Android.Common.targets | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs index 4584601c1b5..6b3d1fd9470 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs @@ -142,7 +142,7 @@ void ProcessRtxtFile (string file, IList result) }); break; } - + continue; } result.Add (new R () { ResourceTypeName = items[1], diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 8be69cc1c2c..717ecc87fb2 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -578,8 +578,10 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - - + + + + From 66b433a8ea5a07a52fbe309c36aa02dac706886f Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Thu, 8 Dec 2022 11:02:41 +0000 Subject: [PATCH 03/18] Fix failing test --- src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 717ecc87fb2..4a07b87e4b4 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -582,7 +582,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - + From a3077557ac80c5acc335e2965436e2af80127d12 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Thu, 8 Dec 2022 13:20:16 +0000 Subject: [PATCH 04/18] Fix make all-tests --- src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 4a07b87e4b4..14418bb0e23 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -578,7 +578,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - + From fb0bccfb767918619a1ddd80442b09455562972b Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Thu, 8 Dec 2022 16:59:06 +0000 Subject: [PATCH 05/18] Fix apkdesc files --- .../BuildReleaseArm64SimpleLegacy.apkdesc | 8 +++--- .../BuildReleaseArm64XFormsLegacy.apkdesc | 25 ++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc index a881ffe9a94..ff98f67fb80 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc @@ -8,13 +8,13 @@ "Size": 68923 }, "assemblies/Mono.Android.dll": { - "Size": 265142 + "Size": 265140 }, "assemblies/mscorlib.dll": { - "Size": 769035 + "Size": 769036 }, "assemblies/System.Core.dll": { - "Size": 28216 + "Size": 28215 }, "assemblies/System.dll": { "Size": 9191 @@ -41,7 +41,7 @@ "Size": 66184 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 21248 + "Size": 21264 }, "META-INF/ANDROIDD.RSA": { "Size": 1213 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc index 6e7516a240e..4a37d89eac4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc @@ -4,9 +4,6 @@ "AndroidManifest.xml": { "Size": 3140 }, - "assemblies/_Microsoft.Android.Resource.Designer.dll": { - "Size": 133020 - }, "assemblies/FormsViewGroup.dll": { "Size": 7230 }, @@ -14,10 +11,10 @@ "Size": 69966 }, "assemblies/Mono.Android.dll": { - "Size": 572672 + "Size": 572670 }, "assemblies/Mono.Security.dll": { - "Size": 68450 + "Size": 68449 }, "assemblies/mscorlib.dll": { "Size": 915425 @@ -35,7 +32,7 @@ "Size": 110718 }, "assemblies/System.Numerics.dll": { - "Size": 15705 + "Size": 15706 }, "assemblies/System.Runtime.Serialization.dll": { "Size": 186683 @@ -59,7 +56,7 @@ "Size": 125346 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 7380 + "Size": 7381 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { "Size": 18289 @@ -89,7 +86,7 @@ "Size": 13596 }, "assemblies/Xamarin.AndroidX.RecyclerView.dll": { - "Size": 102349 + "Size": 102348 }, "assemblies/Xamarin.AndroidX.SavedState.dll": { "Size": 6294 @@ -113,10 +110,10 @@ "Size": 55807 }, "assemblies/Xamarin.Google.Android.Material.dll": { - "Size": 43514 + "Size": 43513 }, "classes.dex": { - "Size": 3533300 + "Size": 3533252 }, "lib/arm64-v8a/libmono-btls-shared.so": { "Size": 1613872 @@ -134,7 +131,7 @@ "Size": 66184 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 107144 + "Size": 107032 }, "META-INF/android.support.design_material.version": { "Size": 12 @@ -143,7 +140,7 @@ "Size": 1213 }, "META-INF/ANDROIDD.SF": { - "Size": 75981 + "Size": 75858 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -254,7 +251,7 @@ "Size": 10 }, "META-INF/MANIFEST.MF": { - "Size": 75854 + "Size": 75731 }, "META-INF/proguard/androidx-annotations.pro": { "Size": 339 @@ -1886,5 +1883,5 @@ "Size": 341040 } }, - "PackageSize": 9672959 + "PackageSize": 9537694 } \ No newline at end of file From b0f76b6b09492ff879a3020b76f1c51ddc1076ed Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 9 Dec 2022 13:03:18 +0000 Subject: [PATCH 06/18] Update Unit Test feed --- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 53188b11db7..a6d6b3e3513 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -707,7 +707,7 @@ public void RunWithLLVMEnabled () } [Test] - public void ResourceDesignerWithNuGetReference ([Values ("net6.0-android32.0", "net7.0-android33.0")] string dotnetTargetFramework) + public void ResourceDesignerWithNuGetReference ([Values ("net6.0-android32.0", "net7.0-android33.0", "net8.0-android33.0")] string dotnetTargetFramework) { AssertHasDevices (); @@ -725,6 +725,7 @@ public void ResourceDesignerWithNuGetReference ([Values ("net6.0-android32.0", " // Projects targeting net6.0 require ref/runtime packs on NuGet.org "https://api.nuget.org/v3/index.json", "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json", + "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json", }, }; nuget.Sources.Clear (); From ab03d41d94866cfb4acd81a44efb1a77f375255f Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 9 Dec 2022 14:53:50 +0000 Subject: [PATCH 07/18] use AddNuGetSourcesForOlderTargetFrameworks --- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index a6d6b3e3513..956edc36bdf 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -721,13 +721,8 @@ public void ResourceDesignerWithNuGetReference ([Values ("net6.0-android32.0", " Sdk = "Xamarin.Legacy.Sdk/0.2.0-alpha2", ProjectName = "Test.Nuget.Package", IsRelease = true, - ExtraNuGetConfigSources = { - // Projects targeting net6.0 require ref/runtime packs on NuGet.org - "https://api.nuget.org/v3/index.json", - "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json", - "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json", - }, }; + nuget.AddNuGetSourcesForOlderTargetFrameworks (); nuget.Sources.Clear (); nuget.Sources.Add (new AndroidItem.AndroidResource ("Resources/values/Strings.xml") { TextContent = () => @" From 817016e16948fe554f6a7f31afba5e58c9377e3e Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 9 Dec 2022 17:08:15 +0000 Subject: [PATCH 08/18] Test .net8 --- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 956edc36bdf..7f780147517 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -707,7 +707,7 @@ public void RunWithLLVMEnabled () } [Test] - public void ResourceDesignerWithNuGetReference ([Values ("net6.0-android32.0", "net7.0-android33.0", "net8.0-android33.0")] string dotnetTargetFramework) + public void ResourceDesignerWithNuGetReference ([Values ("net8.0-android33.0")] string dotnetTargetFramework) { AssertHasDevices (); From 5e2d6bbe022eb4fb57597875c31f19649af0631b Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 14 Dec 2022 20:26:23 +0000 Subject: [PATCH 09/18] fix merge conflicts --- .../Properties/Resources.Designer.cs | 18 +++++++++--------- .../Properties/Resources.resx | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index 05f4c4e0c4c..c87254b93ce 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -728,15 +728,6 @@ public static string XA1028 { } } - /// - /// Looks up a localized string similar to The 'AndroidEnableProguard' MSBuild property is set to 'true' and the 'AndroidLinkTool' MSBuild property is empty, so 'AndroidLinkTool' will default to 'proguard'.. - /// - public static string XA1031 { - get { - return ResourceManager.GetString("XA1031", resourceCulture); - } - } - /// /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in Xamarin.Android once .NET 6 is released.. /// @@ -1476,5 +1467,14 @@ public static string XA1033 { return ResourceManager.GetString("XA1033", resourceCulture); } } + + /// + /// Looks up a localized string similar to Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file. + /// + public static string XA1034 { + get { + return ResourceManager.GetString("XA1034", resourceCulture); + } + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index a526aa6c63b..c36b272704b 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -487,6 +487,7 @@ Please change the value to an assembly-qualifed type name which inherits from '{ Could not resolve '{0}'. Please check your `AndroidHttpClientHandlerType` setting. The following are literal names and should not be translated: 'AndroidHttpClientHandlerType', {0} - The value of the property. + Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file. The following are literal names and should not be translated: '_Microsoft.Android.Resource.Desinger', 'AndroidUseDesignerAssembly', 'true' From b080be042136d7ab80f265635f18bf1cb167fb17 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 14 Dec 2022 23:48:05 +0000 Subject: [PATCH 10/18] Change to XA1034 --- .../guides/building-apps/build-properties.md | 2 +- Documentation/guides/messages/xa1034.md | 16 ++++++++++++++++ .../Xamarin.Android.Resource.Designer.targets | 4 ++-- .../AndroidUpdateResourcesTest.cs | 4 ++-- 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 Documentation/guides/messages/xa1034.md diff --git a/Documentation/guides/building-apps/build-properties.md b/Documentation/guides/building-apps/build-properties.md index 72b17d2806d..1cfab5a9e06 100644 --- a/Documentation/guides/building-apps/build-properties.md +++ b/Documentation/guides/building-apps/build-properties.md @@ -1388,7 +1388,7 @@ net7.0-android have been deprecated. .NET 8 Projects which choose to turn this setting off will not be able to consume references which do use it. If you try to use an assembly which does have this feature enabled in a project that does not, you will -get a `XA1031` build error. +get a `XA1034` build error. Added in .NET 8. Unsupported in Classic Xamarin.Android. diff --git a/Documentation/guides/messages/xa1034.md b/Documentation/guides/messages/xa1034.md new file mode 100644 index 00000000000..be1bffd43e7 --- /dev/null +++ b/Documentation/guides/messages/xa1034.md @@ -0,0 +1,16 @@ +--- +title: Xamarin.Android error XA1034 +description: XA1034 error code +ms.date: 13/12/2022 +--- +# Xamarin.Android error XA1034 + +## Example messages + +``` +Your project references 'Foo.dll' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file. +``` + +## Solution + +Edit your csproj directly and change the 'AndroidUseDesignerAssembly' to `True`. \ No newline at end of file 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 95e7d80efd3..8530f437915 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 @@ -153,8 +153,8 @@ Copyright (C) 2016 Xamarin. All rights reserved. <_ErrorItems Include="@(_MonoAndroidReferencePath)" Condition=" '%(_MonoAndroidReferencePath.HasResourceDesignerAssemblyReference)' == 'True' "/> <_ErrorItems Include="@(_MonoAndroidReferenceDependencyPaths)" Condition=" '%(_MonoAndroidReferenceDependencyPaths.HasResourceDesignerAssemblyReference)' == 'True' "/> - diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index 00add1baf48..35b5bf82aed 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -651,7 +651,7 @@ public void CheckOldResourceDesignerWithWrongCasingIsRemoved ([Values (true, fal } [Test] - public void CheckThatXA1031IsRaisedForInvalidConfiguration ([Values (true, false)] bool isRelease) + public void CheckThatXA1034IsRaisedForInvalidConfiguration ([Values (true, false)] bool isRelease) { if (!Builder.UseDotNet) Assert.Ignore ("Test uses designer assembly which does not work on Legacy projects."); @@ -688,7 +688,7 @@ public static string GetFoo () { using (var pb = CreateApkBuilder (Path.Combine (path, proj.ProjectName))) { pb.ThrowOnBuildFailure = false; Assert.IsFalse (pb.Build (proj), "Application project build should have failed."); - StringAssertEx.ContainsText (pb.LastBuildOutput, "XA1031: "); + StringAssertEx.ContainsText (pb.LastBuildOutput, "XA1034: "); StringAssertEx.ContainsText (pb.LastBuildOutput, "1 Error(s)"); } } From d669fd66d016c6d7ce1cfa21d0c1c4e2397a65d8 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Dec 2022 16:51:04 +0000 Subject: [PATCH 11/18] Update based on feedback --- Documentation/guides/building-apps/build-properties.md | 3 ++- .../Android/Xamarin.Android.Resource.Designer.targets | 7 ------- src/Xamarin.Android.Build.Tasks/Tasks/FilterAssemblies.cs | 4 +--- .../Tasks/GenerateResourceDesignerAssembly.cs | 4 ++-- .../Utilities/FileResourceParser.cs | 2 +- .../Utilities/ManagedResourceParser.cs | 4 ++-- .../Utilities/ResourceParser.cs | 6 ------ src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs | 2 ++ src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs | 6 +++--- 9 files changed, 13 insertions(+), 25 deletions(-) diff --git a/Documentation/guides/building-apps/build-properties.md b/Documentation/guides/building-apps/build-properties.md index 1cfab5a9e06..113c87c3635 100644 --- a/Documentation/guides/building-apps/build-properties.md +++ b/Documentation/guides/building-apps/build-properties.md @@ -1376,7 +1376,8 @@ This setting is not backward compatible with Classic Xamarin.Android. As a Nuget Author it is recommended that you ship three versions of the assembly if you want to maintain backward compatibility. One for MonoAndroid, one for net6.0-android and -one for net8.0-android. You can do this by using [Xamarin.Legacy.Sdk](https://www.nuget.org/packages/Xamarin.Legacy.Sdk). +one for net8.0-android. You can do this by using [Xamarin.Legacy.Sdk](https://www.nuget.org/packages/Xamarin.Legacy.Sdk). This is only required if your Nuget Library +project makes use of `AndroidResource` items in the project or via a dependency. ``` monoandroid90;net6.0-android;net8.0-android 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 8530f437915..de36c90ea4b 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 @@ -91,13 +91,6 @@ Copyright (C) 2016 Xamarin. All rights reserved. - Parse (string resourceDirectory, IEnumerable additionalR if (!resources.ContainsKey(t)) { continue; } - if (resources[t].Count () == 0) { + if (resources[t].Count == 0) { continue; } foreach (R r in resources[t].OrderBy(x => x.ToSortedString(), StringComparer.Ordinal)) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs index bcb01245334..07c4b1537c5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs @@ -377,7 +377,7 @@ void CreateField (CodeTypeDeclaration parentType, string name, Type type) CodeMemberField CreateIntField (CodeTypeDeclaration parentType, string name, int value = -1) { - string mappedName = GetResourceName (parentType.Name, name, map); + string mappedName = ResourceIdentifier.GetResourceName (parentType.Name, name, map, Log); CodeMemberField f = (CodeMemberField)parentType.Members.OfType ().FirstOrDefault (x => string.Compare (x.Name, mappedName, StringComparison.Ordinal) == 0); if (f != null) return f; @@ -397,7 +397,7 @@ CodeMemberField CreateIntField (CodeTypeDeclaration parentType, string name, int CodeMemberField CreateIntArrayField (CodeTypeDeclaration parentType, string name, int count, params int[] values) { - string mappedName = GetResourceName (parentType.Name, name, map); + string mappedName = ResourceIdentifier.GetResourceName (parentType.Name, name, map, Log); CodeMemberField f = (CodeMemberField)parentType.Members.OfType ().FirstOrDefault (x => string.Compare (x.Name, mappedName, StringComparison.Ordinal) == 0); if (f != null) return f; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs index 64cedf71129..3becd20d1ec 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs @@ -37,11 +37,5 @@ internal static string GetNestedTypeName (string name) default: return char.ToUpperInvariant (name[0]) + name.Substring (1); } } - - internal string GetResourceName (string type, string name, Dictionary map) - { - return ResourceIdentifier.GetResourceName (type, name, map, Log); - } - } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs index 6b3d1fd9470..644df0e2e31 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtParser.cs @@ -11,10 +11,12 @@ public enum RType { Integer, Array, } + public enum ResourceType { System, Custom, } + public struct R : IComparable { public RType Type; public int Id; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs index cc2e7a70991..5682af04139 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs @@ -13,11 +13,11 @@ namespace Xamarin.Android.Tasks public class RtxtWriter { public void Write (string file, IList items) { - var sb = new StringBuilder (); + using var sw = MemoryStreamPool.Shared.CreateStreamWriter (); foreach (var item in items) { - sb.AppendLine (item.ToString ()); + sw .WriteLine (item.ToString ()); } - Files.CopyIfStringChanged (sb.ToString (), file); + Files.CopyIfStreamChanged (sw.BaseStream, file); } } } From 6837c90a34b0ac1a99b10765d467d36f7467fc99 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Dec 2022 16:51:34 +0000 Subject: [PATCH 12/18] Back out some unit test changes --- .../Tests/Xamarin.Android.Build.Tests/AotTests.cs | 9 +++++---- .../Mono.Android-Test.Shared.projitems | 1 + tests/Mono.Android-Tests/Mono.Android-Tests.csproj | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index 6a8ccadba77..3f2ee58ed3a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -277,10 +277,11 @@ public void BuildAMassiveApp () IsRelease = true, }; if (Builder.UseDotNet) { - app1.PackageReferences.Clear (); - app1.PackageReferences.Add (KnownPackages.XamarinForms_5_0_0_2515); - app1.PackageReferences.Add (KnownPackages.XamarinFormsMaps_5_0_0_2515); - app1.PackageReferences.Add (KnownPackages.Xamarin_Build_Download_0_11_3); + //TODO Re-enable if this test fails. + // app1.PackageReferences.Clear (); + // app1.PackageReferences.Add (KnownPackages.XamarinForms_5_0_0_2515); + // app1.PackageReferences.Add (KnownPackages.XamarinFormsMaps_5_0_0_2515); + // app1.PackageReferences.Add (KnownPackages.Xamarin_Build_Download_0_11_3); } //NOTE: BuildingInsideVisualStudio prevents the projects from being built as dependencies diff --git a/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems b/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems index 185f6e9fe7c..052219da8fc 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems +++ b/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems @@ -14,6 +14,7 @@ + diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests.csproj b/tests/Mono.Android-Tests/Mono.Android-Tests.csproj index f976680d4e3..1d4a287f573 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Tests.csproj +++ b/tests/Mono.Android-Tests/Mono.Android-Tests.csproj @@ -29,7 +29,6 @@ <_ASANScript>..\..\build-tools\wrap.sh\asan.sh <_UBSANScript>..\..\build-tools\wrap.sh\ubsan.sh <_MonoAndroidTestPackage>Mono.Android_Tests - True From c9441127bde9d8d2a88590296b3114f11a9bfc46 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Dec 2022 17:10:45 +0000 Subject: [PATCH 13/18] Fix build error --- .../Utilities/JavaResourceParser.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs index bb705dfbcdd..bf92442a733 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs @@ -23,7 +23,7 @@ public CodeTypeDeclaration Parse (string file, bool isApp, Dictionary new { Match = p.Key.Match (line), Handler = p.Value }).FirstOrDefault (x => x.Match.Success); - + if (info == null) continue; @@ -84,7 +84,7 @@ public JavaResourceParser () Parse (@"^ public static final int ([^ =]+)\s*=\s*([^;]+);$", (m, app, g, map) => { var name = ((CodeTypeDeclaration) g.Members [g.Members.Count-1]).Name; - var f = new CodeMemberField (typeof (int), GetResourceName (name, m.Groups[1].Value, map)) { + var f = new CodeMemberField (typeof (int), ResourceIdentifier.GetResourceName (name, m.Groups[1].Value, map, Log)) { Attributes = app ? MemberAttributes.Const | MemberAttributes.Public : MemberAttributes.Static | MemberAttributes.Public, InitExpression = new CodePrimitiveExpression (ToInt32 (m.Groups [2].Value, m.Groups [2].Value.IndexOf ("0x", StringComparison.Ordinal) == 0 ? 16 : 10)), Comments = { @@ -97,7 +97,7 @@ public JavaResourceParser () Parse (@"^ public static final int\[\] ([^ =]+) = {", (m, app, g, map) => { var name = ((CodeTypeDeclaration) g.Members [g.Members.Count-1]).Name; - var f = new CodeMemberField (typeof (int[]), GetResourceName (name, m.Groups[1].Value, map)) { + var f = new CodeMemberField (typeof (int[]), ResourceIdentifier.GetResourceName (name, m.Groups[1].Value, map, Log)) { // pity I can't make the member readonly... Attributes = MemberAttributes.Public | MemberAttributes.Static, }; From f48c1f582302d98a3b5131656267d61046ac013b Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Sat, 17 Dec 2022 17:09:55 +0000 Subject: [PATCH 14/18] Use Flush to make sure we have data in the stream --- .../Utilities/RtxtWriter.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs index 5682af04139..eb3a8abf038 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/RtxtWriter.cs @@ -13,11 +13,13 @@ namespace Xamarin.Android.Tasks public class RtxtWriter { public void Write (string file, IList items) { - using var sw = MemoryStreamPool.Shared.CreateStreamWriter (); - foreach (var item in items) { - sw .WriteLine (item.ToString ()); + using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ()) { + foreach (var item in items) { + sw.WriteLine (item.ToString ()); + } + sw.Flush (); + Files.CopyIfStreamChanged (sw.BaseStream, file); } - Files.CopyIfStreamChanged (sw.BaseStream, file); } } } From ae51be4eec44ff034408ac83b3c1a3f3c28e479f Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Sun, 18 Dec 2022 23:42:16 +0000 Subject: [PATCH 15/18] Fix apkdesc --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 20 +++++++-------- .../BuildReleaseArm64SimpleLegacy.apkdesc | 6 ++--- .../BuildReleaseArm64XFormsDotNet.apkdesc | 18 ++++++------- .../BuildReleaseArm64XFormsLegacy.apkdesc | 25 +++++++++++-------- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index d747a184fe7..a0af2696b00 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -8,13 +8,13 @@ "Size": 1028 }, "assemblies/Java.Interop.dll": { - "Size": 58924 + "Size": 58926 }, "assemblies/Mono.Android.dll": { - "Size": 87710 + "Size": 87074 }, "assemblies/Mono.Android.Runtime.dll": { - "Size": 5924 + "Size": 5832 }, "assemblies/rc.bin": { "Size": 1182 @@ -26,16 +26,16 @@ "Size": 9253 }, "assemblies/System.Private.CoreLib.dll": { - "Size": 484001 + "Size": 483854 }, "assemblies/System.Runtime.dll": { - "Size": 2629 + "Size": 2608 }, "assemblies/System.Runtime.InteropServices.dll": { "Size": 2269 }, "assemblies/UnnamedProject.dll": { - "Size": 3628 + "Size": 3275 }, "classes.dex": { "Size": 19020 @@ -59,16 +59,16 @@ "Size": 150584 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 16632 + "Size": 16728 }, "META-INF/BNDLTOOL.RSA": { "Size": 1213 }, "META-INF/BNDLTOOL.SF": { - "Size": 2914 + "Size": 3037 }, "META-INF/MANIFEST.MF": { - "Size": 2787 + "Size": 2910 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -95,5 +95,5 @@ "Size": 1904 } }, - "PackageSize": 2603241 + "PackageSize": 2603338 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc index ff98f67fb80..4eb6fa09ccf 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc @@ -14,13 +14,13 @@ "Size": 769036 }, "assemblies/System.Core.dll": { - "Size": 28215 + "Size": 28216 }, "assemblies/System.dll": { - "Size": 9191 + "Size": 9192 }, "assemblies/UnnamedProject.dll": { - "Size": 2896 + "Size": 2894 }, "classes.dex": { "Size": 370828 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index 6ae5c9740f2..8134fd88f91 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -11,13 +11,13 @@ "Size": 7314 }, "assemblies/Java.Interop.dll": { - "Size": 66797 + "Size": 66801 }, "assemblies/Mono.Android.dll": { - "Size": 444767 + "Size": 444662 }, "assemblies/Mono.Android.Runtime.dll": { - "Size": 5924 + "Size": 5832 }, "assemblies/mscorlib.dll": { "Size": 3856 @@ -104,7 +104,7 @@ "Size": 16805 }, "assemblies/System.Runtime.dll": { - "Size": 2791 + "Size": 2756 }, "assemblies/System.Runtime.InteropServices.dll": { "Size": 2269 @@ -131,7 +131,7 @@ "Size": 1858 }, "assemblies/UnnamedProject.dll": { - "Size": 117399 + "Size": 5347 }, "assemblies/Xamarin.AndroidX.Activity.dll": { "Size": 5872 @@ -221,7 +221,7 @@ "Size": 150584 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 333632 + "Size": 333728 }, "META-INF/android.support.design_material.version": { "Size": 12 @@ -335,13 +335,13 @@ "Size": 1213 }, "META-INF/BNDLTOOL.SF": { - "Size": 79203 + "Size": 79326 }, "META-INF/com.google.android.material_material.version": { "Size": 10 }, "META-INF/MANIFEST.MF": { - "Size": 79076 + "Size": 79199 }, "META-INF/proguard/androidx-annotations.pro": { "Size": 339 @@ -1976,5 +1976,5 @@ "Size": 341228 } }, - "PackageSize": 7991971 + "PackageSize": 7803652 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc index 4a37d89eac4..0d28c81d989 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc @@ -4,6 +4,9 @@ "AndroidManifest.xml": { "Size": 3140 }, + "assemblies/_Microsoft.Android.Resource.Designer.dll": { + "Size": 119643 + }, "assemblies/FormsViewGroup.dll": { "Size": 7230 }, @@ -14,7 +17,7 @@ "Size": 572670 }, "assemblies/Mono.Security.dll": { - "Size": 68449 + "Size": 68450 }, "assemblies/mscorlib.dll": { "Size": 915425 @@ -44,7 +47,7 @@ "Size": 395668 }, "assemblies/UnnamedProject.dll": { - "Size": 116994 + "Size": 116997 }, "assemblies/Xamarin.AndroidX.Activity.dll": { "Size": 7711 @@ -56,7 +59,7 @@ "Size": 125346 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 7381 + "Size": 7380 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { "Size": 18289 @@ -65,7 +68,7 @@ "Size": 131944 }, "assemblies/Xamarin.AndroidX.DrawerLayout.dll": { - "Size": 15444 + "Size": 15443 }, "assemblies/Xamarin.AndroidX.Fragment.dll": { "Size": 43150 @@ -86,7 +89,7 @@ "Size": 13596 }, "assemblies/Xamarin.AndroidX.RecyclerView.dll": { - "Size": 102348 + "Size": 102349 }, "assemblies/Xamarin.AndroidX.SavedState.dll": { "Size": 6294 @@ -110,10 +113,10 @@ "Size": 55807 }, "assemblies/Xamarin.Google.Android.Material.dll": { - "Size": 43513 + "Size": 43514 }, "classes.dex": { - "Size": 3533252 + "Size": 3533300 }, "lib/arm64-v8a/libmono-btls-shared.so": { "Size": 1613872 @@ -131,7 +134,7 @@ "Size": 66184 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 107032 + "Size": 107160 }, "META-INF/android.support.design_material.version": { "Size": 12 @@ -140,7 +143,7 @@ "Size": 1213 }, "META-INF/ANDROIDD.SF": { - "Size": 75858 + "Size": 75981 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -251,7 +254,7 @@ "Size": 10 }, "META-INF/MANIFEST.MF": { - "Size": 75731 + "Size": 75854 }, "META-INF/proguard/androidx-annotations.pro": { "Size": 339 @@ -1883,5 +1886,5 @@ "Size": 341040 } }, - "PackageSize": 9537694 + "PackageSize": 9656575 } \ No newline at end of file From 94f399a9f644f0a6aa4231afc94adb2f1e9af757 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Sun, 18 Dec 2022 23:46:45 +0000 Subject: [PATCH 16/18] update apkdesc --- .../Base/BuildReleaseArm64SimpleDotNet.apkdesc | 2 +- .../Base/BuildReleaseArm64XFormsLegacy.apkdesc | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index a0af2696b00..fd5dea2cee2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -35,7 +35,7 @@ "Size": 2269 }, "assemblies/UnnamedProject.dll": { - "Size": 3275 + "Size": 3273 }, "classes.dex": { "Size": 19020 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc index 0d28c81d989..d2314748565 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc @@ -17,7 +17,7 @@ "Size": 572670 }, "assemblies/Mono.Security.dll": { - "Size": 68450 + "Size": 68449 }, "assemblies/mscorlib.dll": { "Size": 915425 @@ -32,7 +32,7 @@ "Size": 12370 }, "assemblies/System.Net.Http.dll": { - "Size": 110718 + "Size": 110717 }, "assemblies/System.Numerics.dll": { "Size": 15706 @@ -44,7 +44,7 @@ "Size": 26604 }, "assemblies/System.Xml.dll": { - "Size": 395668 + "Size": 395667 }, "assemblies/UnnamedProject.dll": { "Size": 116997 @@ -59,7 +59,7 @@ "Size": 125346 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 7380 + "Size": 7381 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { "Size": 18289 @@ -80,7 +80,7 @@ "Size": 7078 }, "assemblies/Xamarin.AndroidX.Lifecycle.LiveData.Core.dll": { - "Size": 7207 + "Size": 7208 }, "assemblies/Xamarin.AndroidX.Lifecycle.ViewModel.dll": { "Size": 4886 From ae8764cde37281fd93175060b85ff382ea47fb9a Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Mon, 19 Dec 2022 21:46:41 +0000 Subject: [PATCH 17/18] ff --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 4 ++-- .../BuildReleaseArm64SimpleLegacy.apkdesc | 2 +- .../BuildReleaseArm64XFormsDotNet.apkdesc | 2 +- .../BuildReleaseArm64XFormsLegacy.apkdesc | 21 ++++++++----------- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index fd5dea2cee2..f5a8ad55bfe 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -14,7 +14,7 @@ "Size": 87074 }, "assemblies/Mono.Android.Runtime.dll": { - "Size": 5832 + "Size": 5833 }, "assemblies/rc.bin": { "Size": 1182 @@ -35,7 +35,7 @@ "Size": 2269 }, "assemblies/UnnamedProject.dll": { - "Size": 3273 + "Size": 3276 }, "classes.dex": { "Size": 19020 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc index 4eb6fa09ccf..adfe30f0e3b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc @@ -20,7 +20,7 @@ "Size": 9192 }, "assemblies/UnnamedProject.dll": { - "Size": 2894 + "Size": 2897 }, "classes.dex": { "Size": 370828 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index 8134fd88f91..efc6347e949 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -17,7 +17,7 @@ "Size": 444662 }, "assemblies/Mono.Android.Runtime.dll": { - "Size": 5832 + "Size": 5833 }, "assemblies/mscorlib.dll": { "Size": 3856 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc index d2314748565..00393868d67 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc @@ -4,9 +4,6 @@ "AndroidManifest.xml": { "Size": 3140 }, - "assemblies/_Microsoft.Android.Resource.Designer.dll": { - "Size": 119643 - }, "assemblies/FormsViewGroup.dll": { "Size": 7230 }, @@ -32,7 +29,7 @@ "Size": 12370 }, "assemblies/System.Net.Http.dll": { - "Size": 110717 + "Size": 110718 }, "assemblies/System.Numerics.dll": { "Size": 15706 @@ -44,7 +41,7 @@ "Size": 26604 }, "assemblies/System.Xml.dll": { - "Size": 395667 + "Size": 395668 }, "assemblies/UnnamedProject.dll": { "Size": 116997 @@ -59,7 +56,7 @@ "Size": 125346 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 7381 + "Size": 7380 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { "Size": 18289 @@ -74,7 +71,7 @@ "Size": 43150 }, "assemblies/Xamarin.AndroidX.Legacy.Support.Core.UI.dll": { - "Size": 6728 + "Size": 6727 }, "assemblies/Xamarin.AndroidX.Lifecycle.Common.dll": { "Size": 7078 @@ -116,7 +113,7 @@ "Size": 43514 }, "classes.dex": { - "Size": 3533300 + "Size": 3533252 }, "lib/arm64-v8a/libmono-btls-shared.so": { "Size": 1613872 @@ -134,7 +131,7 @@ "Size": 66184 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 107160 + "Size": 107032 }, "META-INF/android.support.design_material.version": { "Size": 12 @@ -143,7 +140,7 @@ "Size": 1213 }, "META-INF/ANDROIDD.SF": { - "Size": 75981 + "Size": 75858 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -254,7 +251,7 @@ "Size": 10 }, "META-INF/MANIFEST.MF": { - "Size": 75854 + "Size": 75731 }, "META-INF/proguard/androidx-annotations.pro": { "Size": 339 @@ -1886,5 +1883,5 @@ "Size": 341040 } }, - "PackageSize": 9656575 + "PackageSize": 9537694 } \ No newline at end of file From a765beacc6c9f29597d75ed9dbe56529a9cdc478 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 4 Jan 2023 19:55:30 -0500 Subject: [PATCH 18/18] Fix indentation formatting --- .../Xamarin.Android.Resource.Designer.targets | 164 +++++++++--------- 1 file changed, 82 insertions(+), 82 deletions(-) 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 de36c90ea4b..8d19b2128da 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 @@ -60,16 +60,16 @@ Copyright (C) 2016 Xamarin. All rights reserved. Inputs="$(_AndroidResFlagFile);@(_AndroidResourceDest);@(LibraryResourceDirectories->'%(StampFile)')" Outputs="$(_DesignerIntermediateOutputPath)R.txt" > - - - + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - + + + + + - - <_ErrorItems Include="@(_MonoAndroidReferencePath)" Condition=" '%(_MonoAndroidReferencePath.HasResourceDesignerAssemblyReference)' == 'True' "/> - <_ErrorItems Include="@(_MonoAndroidReferenceDependencyPaths)" Condition=" '%(_MonoAndroidReferenceDependencyPaths.HasResourceDesignerAssemblyReference)' == 'True' "/> - - + + <_ErrorItems Include="@(_MonoAndroidReferencePath)" Condition=" '%(_MonoAndroidReferencePath.HasResourceDesignerAssemblyReference)' == 'True' "/> + <_ErrorItems Include="@(_MonoAndroidReferenceDependencyPaths)" Condition=" '%(_MonoAndroidReferenceDependencyPaths.HasResourceDesignerAssemblyReference)' == 'True' "/> + + @@ -168,17 +168,17 @@ Copyright (C) 2016 Xamarin. All rights reserved. Condition=" '$(AndroidUseDesignerAssembly)' == 'True' " DependsOnTargets="_SetupDesignerProperties" AfterTargets="GenerateGlobalUsings"> - - - PreserveNewest - - - - - - + + + PreserveNewest + + + + + +