diff --git a/.vscode/settings.json b/.vscode/settings.json index 86dd807da21..a500d3e01c7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,6 @@ { "nxunitExplorer.modules": [ - "bin/TestDebug/MSBuildDeviceIntegration/net472/MSBuildDeviceIntegration.dll", - "bin/TestDebug/net472/Xamarin.Android.Build.Tests.dll", - "bin/TestRelease/MSBuildDeviceIntegration/net472/MSBuildDeviceIntegration.dll", + "bin/Test*/**/net472/*.dll", ], "cmake.configureOnOpen": false, "dotnetCoreExplorer.searchpatterns": "bin/Test{Debug,Release}/**/net6.0/{Xamarin.Android.Build.Tests,MSBuildDeviceIntegration}.dll", diff --git a/Documentation/guides/BindingJavaSource.md b/Documentation/guides/BindingJavaSource.md new file mode 100644 index 00000000000..bff7f06cb93 --- /dev/null +++ b/Documentation/guides/BindingJavaSource.md @@ -0,0 +1,103 @@ +--- +id: +title: "Binding Java Source" +dateupdated: 2021-05-21 +--- + +# Overview + +With .net 6 Bindings can be done on not only `.jar` and `.aar` files +but also raw `.java` code. This will allow developers of bindings +or applications to write custom API's for underlying bindings +and expose them easily to the developer. + +Applications already had the ability to include +[`AndroidJavaSource`](https://docs.microsoft.com/en-us/xamarin/android/deploy-test/building-apps/build-items#androidjavasource) +items in them, these would then be compiled into the final `classes.dex`. +However this custom java source code was not "bound" and if users wanted +to call these classes they would need to do that manually. + +Starting with .NET 7, all `*.java` files within the project directory are +automatically added to the `AndroidJavaSource` item group. Additionally, +`AndroidJavaSource` now supports `Bind` item metadata. This will instruct +the build system to not only compile the code but also produce a C# API for it. + +The `%(Bind)` attribute metadata is `True` by default. If you do not want +to bind the Java code, set `%(Bind)` to `False`. + +```xml + + + +``` + +# Example + +Consider the following Java code. + +```java +package com.xamarin.test; + +class MyClass { + public boolean isDave (String name) + { + return name.equals ("Dave"); + } +} +``` + +We want to bind this into a C# API in our app project. By default +the app project will pick up ALL `.java` files and add them to +the `AndroidJavaSource` ItemGroup. The `Bind` attribute is `true` +by default as well so it will be automatically bound. + +```xml + +``` + +When we build the app, the java code will be compiled into a +`.jar` file which matches the application project name. +This `.jar` will then be bound and the generated C# API will end +up being something like this. + +```csharp +using System; + +namespace Com.Xamarin.Test { + public class MyClass : Java.Lang.Object { + public virtual bool IsDave (string name) => …; + } +} +``` + +All this will happen before the main C# code is compiled. The binding +code will be included in the C# compile process, so you can use the +code directly in your app. + +```csharp +public class MainActivity : Activity { + public override void OnCreate() + { + var c = new MyClass (); + c.IsDave ("Bob"); + } +} +``` + + +# Limitations + +This feature is only available in .NET 7. + +You will be limited to standard java types and any types that +are available in a `.jar` or `.aar` which you reference. + +You *should not* use Java Generics. The Binding process currently does not +really support Java Generic very well. Stick to primitive types +or normal classes as much as possible, so that you don't need to use +[`metadata.xml`](https://docs.microsoft.com/en-us/xamarin/android/platform/binding-java-library/customizing-bindings/java-bindings-metadata) +to alter the API of the Java class. + +Because of the point at which the Java compilation happens +(before the `` task), you will not be able to access any of the +`R.*` Resource types either. This may be addressed in a later release. diff --git a/Documentation/guides/building-apps/build-items.md b/Documentation/guides/building-apps/build-items.md index 837487ea0f6..44b37c48a2a 100644 --- a/Documentation/guides/building-apps/build-items.md +++ b/Documentation/guides/building-apps/build-items.md @@ -6,7 +6,7 @@ ms.assetid: 5EBEE1A5-3879-45DD-B1DE-5CD4327C2656 ms.technology: xamarin-android author: jonpryor ms.author: jopryo -ms.date: 03/29/2022 +ms.date: 05/11/2022 --- # Build Items @@ -89,6 +89,13 @@ package. Files with a Build action of `AndroidJavaSource` are Java source code which will be included in the final Android package. +Starting with .NET 7, all `**\*.java` files within the project directory +automatically have a Build action of `AndroidJavaSource`, *and* will be +bound prior to the Assembly build. This allows C# code to easily use +types and members present within the `**\*.java` files. + +Set `%(AndroidJavaSource.Bind)` to False to disable this behavior. + ## AndroidLibrary **AndroidLibrary** is a new build action for simplifying how diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index b0ce8279e3a..3a18d226aa9 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -288,6 +288,7 @@ <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.DX.targets" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.EmbeddedResource.targets" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.FSharp.targets" ExcludeFromAndroidNETSdk="true" /> + <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.Javac.targets" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.Legacy.targets" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.PCLSupport.props" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Xamarin.Android.PCLSupport.targets" ExcludeFromAndroidNETSdk="true" /> diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.AvailableItems.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.AvailableItems.targets index 4d11ec2c80d..3e63db73393 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.AvailableItems.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.AvailableItems.targets @@ -66,6 +66,9 @@ This item group populates the Build Action drop-down in IDEs. true true + + true + true 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 de37de3657f..e0f1240f3d1 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 @@ -52,7 +52,7 @@ This file is only used by binding projects. - + $(IntermediateOutputPath)generated\ intellisense $(IntermediateOutputPath)api.xml - <_GeneratorStampFile>$(IntermediateOutputPath)generator.stamp + <_GeneratorStampFile>$(_AndroidStampDirectory)generator.stamp @@ -29,7 +29,7 @@ It is shared between "legacy" binding projects and .NET 5 projects. + Condition=" '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' Or '@(LibraryProjectZip->Count())' != '0' Or '@(_JavaBindingSource->Count())' != '0' "> <_AndroidGenerateManagedBindings>true @@ -115,15 +115,17 @@ It is shared between "legacy" binding projects and .NET 5 projects. + - + - + + 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 new file mode 100644 index 00000000000..75b68300b74 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Javac.targets @@ -0,0 +1,141 @@ + + + + + + + + + + <_AndroidIntermediateBindingJavaClassDirectory>$(IntermediateOutputPath)binding\bin\classes\ + <_AndroidIntermediateBindingJavaSourceDirectory>$(IntermediateOutputPath)binding\src + <_AndroidIntermediateBindingClassesZip>$(IntermediateOutputPath)binding\bin\$(MSBuildProjectName).jar + <_AndroidCompileJavaStampFile>$(_AndroidStampDirectory)_CompileJava.stamp + <_AndroidCompileBindingJavaStampFile>$(_AndroidStampDirectory)_CompileBindingJava.stamp + + + + + + + + + + + + + + + + + + + + + + + + + <_JavaLibrariesToCompileForApp Include="@(_JavaLibrariesToCompile)" Condition=" '$(_InstantRunEnabled)' != 'True' " /> + + + + + + + <_JavaBindingSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' == 'True' " /> + + + + + + <_JavaSource Include="@(AndroidJavaSource)" Condition=" '%(AndroidJavaSource.Bind)' != 'True' " /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/Sdk/AutoImport.props b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/Sdk/AutoImport.props index c29ff35a393..b87c047a612 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/Sdk/AutoImport.props +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/Sdk/AutoImport.props @@ -48,6 +48,7 @@ https://github.com/dotnet/designs/blob/4703666296f5e59964961464c25807c727282cae/ + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets index 94cfa5eed8a..aab24a7676b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets @@ -113,4 +113,8 @@ 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 2099fa39190..02cf141b5e5 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 @@ -25,6 +25,8 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. _CheckForObsoleteFrameworkAssemblies; _ValidateAndroidPackageProperties; AddLibraryJarsToBind; + _CollectJavaSourceForBinding; + _CompileBindingJava; $(BuildDependsOn); _CompileDex; $(_AfterCompileDex); @@ -92,7 +94,10 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. _RemoveLegacyDesigner; _ValidateAndroidPackageProperties; AddLibraryJarsToBind; + _CollectJavaSourceForBinding; + _CompileBindingJava; $(BuildDependsOn); + _CreateAar; _AddFilesToFileWrites; @@ -120,7 +125,6 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. _CheckForDeletedResourceFile; _ComputeAndroidResourcePaths; _UpdateAndroidResgen; - _CreateAar; _SetupMSBuildAllProjects; @@ -146,6 +150,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. $(CleanDependsOn); _CleanMonoAndroidIntermediateDir; _CleanAndroidBuildPropertiesCache; + _CleanAarCache; CleanBindingsOutput; CleanLibraryProjectIntermediaries; CleanNativeLibraryIntermediaries; @@ -155,6 +160,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. _ExtractLibraryProjectImports; _GetLibraryImports; _ExtractAar; + _CollectJavaSourceForBinding; _ExportJarToXml; @@ -167,6 +173,11 @@ projects, these properties are set in Xamarin.Android.Legacy.targets. <_ResolveLibraryProjectsDependsOn> _ExtractAar; + <_CompileBindingJavaDependsOnTargets> + _AdjustJavacVersionArguments; + _DetermineBindingJavaLibrariesToCompile; + _GetJavaPlatformJar; + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs index fe99bcea1d9..984bc8b4ab1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs @@ -38,7 +38,7 @@ protected override string GenerateCommandLineCommands () WriteLine (sw, $"\"{doc}\""); } - cmd.AppendSwitch ($"@{responseFile}"); + cmd.AppendSwitch ($"\"@{responseFile}\""); return cmd.ToString (); } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs index e4ab768c852..f9b434e0e45 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs @@ -236,8 +236,8 @@ protected override string GenerateCommandLineCommands () WriteLine (sw, "--use-legacy-java-resolver=true"); } - cmd.AppendSwitch (ApiXmlInput); - cmd.AppendSwitch ($"@{responseFile}"); + cmd.AppendSwitch ($"\"{ApiXmlInput}\""); + cmd.AppendSwitch ($"\"@{responseFile}\""); return cmd.ToString (); } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetJavaPlatformJar.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetJavaPlatformJar.cs index 879db6f1e49..5586e0c2ec9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetJavaPlatformJar.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetJavaPlatformJar.cs @@ -128,7 +128,7 @@ string GetTargetSdkVersion (string target, XAttribute target_sdk) ); return targetFrameworkVersion; } - return targetSdkVersion; + return targetSdkVersion ?? targetFrameworkVersion; } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaCompileToolTask.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaCompileToolTask.cs index 27e41a9e306..a3c1a73f6c3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/JavaCompileToolTask.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaCompileToolTask.cs @@ -15,7 +15,6 @@ namespace Xamarin.Android.Tasks public abstract class JavaCompileToolTask : JavaToolTask { - [Required] public string StubSourceDirectory { get; set; } public ITaskItem[] JavaSourceFiles { get; set; } @@ -27,9 +26,9 @@ protected override string ToolName { } private bool IsRunningInsideVS { - get { + get { var vside = false; - return bool.TryParse(Environment.GetEnvironmentVariable("VSIDE"), out vside) && vside; + return bool.TryParse(Environment.GetEnvironmentVariable("VSIDE"), out vside) && vside; } } @@ -65,7 +64,13 @@ private void GenerateResponseFile () // Include any user .java files if (JavaSourceFiles != null) foreach (var file in JavaSourceFiles.Where (p => Path.GetExtension (p.ItemSpec) == ".java")) - sw.WriteLine (string.Format ("\"{0}\"", file.ItemSpec.Replace (@"\", @"\\"))); + sw.WriteLine (string.Format ("\"{0}\"", file.ItemSpec.Replace (@"\", @"\\"))); + + if (string.IsNullOrEmpty (StubSourceDirectory)) + return; + + if (!Directory.Exists (StubSourceDirectory)) + return; foreach (var file in Directory.GetFiles (StubSourceDirectory, "*.java", SearchOption.AllDirectories)) { // This makes sense. BAD sense. but sense. diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs index 483bf9be55b..b7df052a49f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Javac.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using Xamarin.Tools.Zip; using Xamarin.Android.Tools; +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 07c1c103abc..6dd55442064 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 @@ -4,8 +4,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Xml.Linq; using Xamarin.ProjectTools; +using Microsoft.Android.Build.Tasks; namespace Xamarin.Android.Build.Tests { @@ -90,13 +92,17 @@ public void CleanBasicBindingLibrary (string classParser) proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder (Path.Combine ("temp", TestName))) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + b.BuildLogFile = "clean.log"; Assert.IsTrue (b.Clean (proj), "Clean should have succeeded"); var ignoreFiles = new string [] { "TemporaryGeneratedFile", "FileListAbsolute.txt", + "assets.cache", + "Resource.designer.cs", + "_TelemetryProps", }; var files = Directory.GetFiles (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath), "*", SearchOption.AllDirectories) - .Where (x => !ignoreFiles.Any (i => !Path.GetFileName (x).Contains (i))); + .Where (x => !ignoreFiles.Any (i => Path.GetFileName (x).Contains (i))); CollectionAssert.IsEmpty (files, $"{proj.IntermediateOutputPath} should have no files."); } } @@ -198,7 +204,7 @@ public override Java.Lang.Object LoadInBackground () { return (Java.Lang.Object) LoadInBackgroundImpl (); } - } + } }" }); using (var b = CreateDllBuilder ()) { @@ -357,7 +363,7 @@ public void BindingCheckHiddenFiles () FileAssert.DoesNotExist (Path.Combine (dsStorePath, ".DS_Store")); DirectoryAssert.DoesNotExist (Path.Combine (dsStorePath, "_MACOSX")); var svgJar = Builder.UseDotNet ? - Path.Combine (libraryProjects, assemblyIdentityMap.IndexOf ($"{binding.ProjectName}.aar").ToString (), "jl", "libs", "FD575F2BC294C4A9.jar") : + Path.Combine (libraryProjects, assemblyIdentityMap.IndexOf ($"{binding.ProjectName}.aar").ToString (), "jl", "libs", "FD575F2BC294C4A9.jar") : Path.Combine (dsStorePath, "svg-android.jar"); FileAssert.Exists (svgJar); } @@ -639,6 +645,66 @@ public void BugzillaBug11964 () } } + [Test] + public void BindingWithAndroidJavaSource () + { + if (!Builder.UseDotNet) + Assert.Ignore ("This Feature and Test is not available in Legacy Projects"); + var path = Path.Combine ("temp", TestName); + var lib = new XamarinAndroidBindingProject () { + ProjectName = "BindingsProject", + AndroidClassParser = "class-parse", + Jars = { + new AndroidItem.EmbeddedJar ("javasourcejartest.jar") { + BinaryContent = () => ResourceData.JavaSourceJarTestJar, + } + }, + OtherBuildItems = { + new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { + Encoding = Encoding.ASCII, + TextContent = () => ResourceData.JavaSourceTestExtension, + Metadata = { + { "Bind", "True" }, + }, + }, + }, + + }; + var app = new XamarinAndroidApplicationProject () { + ProjectName = "App", + References = { new BuildItem.ProjectReference ($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid) } + }; + using (var libBuilder = CreateDllBuilder (Path.Combine (path, lib.ProjectName), cleanupAfterSuccessfulBuild: false)) + using (var appBuilder = CreateApkBuilder (Path.Combine (path, app.ProjectName))) { + Assert.IsTrue (libBuilder.Build (lib), "Library build should have succeeded."); + var generatedCode = Path.Combine (Root, libBuilder.ProjectDirectory, lib.IntermediateOutputPath, + "generated", "src", "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceTestExtension.cs"); + FileAssert.Exists (generatedCode, $"'{generatedCode}' should have been generated."); + StringAssertEx.ContainsText (File.ReadAllLines (generatedCode), "public virtual unsafe 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 (appBuilder.Build (app), "App build should have succeeded."); + appBuilder.Target = "SignAndroidPackage"; + Assert.IsTrue (appBuilder.Build (app), "App SignAndroidPackage should have succeeded."); + var hash = Files.HashString (Path.Combine (lib.IntermediateOutputPath, + "binding", "bin", $"{lib.ProjectName}.jar").Replace ("\\", "/")); + var intermediate = Path.Combine (Root, appBuilder.ProjectDirectory, app.IntermediateOutputPath); + var lpPath = Path.Combine ("0", "jl", $"{lib.ProjectName}.jar"); + if (Builder.UseDotNet) { + lpPath = Path.Combine ("1", "jl", "libs", $"{hash}.jar"); + } + var jar = Path.Combine (intermediate, "lp", lpPath); + FileAssert.Exists (jar, $"'{jar}' should have been generated."); + var dexFile = Path.Combine (intermediate, "android", "bin", "classes.dex"); + FileAssert.Exists (dexFile); + string className = "Lcom/xamarin/android/test/msbuildtest/JavaSourceJarTest;"; + Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); + className = "Lcom/xamarin/android/test/msbuildtest/JavaSourceTestExtension;"; + Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); + Assert.IsTrue (appBuilder.Clean (app), "App clean should have succeeded."); + } + } + [Test] public void LibraryProjectZipWithLint () { 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 060b9d49832..28789f9eb3e 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 @@ -1178,13 +1178,15 @@ XamarinAndroidApplicationProject CreateMultiDexRequiredApplication (string debug TextContent = () => "public class ManyMethods { \n" + string.Join (Environment.NewLine, Enumerable.Range (0, 32768).Select (i => "public void method" + i + "() {}")) + "}", - Encoding = Encoding.ASCII + Encoding = Encoding.ASCII, + Metadata = { { "Bind", "False "}}, }); proj.OtherBuildItems.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 + "() {}")) + "}", - Encoding = Encoding.ASCII + Encoding = Encoding.ASCII, + Metadata = { { "Bind", "False "}}, }); return proj; } 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 53e24f6886f..379a9c99464 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 @@ -261,6 +261,7 @@ public TestMe createTestMe () { } }", Encoding = Encoding.ASCII, + MetadataValues = "Bind=False", } }, }; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Resources/JavaSourceTestExtension.java b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Resources/JavaSourceTestExtension.java new file mode 100644 index 00000000000..df727c0055a --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Resources/JavaSourceTestExtension.java @@ -0,0 +1,7 @@ +// some comment +package com.xamarin.android.test.msbuildtest; +public class JavaSourceTestExtension extends JavaSourceJarTest { + public String greetWithQuestion (String name, java.util.Date date, String question) { + return greet (name, date) + question; + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ResourceData.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ResourceData.cs index 19c2cba2839..163241116fe 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ResourceData.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ResourceData.cs @@ -17,6 +17,7 @@ static class ResourceData static Lazy library2Aar = new Lazy (() => GetResourceData ("library2.aar")); static Lazy apacheHttpClient_cs = new Lazy (() => GetResourceData ("ApacheHttpClient.cs")); static Lazy javadocCopyright = new Lazy (() => GetResourceData ("javadoc-copyright.xml")); + static Lazy javaSourceTestExtension = new Lazy (() => GetResourceData ("JavaSourceTestExtension.java")); public static byte[] JavaSourceJarTestJar => javaSourceJarTestJar.Value; public static byte[] JavaSourceJarTestSourcesJar => javaSourceJarTestSourcesJar.Value; @@ -26,6 +27,8 @@ static class ResourceData public static byte [] ApacheHttpClient_cs => apacheHttpClient_cs.Value; public static byte [] JavadocCopyright => javadocCopyright.Value; + public static string JavaSourceTestExtension => Encoding.ASCII.GetString (javaSourceTestExtension.Value); + static byte[] GetResourceData (string name) { using var s = typeof (ResourceData).Assembly.GetManifestResourceStream (name); 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 50c189c23f9..1562bc9d3c9 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 @@ -3,6 +3,8 @@ using System.IO; using System.Linq; using System.Xml.Linq; +using System.Reflection; +using System.Text; using Mono.Cecil; using NUnit.Framework; using Xamarin.Android.Tasks; @@ -118,6 +120,11 @@ public Foo () MetadataValues = "Link=x86\\libfoo.so", BinaryContent = () => Array.Empty (), }); + libB.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { + Encoding = Encoding.ASCII, + TextContent = () => ResourceData.JavaSourceTestExtension, + Metadata = { { "Bind", "True"} }, + }); libB.AddReference (libC); activity = libB.Sources.FirstOrDefault (s => s.Include () == "MainActivity.cs"); @@ -126,6 +133,9 @@ public Foo () var libBBuilder = CreateDotNetBuilder (libB, Path.Combine (path, libB.ProjectName)); Assert.IsTrue (libBBuilder.Build (), $"{libB.ProjectName} should succeed"); + var projectJarHash = Files.HashString (Path.Combine (libB.IntermediateOutputPath, + "binding", "bin", $"{libB.ProjectName}.jar").Replace ("\\", "/")); + // Check .aar file for class library var aarPath = Path.Combine (FullProjectDirectory, libB.OutputPath, $"{libB.ProjectName}.aar"); FileAssert.Exists (aarPath); @@ -137,6 +147,7 @@ public Foo () aar.AssertContainsEntry (aarPath, ".net/env/190E30B3D205731E.env"); aar.AssertContainsEntry (aarPath, ".net/env/2CBDAB7FEEA94B19.env"); aar.AssertContainsEntry (aarPath, "libs/A1AFA985571E728E.jar"); + aar.AssertContainsEntry (aarPath, $"libs/{projectJarHash}.jar"); aar.AssertContainsEntry (aarPath, "jni/arm64-v8a/libfoo.so"); aar.AssertContainsEntry (aarPath, "jni/x86/libfoo.so"); } @@ -183,6 +194,8 @@ public Foo () FileAssert.Exists (dexFile); string className = "Lcom/xamarin/android/test/msbuildtest/JavaSourceJarTest;"; Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); + className = "Lcom/xamarin/android/test/msbuildtest/JavaSourceTestExtension;"; + Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); // Check environment variable var environmentFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediate, "x86", required: true); @@ -274,6 +287,18 @@ public void DotNetPack (string dotnetVersion, string platform, int apiLevel) MetadataValues = "Link=x86\\libfoo.so", BinaryContent = () => Array.Empty (), }); + proj.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTest.java") { + Encoding = Encoding.ASCII, + TextContent = () => @"package com.xamarin.android.test.msbuildtest; +public class JavaSourceTest { + public String Say (String quote) { + return quote; + } +} +", + Metadata = { { "Bind", "True"} }, + } + ); var dotnet = CreateDotNetBuilder (proj); Assert.IsTrue (dotnet.Pack (), "`dotnet pack` should succeed"); @@ -418,6 +443,11 @@ public void DotNetBuildBinding () proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javaclasses-sources.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar, }); + proj.OtherBuildItems.Add (new AndroidItem.AndroidJavaSource ("JavaSourceTestExtension.java") { + Encoding = Encoding.ASCII, + TextContent = () => ResourceData.JavaSourceTestExtension, + Metadata = { { "Bind", "True"} }, + }); var dotnet = CreateDotNetBuilder (proj); Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); @@ -427,6 +457,9 @@ public void DotNetBuildBinding () var typeName = "MSBuildTest.JavaSourceJarTest"; var type = assembly.MainModule.GetType (typeName); Assert.IsNotNull (type, $"{assemblyPath} should contain {typeName}"); + typeName = "MSBuildTest.JavaSourceTestExtension"; + type = assembly.MainModule.GetType (typeName); + Assert.IsNotNull (type, $"{assemblyPath} should contain {typeName}"); } } @@ -575,6 +608,11 @@ 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") { + Encoding = Encoding.ASCII, + TextContent = () => ResourceData.JavaSourceTestExtension, + Metadata = { { "Bind", "True"} }, + }); if (!runtimeIdentifiers.Contains (";")) { proj.SetProperty (KnownProperties.RuntimeIdentifier, runtimeIdentifiers); } else { @@ -631,6 +669,8 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo Assert.IsNotNull (assembly.MainModule.GetType (typeName), $"{assemblyPath} should contain {typeName}"); typeName = "Com.Balysv.Material.Drawable.Menu.MaterialMenuView"; Assert.IsNotNull (assembly.MainModule.GetType (typeName), $"{assemblyPath} should contain {typeName}"); + typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceTestExtension"; + Assert.IsNotNull (assembly.MainModule.GetType (typeName), $"{assemblyPath} should contain {typeName}"); } var rids = runtimeIdentifiers.Split (';'); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs index cf9fc86cdbe..0278c04a7a8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs @@ -16,6 +16,7 @@ public class Builder : IDisposable { const string SigSegvError = "Got a SIGSEGV while executing native code"; const string ConsoleLoggerError = "[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: is negative"; + const int DefaultBuildTimeOut = 30; string Arm32AbiDir => UseDotNet ? "armeabi-v7a-net6" : "armeabi-v7a"; @@ -404,7 +405,7 @@ protected bool BuildInternal (string projectOrSolution, string target, string [] p.Start (); p.BeginOutputReadLine (); p.BeginErrorReadLine (); - ranToCompletion = p.WaitForExit ((int)new TimeSpan (0, 15, 0).TotalMilliseconds); + ranToCompletion = p.WaitForExit ((int)new TimeSpan (0, DefaultBuildTimeOut, 0).TotalMilliseconds); if (psi.RedirectStandardOutput) stdout.WaitOne (); if (psi.RedirectStandardError) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Bindings.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Bindings.targets index 39d627f9cfa..99527343326 100755 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Bindings.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Bindings.targets @@ -24,11 +24,11 @@ Copyright (C) 2012 Xamarin Inc. All rights reserved. - True False @@ -128,6 +128,12 @@ Copyright (C) 2012 Xamarin Inc. All rights reserved. /> + + + + @@ -159,6 +165,7 @@ Copyright (C) 2012 Xamarin Inc. All rights reserved. + @@ -167,10 +174,10 @@ Copyright (C) 2012 Xamarin Inc. All rights reserved. - 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 93cf53d9822..7e786d8dbf2 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets @@ -123,6 +123,10 @@ PreserveNewest Xamarin.Android.Aapt2.targets + + PreserveNewest + Xamarin.Android.Javac.targets + PreserveNewest diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index a9ee698265d..551c9180ccd 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -17,7 +17,6 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - @@ -62,9 +61,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - - @@ -85,7 +82,6 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - @@ -365,6 +361,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. + @@ -533,14 +530,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - - - - - + DependsOnTargets="_GetAndroidPackageName;_GetJavaPlatformJar"> $(IntermediateOutputPath)android\bin\$(_AndroidPackage).apk <_BaseZipIntermediate>$(IntermediateOutputPath)android\bin\base.zip @@ -1736,20 +1726,6 @@ because xbuild doesn't support framework reference assemblies. - - - - - - - - <_CompileJavaDependsOnTargets> _AdjustJavacVersionArguments; @@ -1767,54 +1743,6 @@ because xbuild doesn't support framework reference assemblies. - - - - - - - - - - - - - - - - - - - - - - <_JavaLibrariesToCompileForApp Include="@(_JavaLibrariesToCompile)" Condition=" '$(_InstantRunEnabled)' != 'True' " /> - - - - <_CompileToDalvikDependsOnTargets> _CompileJava; @@ -2470,7 +2398,6 @@ because xbuild doesn't support framework reference assemblies. - diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Tooling.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Tooling.targets index 42ebfd4003a..4838fa35119 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Tooling.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Tooling.targets @@ -12,6 +12,7 @@ projects. + @@ -96,4 +97,12 @@ projects. + + + + + + diff --git a/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs b/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs index 368353f8dfa..167c60238d2 100644 --- a/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs @@ -41,7 +41,7 @@ public void EnsureUncaughtExceptionWorks () - +