diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets index 37a058a8ded..5d3ee2ba295 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets @@ -44,23 +44,31 @@ It is shared between "legacy" binding projects and .NET 5 projects. /> + + + <_LibrariesToBind Include="@(EmbeddedJar)" /> + <_LibrariesToBind Include="@(InputJar)" /> + <_LibrariesToBind Include="@(LibraryProjectZip)" /> + <_LibrariesToBind Include="@(_JavaBindingSource)" Condition=" '%(_JavaBindingSource.Bind)' == 'true' "/> + + + + Condition=" '@(_LibrariesToBind->Count())' != '0' "> <_AndroidGenerateManagedBindings>true - + <_GeneratedManagedBindingFiles Include="$(GeneratedOutputPath)**\*.cs" /> @@ -75,7 +83,6 @@ It is shared between "legacy" binding projects and .NET 5 projects. @@ -135,14 +142,17 @@ It is shared between "legacy" binding projects and .NET 5 projects. + + + + > true diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Javac.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Javac.targets index b932c578336..4c2a8ed5173 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Javac.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Javac.targets @@ -21,7 +21,9 @@ It is shared between "legacy" binding projects and .NET 7+ projects. <_AndroidIntermediateBindingClassesZip>$(IntermediateOutputPath)binding\bin\$(MSBuildProjectName).jar <_AndroidIntermediateBindingClassesDocs>$(IntermediateOutputPath)binding\bin\$(MSBuildProjectName)-docs.xml <_AndroidCompileJavaStampFile>$(_AndroidStampDirectory)_CompileJava.stamp + <_AndroidCompileJavaFileList>$(IntermediateOutputPath)_CompileJava.FileList.txt <_AndroidCompileBindingJavaStampFile>$(_AndroidStampDirectory)_CompileBindingJava.stamp + <_AndroidCompileBindingJavaFileList>$(IntermediateOutputPath)_CompileBindingJava.FileList.txt @@ -74,18 +76,36 @@ It is shared between "legacy" binding projects and .NET 7+ projects. <_JavaBindingSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' == 'True' " /> + + + + <_JavaSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' != 'True' " /> + + + + @@ -132,7 +152,7 @@ It is shared between "legacy" binding projects and .NET 7+ projects. 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 31c9442e8e9..df4dab646d8 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 @@ -120,9 +120,6 @@ properties that determine build ordering. UpdateAndroidResources; _BuildResourceDesigner; UpdateAndroidInterfaceProxies; - _SetAndroidGenerateManagedBindings; - _ClearGeneratedManagedBindings; - AddBindingsToCompile; _CheckForInvalidDesignerConfig; @@ -144,6 +141,13 @@ properties that determine build ordering. _AddAndroidDefines; _IncludeLayoutBindingSources; AddLibraryJarsToBind; + _CollectLibrariesToBind; + _SetAndroidGenerateManagedBindings; + ExportJarToXml; + GenerateBindings; + _CollectGeneratedManagedBindingFiles; + _ClearGeneratedManagedBindings; + AddBindingsToCompile; _BuildResourceDesigner; _AddResourceDesignerFiles; $(CompileDependsOn); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs index bb76b585a1d..15f04ccf5e6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs @@ -6,7 +6,9 @@ using System.Linq; using System.Xml; using System.Xml.Linq; +using System.Xml.XPath; using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; using Microsoft.Android.Build.Tasks; namespace Xamarin.Android.Tasks diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs index 58d8012352a..81acffd0fb1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs @@ -39,7 +39,7 @@ public void DotNetBuildBinding () proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javaclasses-sources.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar, }); - proj.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { + proj.AndroidJavaSources.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { Encoding = Encoding.ASCII, TextContent = () => ResourceData.JavaSourceTestExtension, Metadata = { { "Bind", "True"} }, @@ -75,6 +75,7 @@ public void BindingLibraryIncremental (string classParser) "_ResolveLibraryProjectImports", "CoreCompile", "_CreateAar", + "_ClearGeneratedManagedBindings", }; var proj = new XamarinAndroidBindingProject () { @@ -112,6 +113,23 @@ public void BindingLibraryIncremental (string classParser) foreach (var target in targets) { Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped on second build!"); } + + Assert.IsTrue (b.DesignTimeBuild (proj, target: "UpdateGeneratedFiles"), "DTB should have succeeded."); + var cs_file = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "generated", "src", "Com.Larvalabs.Svgandroid.SVGParser.cs"); + FileAssert.Exists (cs_file); + Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "third build should succeed"); + foreach (var target in targets) { + Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped on second build!"); + } + // Fast Update Check Build + Assert.IsTrue (b.DesignTimeBuild (proj, target: "PrepareResources;_GenerateCompileInputs"), "DTB should have succeeded."); + cs_file = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "generated", "src", "Com.Larvalabs.Svgandroid.SVGParser.cs"); + FileAssert.Exists (cs_file); + Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "forth build should succeed"); + foreach (var target in targets) { + Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped on second build!"); + } + } } @@ -671,6 +689,10 @@ public void BindingWithAndroidJavaSource () StringAssertEx.ContainsText (File.ReadAllLines (generatedIface), "string GreetWithQuestion (string name, global::Java.Util.Date date, string question);"); Assert.IsTrue (libBuilder.Build (lib), "Library build should have succeeded."); Assert.IsTrue (libBuilder.Output.IsTargetSkipped ("_CompileBindingJava"), $"`_CompileBindingJava` should be skipped on second build!"); + Assert.IsTrue (libBuilder.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings"), $"`_ClearGeneratedManagedBindings` should be skipped on second build!"); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on second build."); + Assert.IsTrue (libBuilder.DesignTimeBuild (lib, target: "UpdateGeneratedFiles"), "DTB should have succeeded."); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on DTB build."); Assert.IsTrue (appBuilder.Build (app), "App build should have succeeded."); appBuilder.Target = "SignAndroidPackage"; Assert.IsTrue (appBuilder.Build (app), "App SignAndroidPackage should have succeeded."); 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 b0b69ff759b..fce460a2c6d 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 @@ -70,7 +70,7 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javaclasses-sources.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar, }); - proj.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { + proj.AndroidJavaSources.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { Encoding = Encoding.ASCII, TextContent = () => ResourceData.JavaSourceTestExtension, Metadata = { { "Bind", "True"} }, @@ -1511,7 +1511,7 @@ public void BuildApplicationWithJavaSourceUsingAndroidX ([Values(true, false)] b { var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, - OtherBuildItems = { + AndroidJavaSources = { new BuildItem (AndroidBuildActions.AndroidJavaSource, "ToolbarEx.java") { TextContent = () => @"package com.unnamedproject.unnamedproject; import android.content.Context; @@ -1556,11 +1556,11 @@ public void BuildApplicationCheckThatAddStaticResourcesTargetDoesNotRerun () public void CheckJavaError () { var proj = new XamarinAndroidApplicationProject (); - proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe.java") { + proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe.java") { TextContent = () => "public classo TestMe { }", Encoding = Encoding.ASCII }); - proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe2.java") { + proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe2.java") { TextContent = () => "public class TestMe2 {" + "public vod Test ()" + "}", 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 8e625dc3ab7..83d47a85bdc 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 @@ -1000,14 +1000,14 @@ public void BuildProguardEnabledProject (string rid) XamarinAndroidApplicationProject CreateMultiDexRequiredApplication (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") { var proj = new XamarinAndroidApplicationProject (debugConfigurationName, releaseConfigurationName); - proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods.java") { + proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods.java") { TextContent = () => "public class ManyMethods { \n" + string.Join (Environment.NewLine, Enumerable.Range (0, 32768).Select (i => "public void method" + i + "() {}")) + "}", Encoding = Encoding.ASCII, Metadata = { { "Bind", "False "}}, }); - proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods2.java") { + proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods2.java") { TextContent = () => "public class ManyMethods2 { \n" + string.Join (Environment.NewLine, Enumerable.Range (0, 32768).Select (i => "public void method" + i + "() {}")) + "}", @@ -1064,8 +1064,8 @@ public void BuildAfterMultiDexIsNotRequired () } //Now build project again after it no longer requires multidex, remove the *HUGE* AndroidJavaSource build items - while (proj.OtherBuildItems.Count > 1) - proj.OtherBuildItems.RemoveAt (proj.OtherBuildItems.Count - 1); + while (proj.AndroidJavaSources.Count > 1) + proj.AndroidJavaSources.RemoveAt (proj.AndroidJavaSources.Count - 1); proj.SetProperty ("AndroidEnableMultiDex", "False"); Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true), "Build should have succeeded."); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildOutput.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildOutput.cs index 853003056f7..a5692e315ba 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildOutput.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildOutput.cs @@ -52,9 +52,9 @@ public List GetAssemblyMapCache () return File.ReadLines (path).ToList (); } - public bool IsTargetSkipped (string target) => IsTargetSkipped (Builder.LastBuildOutput, target); + public bool IsTargetSkipped (string target, bool defaultIfNotUsed = false) => IsTargetSkipped (Builder.LastBuildOutput, target, defaultIfNotUsed); - public static bool IsTargetSkipped (IEnumerable output, string target) + public static bool IsTargetSkipped (IEnumerable output, string target, bool defaultIfNotUsed = false) { bool found = false; foreach (var line in output) { @@ -69,7 +69,7 @@ public static bool IsTargetSkipped (IEnumerable output, string target) if (found) return true; } - return false; + return defaultIfNotUsed; } /// diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs index 32425e363c0..30ae44a3628 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetXamarinProject.cs @@ -17,10 +17,12 @@ protected DotNetXamarinProject (string debugConfigurationName = "Debug", string Sources = new List (); OtherBuildItems = new List (); + AndroidJavaSources = new List (); ItemGroupList.Add (References); ItemGroupList.Add (OtherBuildItems); ItemGroupList.Add (Sources); + ItemGroupList.Add (AndroidJavaSources); SetProperty ("RootNamespace", () => RootNamespace ?? ProjectName); SetProperty ("AssemblyName", () => AssemblyName ?? ProjectName); @@ -40,6 +42,7 @@ protected DotNetXamarinProject (string debugConfigurationName = "Debug", string public IList OtherBuildItems { get; private set; } public IList Sources { get; private set; } + public IList AndroidJavaSources { get; private set; } public IList ActiveConfigurationProperties { get { return IsRelease ? ReleaseProperties : DebugProperties; } diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs index 20f9de4f0e6..c7e625c0707 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs @@ -611,5 +611,73 @@ public void AdbTargetChangesAppBundle () var after = File.GetLastWriteTimeUtc (apkset); Assert.AreNotEqual (before, after, $"{apkset} should change!"); } + + [Test] + public void AppWithAndroidJavaSource () + { + var path = Path.Combine ("temp", TestName); + var itemToDelete = new AndroidItem.AndroidJavaSource ("TestJavaClass2.java") { + Encoding = Encoding.ASCII, + TextContent = () => @"package com.test.java; + +public class TestJavaClass2 { + + public String test(){ + + return ""Java is called""; + } +}", + Metadata = { + { "Bind", "True" }, + }, + }; + var proj = new XamarinAndroidApplicationProject { + EnableDefaultItems = true, + AndroidJavaSources = { + new AndroidItem.AndroidJavaSource ("TestJavaClass.java") { + Encoding = Encoding.ASCII, + TextContent = () => @"package com.test.java; + +public class TestJavaClass { + + public String test(){ + + return ""Java is called""; + } +}", + Metadata = { + { "Bind", "True" }, + }, + }, + itemToDelete, + }, + }; + using (var b = CreateApkBuilder ()) { + b.ThrowOnBuildFailure = false; + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + b.AssertHasNoWarnings (); + var generatedCode = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, + "generated", "src", "Com.Test.Java.TestJavaClass.cs"); + var generatedCode2 = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, + "generated", "src", "Com.Test.Java.TestJavaClass2.cs"); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have been generated."); + FileAssert.Exists (generatedCode2, $"'{generatedCode2}' should have been generated."); + Assert.IsTrue (b.DesignTimeBuild (proj, target: "UpdateGeneratedFiles"), "DTB should have succeeded."); + Assert.IsTrue (b.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings", defaultIfNotUsed: true), $"`_ClearGeneratedManagedBindings` should be skipped on DTB build!"); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on DTB build."); + FileAssert.Exists (generatedCode2, $"'{generatedCode2}' should have not be deleted on DTB build."); + proj.AndroidJavaSources.Remove (itemToDelete); + File.Delete (Path.Combine (Root, b.ProjectDirectory, itemToDelete.Include ())); + Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "Second build should have succeeded."); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on second build."); + FileAssert.DoesNotExist (generatedCode2, $"'{generatedCode2}' should have be deleted on second build."); + Assert.IsFalse (b.Output.IsTargetSkipped ("_CompileBindingJava"), $"`_CompileBindingJava` should run on second build!"); + Assert.IsTrue (b.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings"), $"`_ClearGeneratedManagedBindings` should be skipped on second build!"); + // Call Install directly so Build does not get called automatically + Assert.IsTrue (b.RunTarget (proj, "Install", doNotCleanupOnUpdate: true, saveProject: false), "Install build should have succeeded."); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have not be deleted on Install build."); + Assert.IsTrue (b.Output.IsTargetSkipped ("_ClearGeneratedManagedBindings", defaultIfNotUsed: true), $"`_ClearGeneratedManagedBindings` should be skipped on Install build!"); + } + } } }