From 50521d9db1c777b3e23a1ab3ab71de9d3c3042aa Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Tue, 2 May 2023 13:51:21 -0500 Subject: [PATCH] [Xamarin.Android.Build.Tasks] Add AndroidEnableRestrictToAttributes (#7990) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context: https://github.com/xamarin/java.interop/issues/1081 Context: https://github.com/xamarin/java.interop/commit/b274a67f38e2f4012ab8414cba2c778f53f0b13c Context: https://github.com/xamarin/AndroidX/issues/690 Android libraries may use the [`androidx.annotation.RestrictTo`][0] annotation to mark a `public` Java type as "not public": // Java @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DrawableWrapper extends Drawable { } Unfortunately, .NET Android didn't know about this annotation, so all such annotated types were bound as *`public`* types: // C# binding public class DrawableWrapper : Drawable { } This is a problem because Google doesn't maintain API compatibility for types with the `@RestrictTo` annotation. This can result in undesirable API breakage; see also xamarin/AndroidX#690. xamarin/java.interop#b274a67f updated `class-parse` to know about the `@RestrictTo` annotation; when present, an `//*/@annotated-visibility` attribute is present within `api.xml`: xamarin/java.interop#b274a67f also updated `generator` to support a `generator --lang-features=restrict-to-attributes`; when present, types with an `//*/@annotated-visibility` attribute will be marked as `[Obsolete]` (*not* removed!), in order to maintain API compatibility with existing ("broken") bindings, so that customers can migrate away from these types: // C# binding [Obsolete "While this type is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.", DiagnosticId = "XAOBS001") partial class DrawableWrapper : Drawable { } The new `[Obsolete]` usage also specifies a custom warning code of `XAOBS001` so that the warning can be suppressed if desired. Add support for a new `$(AndroidEnableRestrictToAttributes)` MSBuild "enum-style" property. Supported values include: * `obsolete`: `generator --lang-features=restrict-to-attributes` will be used and the `[Obsolete]` custom attribute will be placed on bindings of Java types which have a `@RestrictTo` annotation. This is the default value. * `disable`: Java types with a `@RestrictTo` annotation will *not* be marked as `[Obsolete]`, and will be bound as a "normal" Java `public` type. disable If you would instead prefer that types with `@RestrictTo` not be bound at all, this can be achieved via Metadata, e.g. [0]: https://developer.android.com/reference/androidx/annotation/RestrictTo --- .../guides/OneDotNetBindingProjects.md | 52 ++++++++++++++++--- .../guides/building-apps/build-properties.md | 32 ++++++++++++ .../Xamarin.Android.Bindings.Core.targets | 1 + ...soft.Android.Sdk.DefaultProperties.targets | 1 + .../Tasks/Generator.cs | 4 ++ 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/Documentation/guides/OneDotNetBindingProjects.md b/Documentation/guides/OneDotNetBindingProjects.md index e27d7c51f3a..9e0829c1bb9 100644 --- a/Documentation/guides/OneDotNetBindingProjects.md +++ b/Documentation/guides/OneDotNetBindingProjects.md @@ -1,11 +1,11 @@ -# .NET 6 - Xamarin.Android Binding Migration +# .NET 6+ - Xamarin.Android Binding Migration ## Consolidation of binding projects -In .NET 6, there is no longer a concept of a [binding +In .NET 6+, there is no longer a concept of a [binding project][binding] as a separate project type. Any of the MSBuild item groups or build actions that currently work in binding projects will -be supported through a .NET 6 Android application or library. +be supported through a .NET 6+ Android application or library. For example, a binding library would be identical to a class library: @@ -26,7 +26,7 @@ libraries, just that the project file will look the same as an application. The following legacy options are no longer supported. The supported alternatives have been available for several years, and the smoothest migration option is to update - and test your current projects with these options **first** before migrating them to .NET 6. + and test your current projects with these options **first** before migrating them to .NET 6+. ### `` @@ -91,6 +91,44 @@ Or exclude *all* files within that folder: [default-items]: https://github.com/xamarin/xamarin-android/blob/main/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/Sdk/AutoImport.props +## Embedded `.jar`./`.aar` + +In Xamarin.Android Classic, the Java `.jar` or `.aar` was often embedded into the binding `.dll` +as an Embedded Resource. + +However, this led to slow builds, as each `.dll` must be opened and scanned for Java code. If +found, it must be extracted to disk to be used. + +In .NET 6+, Java code is no longer embedded in the `.dll`. The application build process will +automatically include any `.jar` or `.aar` files it finds in the same directory as a referenced `.dll`. + +If a project references a binding via `` or `` then everything +just works and no additional considerations are needed. + +However if a project references a binding via ``, the `.jar`/`.aar` must be located next +to the `.dll`. + +That is, for a reference like this: + +```xml + +``` + +A directory like this will not work: + +``` +\lib + - MyBinding.dll +``` + +The directory must contain the native code as well: + +``` +\lib + - MyBinding.dll + - mybinding.jar +``` + ## Migration Considerations There are several new features set by default to help produce new bindings that better match their @@ -173,7 +211,7 @@ Setting it to `true` will result in "un-nesting" any nested types (legacy behavi true ``` -Setting it to `false` will result in nested types remaining nested in the `interface` (.NET 6 behavior): +Setting it to `false` will result in nested types remaining nested in the `interface` (.NET 6+ behavior): ```xml false @@ -234,7 +272,7 @@ This continues to be enabled/disabled using the same mechanism as all .NET proje ``` -As the default for .NET 6 is `disable`, the same applies for Xamarin Android projects. +As the default for .NET 6+ is `disable`, the same applies for Xamarin Android projects. Use `enable` as shown above to enable NRT support. @@ -243,7 +281,7 @@ Use `enable` as shown above to enable NRT support. ### `Resource.designer.cs` In Xamarin.Android, Java binding projects did not support generating a `Resource.designer.cs` file. -Since binding projects are just class libraries in .NET 6, this file will be generated. This could +Since binding projects are just class libraries in .NET 6+, this file will be generated. This could be a breaking change when migrating existing projects. One example of a failure from this change, is if your binding generates a class named `Resource` diff --git a/Documentation/guides/building-apps/build-properties.md b/Documentation/guides/building-apps/build-properties.md index 113c87c3635..7743863813b 100644 --- a/Documentation/guides/building-apps/build-properties.md +++ b/Documentation/guides/building-apps/build-properties.md @@ -485,6 +485,38 @@ Support for this property was added in Xamarin.Android 9.4. This property is `False` by default. + +## AndroidEnableRestrictToAttributes + +An enum-style property with valid values of `obsolete` and `disable`. + +When set to `obsolete`, types and members that are marked with the Java annotation +`androidx.annotation.RestrictTo` *or* are in non-exported Java packages will +be marked with an `[Obsolete]` attribute in the C# binding. + +This `[Obsolete]` attribute has a descriptive message explaining that the +Java package owner considers the API to be "internal" and warns against its use. + +This attribute also has a custom warning code `XAOBS001` so that it can be suppressed +independently of "normal" obsolete API. + +When set to `disable`, API will be generated as normal with no additional +attributes. (This is the same behavior as before .NET 8.) + +Adding `[Obsolete]` attributes instead of automatically removing the API was done to +preserve API compatibility with existing packages. If you would instead prefer to +*remove* members that have the `@RestrictTo` annotation *or* are in non-exported +Java packages, you can use [Transform files](https://learn.microsoft.com/xamarin/android/platform/binding-java-library/customizing-bindings/java-bindings-metadata#metadataxml-transform-file) in addition to +this property to prevent these types from being bound: + +```xml + +``` + +Support for this property was added in .NET 8. + +This property is set to `obsolete` by default. + ## AndroidEnableSGenConcurrent A boolean property that 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 1acc3099159..07564b1309e 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 @@ -93,6 +93,7 @@ It is shared between "legacy" binding projects and .NET 5 projects. EnableBindingStaticAndDefaultInterfaceMethods="$(AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods)" EnableBindingNestedInterfaceTypes="$(AndroidBoundInterfacesContainTypes)" EnableBindingInterfaceConstants="$(AndroidBoundInterfacesContainConstants)" + EnableRestrictToAttributes="$(AndroidEnableRestrictToAttributes)" Nullable="$(Nullable)" UseJavaLegacyResolver="$(_AndroidUseJavaLegacyResolver)" NamespaceTransforms="@(AndroidNamespaceReplacement)" 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 cf1da6464d5..8f72ec0b74e 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 @@ -36,6 +36,7 @@ true true true + obsolete false diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs index 6d5848b96c6..33a9cad54cc 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs @@ -51,6 +51,7 @@ public class BindingsGenerator : AndroidDotnetToolTask public bool EnableBindingStaticAndDefaultInterfaceMethods { get; set; } public bool EnableBindingNestedInterfaceTypes { get; set; } public bool EnableBindingInterfaceConstants { get; set; } + public string EnableRestrictToAttributes { get; set; } public string Nullable { get; set; } public ITaskItem[] TransformFiles { get; set; } @@ -216,6 +217,9 @@ protected override string GenerateCommandLineCommands () if (EnableBindingStaticAndDefaultInterfaceMethods) features.Add ("default-interface-methods"); + if (string.Equals (EnableRestrictToAttributes, "obsolete", StringComparison.OrdinalIgnoreCase)) + features.Add ("restrict-to-attributes"); + if (string.Equals (Nullable, "enable", StringComparison.OrdinalIgnoreCase)) features.Add ("nullable-reference-types");