diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets index 4e1b6e05063..5a9e9a29c69 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.ClassParse.targets @@ -31,7 +31,7 @@ This file is only used by binding projects. @@ -50,7 +50,7 @@ This file is only used by binding projects. - + @@ -114,7 +114,6 @@ It is shared between "legacy" binding projects and .NET 7+ projects. Condition=" '@(_JavaBindingSource->Count())' != '0' " JavaPlatformJarPath="$(JavaPlatformJarPath)" ClassesOutputDirectory="$(_AndroidIntermediateBindingJavaClassDirectory)" - ClassesZip="$(_AndroidIntermediateBindingClassesZip)" StubSourceDirectory="$(_AndroidIntermediateBindingJavaSourceDirectory)" JavaSourceFiles="@(_JavaBindingSource)" ToolPath="$(JavacToolPath)" @@ -126,6 +125,12 @@ It is shared between "legacy" binding projects and .NET 7+ projects. IntermediateOutputPath="$(IntermediateOutputPath)" AssemblyIdentityMapFile="$(_AndroidLibrayProjectAssemblyMapFile)" /> + + <_JavaBindingClassDirectory + Condition=" '$(AndroidApplication)' == 'true' and '$(AndroidClassParser)' != 'jar2xml' " + Include="$(_AndroidIntermediateBindingJavaClassDirectory)" + /> + <_JavaBindingClassFile + Condition=" '$(AndroidApplication)' == 'true' and '$(AndroidClassParser)' != 'jar2xml' " + Include="$(_AndroidIntermediateBindingJavaClassDirectory)**\*.class" + /> @@ -154,21 +167,19 @@ It is shared between "legacy" binding projects and .NET 7+ projects. Inputs="@(_AndroidMSBuildAllProjects);$(_AndroidCompileJavaFileList);$(MonoPlatformJarPath);@(_JavaStubFiles);@(_JavaSource)" Outputs="$(_AndroidCompileJavaStampFile)"> - + - (); + // --lib and program inputs + var inputs = new List (); var libjars = new List (); + if (ClassFiles != null) { + foreach (var classFile in ClassFiles) { + inputs.Add (classFile.ItemSpec); + } + } if (AlternativeJarLibrariesToEmbed?.Length > 0) { Log.LogDebugMessage (" processing AlternativeJarLibrariesToEmbed..."); foreach (var jar in AlternativeJarLibrariesToEmbed) { - injars.Add (jar.ItemSpec); + inputs.Add (jar.ItemSpec); } } else if (JavaLibrariesToEmbed != null) { - Log.LogDebugMessage (" processing ClassesZip, JavaLibrariesToEmbed..."); - if (!ClassesZip.IsNullOrEmpty () && File.Exists (ClassesZip)) { - injars.Add (ClassesZip); - } + Log.LogDebugMessage (" processing JavaLibrariesToEmbed..."); foreach (var jar in JavaLibrariesToEmbed) { - injars.Add (jar.ItemSpec); + inputs.Add (jar.ItemSpec); } } libjars.Add (JavaPlatformJarPath); @@ -163,8 +165,8 @@ protected virtual string CreateResponseFile () WriteArg (response, "--lib"); WriteArg (response, jar); } - foreach (var jar in injars) { - WriteArg (response, jar); + foreach (var input in inputs) { + WriteArg (response, input); } return responseFile; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs index 4dfbfa17629..abcef357f1a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs @@ -9,7 +9,6 @@ using Microsoft.Build.Utilities; using System.Text; using System.Collections.Generic; -using Xamarin.Tools.Zip; using Xamarin.Android.Tools; using Microsoft.Android.Build.Tasks; @@ -22,8 +21,6 @@ public class Javac : JavaCompileToolTask [Required] public string ClassesOutputDirectory { get; set; } = ""; - public string? ClassesZip { get; set; } - public string? JavaPlatformJarPath { get; set; } public string? JavacTargetVersion { get; set; } @@ -37,17 +34,7 @@ public override bool RunTask () { if (!Directory.Exists (ClassesOutputDirectory)) Directory.CreateDirectory (ClassesOutputDirectory); - var result = base.RunTask (); - if (!result) - return result; - // compress all the class files - if (!ClassesZip.IsNullOrEmpty ()) { - using (var zip = new ZipArchiveEx (ClassesZip, FileMode.OpenOrCreate)) { - zip.AutoFlush = false; - zip.AddDirectory (ClassesOutputDirectory, "", CompressionMethod.Store); - } - } - return result; + return base.RunTask (); } protected override string GenerateCommandLineCommands () 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 63a575f42a2..5025442ac33 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 @@ -2152,9 +2152,23 @@ public static Toolbar GetToolbar (Context context) { } } ", - Encoding = Encoding.ASCII + Encoding = Encoding.ASCII, + Metadata = { { "Bind", "True" } }, }, - } + }, + Sources = { + new BuildItem.Source ("UseToolbarEx.cs") { + TextContent = () => """ +using Android.Content; + +class UseToolbarEx +{ + public AndroidX.AppCompat.Widget.Toolbar GetToolbar (Context context) => + Com.Unnamedproject.Unnamedproject.ToolbarEx.GetToolbar (context); +} +""", + }, + }, }; proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.AndroidXAppCompat); @@ -2162,6 +2176,14 @@ public static Toolbar GetToolbar (Context context) { b.ThrowOnBuildFailure = false; Assert.IsTrue (b.Build (proj), "Build should have succeeded"); + var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); + var bindingJar = Path.Combine (intermediate, "binding", "bin", $"{proj.ProjectName}.jar"); + FileAssert.DoesNotExist (bindingJar, "Application builds should pass bound Java class files directly to D8/R8."); + var dexFile = Path.Combine (intermediate, "android", "bin", "classes.dex"); + FileAssert.Exists (dexFile); + Assert.IsTrue (DexUtils.ContainsClass ("Lcom/unnamedproject/unnamedproject/ToolbarEx;", dexFile, AndroidSdkPath), + $"`{dexFile}` should contain the bound Java source."); + Assert.IsTrue (b.Clean (proj), "Clean should have succeeded."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 48cd2eb9d58..cc229e477b4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -1432,35 +1432,30 @@ public void BuildIncrementingClassName ([Values (AndroidRuntime.CoreCLR, Android using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - var classesZipPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "classes.zip"); - FileAssert.Exists (classesZipPath); - var expectedBuilder = new StringBuilder (); - using (var zip = ZipHelper.OpenZip (classesZipPath)) { - foreach (var file in zip) { - expectedBuilder.AppendLine (file.FullName); - } - } - var expectedZip = expectedBuilder.ToString (); + var classesDirectory = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "classes"); + DirectoryAssert.Exists (classesDirectory); + var expectedClasses = Directory.GetFiles (classesDirectory, "*.class", SearchOption.AllDirectories) + .Select (path => Path.GetRelativePath (classesDirectory, path)) + .OrderBy (path => path) + .ToArray (); + Assert.IsNotEmpty (expectedClasses); source.Timestamp = null; //Force the file to re-save w/ new Timestamp Assert.IsTrue (b.Build (proj), "Second build should have succeeded."); - var actualBuilder = new StringBuilder (); - using (var zip = ZipHelper.OpenZip (classesZipPath)) { - foreach (var file in zip) { - actualBuilder.AppendLine (file.FullName); - } - } - var actualZip = actualBuilder.ToString (); - Assert.AreNotEqual (expectedZip, actualZip); + var actualClasses = Directory.GetFiles (classesDirectory, "*.class", SearchOption.AllDirectories) + .Select (path => Path.GetRelativePath (classesDirectory, path)) + .OrderBy (path => path) + .ToArray (); + CollectionAssert.AreNotEqual (expectedClasses, actualClasses); //Build with no changes Assert.IsTrue (b.Build (proj), "Third build should have succeeded."); - FileAssert.Exists (classesZipPath); + DirectoryAssert.Exists (classesDirectory); //Clean Assert.IsTrue (b.Clean (proj), "Clean should have succeeded."); - FileAssert.DoesNotExist (classesZipPath); + DirectoryAssert.DoesNotExist (classesDirectory); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/D8Tests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/D8Tests.cs index 7ed141a91f0..5146ab04bde 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/D8Tests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/D8Tests.cs @@ -46,10 +46,12 @@ public void ResponseFileContainsLibAndInputJars () var inputJar1 = Path.Combine (tempDir, "input1.jar"); var inputJar2 = Path.Combine (tempDir, "input2.jar"); var libJar1 = Path.Combine (tempDir, "lib1.jar"); + var classFile = Path.Combine (tempDir, "Example.class"); File.WriteAllText (platformJar, "mock"); File.WriteAllText (inputJar1, "mock"); File.WriteAllText (inputJar2, "mock"); File.WriteAllText (libJar1, "mock"); + File.WriteAllText (classFile, "mock"); var d8Task = new D8TestTask { BuildEngine = engine, @@ -60,6 +62,9 @@ public void ResponseFileContainsLibAndInputJars () new TaskItem (inputJar1), new TaskItem (inputJar2), }, + ClassFiles = new ITaskItem [] { + new TaskItem (classFile), + }, JavaLibrariesToReference = new ITaskItem [] { new TaskItem (libJar1), }, @@ -87,6 +92,7 @@ public void ResponseFileContainsLibAndInputJars () // Should contain input jars as direct arguments (no --lib prefix) Assert.IsTrue (responseFileContent.Any (line => line.Contains ("input1.jar")), "Response file should contain input1.jar"); Assert.IsTrue (responseFileContent.Any (line => line.Contains ("input2.jar")), "Response file should contain input2.jar"); + Assert.IsTrue (responseFileContent.Any (line => line.Contains ("Example.class")), "Response file should contain class files"); } finally { // Clean up response file diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 57fa1a57afc..3be0e3b6793 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -921,7 +921,6 @@ because xbuild doesn't support framework reference assemblies. <_AndroidIntermediateJavaSourceDirectory>$(IntermediateOutputPath)android\src\ <_AndroidIntermediateDexOutputDirectory>$(IntermediateOutputPath)android\bin\ <_AndroidIntermediateJavaClassDirectory>$(IntermediateOutputPath)android\bin\classes\ - <_AndroidIntermediateClassesZip>$(IntermediateOutputPath)android\bin\classes.zip <_AndroidAotBinDirectory>$(IntermediateOutputPath)aot <_AndroidResgenFlagFile>$(IntermediateOutputPath)R.cs.flag <_AndroidResFlagFile>$(IntermediateOutputPath)res.flag @@ -1968,8 +1967,9 @@ because xbuild doesn't support framework reference assemblies. <_CompileToDalvikInputs> @(_AndroidMSBuildAllProjects) ;@(_JavaLibrariesToCompileForApp) + ;@(_JavaBindingClassFile) ;@(AndroidExternalJavaLibrary) - ;$(_AndroidIntermediateClassesZip) + ;$(_AndroidCompileJavaStampFile) ;@(ProguardConfiguration) ;@(MultiDexMainDexList) ;$(_AndroidBuildPropertiesCache) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.D8.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.D8.targets index f66903d0449..9690a9ebf57 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.D8.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.D8.targets @@ -51,6 +51,8 @@ Copyright (C) 2018 Xamarin. All rights reserved. <_AndroidD8MapDiagnostics Condition=" '$(AndroidD8IgnoreWarnings)' == 'true' " Include="warning" To="info" /> <_AndroidR8MapDiagnostics Condition=" '$(AndroidR8IgnoreWarnings)' == 'true' " Include="warning" To="info" /> + <_JavaClassFile Include="$(_AndroidIntermediateJavaClassDirectory)**\*.class" /> + <_JavaClassFile Include="@(_JavaBindingClassFile)" /> <_R8KeepJavaSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' != 'True' " /> @@ -66,7 +68,7 @@ Copyright (C) 2018 Xamarin. All rights reserved. OutputDirectory="$(_AndroidIntermediateDexOutputDirectory)" Debug="$(AndroidIncludeDebugSymbols)" JavaPlatformJarPath="$(JavaPlatformJarPath)" - ClassesZip="$(_AndroidIntermediateClassesZip)" + ClassFiles="@(_JavaClassFile)" JavaLibrariesToEmbed="@(_JavaLibrariesToCompileForApp);" JavaLibrariesToReference="@(AndroidExternalJavaLibrary)" EnableDesugar="$(AndroidEnableDesugar)" @@ -99,7 +101,7 @@ Copyright (C) 2018 Xamarin. All rights reserved. OutputDirectory="$(_AndroidIntermediateDexOutputDirectory)" Debug="$(AndroidIncludeDebugSymbols)" JavaPlatformJarPath="$(JavaPlatformJarPath)" - ClassesZip="$(_AndroidIntermediateClassesZip)" + ClassFiles="@(_JavaClassFile)" JavaLibrariesToEmbed="@(_JavaLibrariesToCompileForApp)" AlternativeJarLibrariesToEmbed="@(_AlternativeJarForAppD8)" JavaLibrariesToReference="@(AndroidExternalJavaLibrary)"