Skip to content

Commit 4f41349

Browse files
jpobstjonathanpeppers
authored andcommitted
[Xamarin.Android.Build.Tasks] Add AndroidEnableRestrictToAttributes (#7990)
Context: dotnet/java-interop#1081 Context: dotnet/java-interop@b274a67 Context: dotnet/android-libraries#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 dotnet/android-libraries#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`: <class name="DrawableWrapper" … annotated-visibility="LIBRARY_GROUP_PREFIX" /> 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. <AndroidEnableRestrictToAttributes>disable</AndroidEnableRestrictToAttributes> If you would instead prefer that types with `@RestrictTo` not be bound at all, this can be achieved via Metadata, e.g. <remove-node path="//*[@annotated-visibility]" /> [0]: https://developer.android.com/reference/androidx/annotation/RestrictTo
1 parent 465e338 commit 4f41349

File tree

5 files changed

+83
-7
lines changed

5 files changed

+83
-7
lines changed

Documentation/guides/OneDotNetBindingProjects.md

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# .NET 6 - Xamarin.Android Binding Migration
1+
# .NET 6+ - Xamarin.Android Binding Migration
22

33
## Consolidation of binding projects
44

5-
In .NET 6, there is no longer a concept of a [binding
5+
In .NET 6+, there is no longer a concept of a [binding
66
project][binding] as a separate project type. Any of the MSBuild item
77
groups or build actions that currently work in binding projects will
8-
be supported through a .NET 6 Android application or library.
8+
be supported through a .NET 6+ Android application or library.
99

1010
For example, a binding library would be identical to a class library:
1111

@@ -26,7 +26,7 @@ libraries, just that the project file will look the same as an application.
2626

2727
The following legacy options are no longer supported. The supported alternatives
2828
have been available for several years, and the smoothest migration option is to update
29-
and test your current projects with these options **first** before migrating them to .NET 6.
29+
and test your current projects with these options **first** before migrating them to .NET 6+.
3030

3131
### `<AndroidClassParser>`
3232

@@ -70,6 +70,44 @@ all default item inclusion behavior can be disabled by setting `$(EnableDefaultI
7070

7171
[default-items]: https://github.com/xamarin/xamarin-android/blob/main/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/Sdk/AutoImport.props
7272

73+
## Embedded `.jar`./`.aar`
74+
75+
In Xamarin.Android Classic, the Java `.jar` or `.aar` was often embedded into the binding `.dll`
76+
as an Embedded Resource.
77+
78+
However, this led to slow builds, as each `.dll` must be opened and scanned for Java code. If
79+
found, it must be extracted to disk to be used.
80+
81+
In .NET 6+, Java code is no longer embedded in the `.dll`. The application build process will
82+
automatically include any `.jar` or `.aar` files it finds in the same directory as a referenced `.dll`.
83+
84+
If a project references a binding via `<PackageReference>` or `<ProjectReference>` then everything
85+
just works and no additional considerations are needed.
86+
87+
However if a project references a binding via `<Reference>`, the `.jar`/`.aar` must be located next
88+
to the `.dll`.
89+
90+
That is, for a reference like this:
91+
92+
```xml
93+
<Reference Include="MyBinding.dll" />
94+
```
95+
96+
A directory like this will not work:
97+
98+
```
99+
\lib
100+
- MyBinding.dll
101+
```
102+
103+
The directory must contain the native code as well:
104+
105+
```
106+
\lib
107+
- MyBinding.dll
108+
- mybinding.jar
109+
```
110+
73111
## Migration Considerations
74112

75113
There are several new features set by default to help produce new bindings that better match their
@@ -152,7 +190,7 @@ Setting it to `true` will result in "un-nesting" any nested types (legacy behavi
152190
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>
153191
```
154192

155-
Setting it to `false` will result in nested types remaining nested in the `interface` (.NET 6 behavior):
193+
Setting it to `false` will result in nested types remaining nested in the `interface` (.NET 6+ behavior):
156194

157195
```xml
158196
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>
@@ -213,7 +251,7 @@ This continues to be enabled/disabled using the same mechanism as all .NET proje
213251
</PropertyGroup>
214252
```
215253

216-
As the default for .NET 6 is `disable`, the same applies for Xamarin Android projects.
254+
As the default for .NET 6+ is `disable`, the same applies for Xamarin Android projects.
217255

218256
Use `enable` as shown above to enable NRT support.
219257

@@ -222,7 +260,7 @@ Use `enable` as shown above to enable NRT support.
222260
### `Resource.designer.cs`
223261

224262
In Xamarin.Android, Java binding projects did not support generating a `Resource.designer.cs` file.
225-
Since binding projects are just class libraries in .NET 6, this file will be generated. This could
263+
Since binding projects are just class libraries in .NET 6+, this file will be generated. This could
226264
be a breaking change when migrating existing projects.
227265

228266
One example of a failure from this change, is if your binding generates a class named `Resource`

Documentation/guides/building-apps/build-properties.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,38 @@ Support for this property was added in Xamarin.Android 9.4.
476476

477477
This property is `False` by default.
478478

479+
480+
## AndroidEnableRestrictToAttributes
481+
482+
An enum-style property with valid values of `obsolete` and `disable`.
483+
484+
When set to `obsolete`, types and members that are marked with the Java annotation
485+
`androidx.annotation.RestrictTo` *or* are in non-exported Java packages will
486+
be marked with an `[Obsolete]` attribute in the C# binding.
487+
488+
This `[Obsolete]` attribute has a descriptive message explaining that the
489+
Java package owner considers the API to be "internal" and warns against its use.
490+
491+
This attribute also has a custom warning code `XAOBS001` so that it can be suppressed
492+
independently of "normal" obsolete API.
493+
494+
When set to `disable`, API will be generated as normal with no additional
495+
attributes. (This is the same behavior as before .NET 8.)
496+
497+
Adding `[Obsolete]` attributes instead of automatically removing the API was done to
498+
preserve API compatibility with existing packages. If you would instead prefer to
499+
*remove* members that have the `@RestrictTo` annotation *or* are in non-exported
500+
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
501+
this property to prevent these types from being bound:
502+
503+
```xml
504+
<remove-node path="//*[@annotated-visibility]" />
505+
```
506+
507+
Support for this property was added in .NET 8.
508+
509+
This property is set to `obsolete` by default.
510+
479511
## AndroidEnableSGenConcurrent
480512

481513
A boolean property that

src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ It is shared between "legacy" binding projects and .NET 5 projects.
9898
EnableBindingStaticAndDefaultInterfaceMethods="$(AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods)"
9999
EnableBindingNestedInterfaceTypes="$(AndroidBoundInterfacesContainTypes)"
100100
EnableBindingInterfaceConstants="$(AndroidBoundInterfacesContainConstants)"
101+
EnableRestrictToAttributes="$(AndroidEnableRestrictToAttributes)"
101102
Nullable="$(Nullable)"
102103
UseJavaLegacyResolver="$(_AndroidUseJavaLegacyResolver)"
103104
NamespaceTransforms="@(AndroidNamespaceReplacement)"

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods Condition=" '$(AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods)' == '' ">true</AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods>
3535
<AndroidBoundInterfacesContainTypes Condition=" '$(AndroidBoundInterfacesContainTypes)' == '' ">true</AndroidBoundInterfacesContainTypes>
3636
<AndroidBoundInterfacesContainConstants Condition=" '$(AndroidBoundInterfacesContainConstants)' == '' ">true</AndroidBoundInterfacesContainConstants>
37+
<AndroidEnableRestrictToAttributes Condition=" '$(AndroidEnableRestrictToAttributes)' == '' ">obsolete</AndroidEnableRestrictToAttributes>
3738

3839
<!-- Mono components -->
3940
<AndroidEnableProfiler Condition=" '$(AndroidEnableProfiler)' == ''">false</AndroidEnableProfiler>

src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class BindingsGenerator : AndroidDotnetToolTask
5151
public bool EnableBindingStaticAndDefaultInterfaceMethods { get; set; }
5252
public bool EnableBindingNestedInterfaceTypes { get; set; }
5353
public bool EnableBindingInterfaceConstants { get; set; }
54+
public string EnableRestrictToAttributes { get; set; }
5455
public string Nullable { get; set; }
5556

5657
public ITaskItem[] TransformFiles { get; set; }
@@ -216,6 +217,9 @@ protected override string GenerateCommandLineCommands ()
216217
if (EnableBindingStaticAndDefaultInterfaceMethods)
217218
features.Add ("default-interface-methods");
218219

220+
if (string.Equals (EnableRestrictToAttributes, "obsolete", StringComparison.OrdinalIgnoreCase))
221+
features.Add ("restrict-to-attributes");
222+
219223
if (string.Equals (Nullable, "enable", StringComparison.OrdinalIgnoreCase))
220224
features.Add ("nullable-reference-types");
221225

0 commit comments

Comments
 (0)