In .NET 6+, there is no longer a concept of a binding project 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.
For example, a binding library would be identical to a class library:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-android</TargetFramework>
</PropertyGroup>
</Project>
Note: It is still recommended that you create separate project(s) for binding your 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+.
jar2xml
is no longer a valid option for <AndroidClassParser>
. As class-parse
is
now the only valid option, this setting will no longer affect anything, and class-parse
will always be used.
class-parse
takes advantage of many new modern features not available in jar2xml
, such as:
- Automatic parameter names for class methods (if your Java code is compiled with
javac -parameters
) - Kotlin support
- Static/Default interface member (DIM) support
- Java Nullable reference type (NRT) annotations support
XamarinAndroid
is no longer a valid option for <AndroidCodegenTarget>
. XAJavaInterop1
is now the default and only supported option.
If you have hand-bound code in your Additions
files that interacts with the generated binding
plumbing (which is rare), it may need to be updated to be compatible with XAJavaInterop1
.
File structure:
Transforms/
Metadata.xml
foo.jar
Transforms\*.xml
files are automatically included as a
@(TransformFile)
item, and .jar
/.aar
files are automatically included
as a @(AndroidLibrary)
item.
This will bind C# types for the Java types found in foo.jar
using
the metadata fixups from Transforms\Metadata.xml
.
Default Android related file globbing behavior is defined in AutoImport.props.
This behavior can be disabled for Android items by setting $(EnableDefaultAndroidItems)
to false
, or
all default item inclusion behavior can be disabled by setting $(EnableDefaultItems)
to false
.
Undesired .jar
or .aar
files could be included with the default
wildcards. In one case a AndroidStudio\gradle\wrapper\gradle-wrapper.jar
file was unintentionally being bound, yielding C# compiler errors:
Org.Gradle.Cli.AbstractCommandLineConverter.cs(11,89): error CS0535: 'Download' does not implement interface member 'IDownload.Download(URI, File)'
Org.Gradle.Wrapper.Download.cs(10,60): error CS0535: 'AbstractCommandLineConverter' does not implement interface member 'ICommandLineConverter.Convert(ParsedCommandLine, Object)'
To solve this issue, you can either remove the specific file in your .csproj
:
<ItemGroup>
<AndroidLibrary Remove="AndroidStudio\gradle\wrapper\gradle-wrapper.jar" />
</ItemGroup>
Or exclude all files within that folder:
<AndroidLibrary Remove="AndroidStudio\**\*" />
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 <PackageReference>
or <ProjectReference>
then everything
just works and no additional considerations are needed.
However if a project references a binding via <Reference>
, the .jar
/.aar
must be located next
to the .dll
.
That is, for a reference like this:
<Reference Include="MyBinding.dll" />
A directory like this will not work:
\lib
- MyBinding.dll
The directory must contain the native code as well:
\lib
- MyBinding.dll
- mybinding.jar
There are several new features set by default to help produce new bindings that better match their Java counterparts. However, if you are migrating an existing binding project, these features may create bindings that are not API compatible with your existing released bindings. In order to maintain compatibility, you may wish to disable or modify these new features.
Traditionally, C# has not allowed constants to be declared in an interface
, which is a common pattern
in Java code:
public interface Foo {
public static int BAR = 1;
}
This pattern was previously supported by creating an alternative class
that contains the constant(s):
public abstract class Foo : Java.Lang.Object
{
public static int Bar = 1;
}
With C# 8, we can now put these constants on the interface
just like Java:
public interface IFoo {
public static int Bar = 1;
}
However this means we no longer generate the alternative class that existing code may depend on.
Setting <AndroidBoundInterfacesContainConstants>false</AndroidBoundInterfacesContainConstants>
will revert to the legacy behavior.
Traditionally, C# has not allowed nested types to be declared in an interface
, which is allowed
in Java code:
public interface Foo {
public class Bar { }
}
This pattern was supported by moving the nested type to a top-level type with a generated name composed of the interface and nested type name:
public interface IFoo { }
public class IFooBar : Java.Lang.Object { }
With C# 8, we can now put these nested type in the interface
just like Java:
public interface IFoo {
public class Bar : Java.Lang.Object { }
}
However this means we no longer generate the top-level class that existing code may depend on.
Setting <AndroidBoundInterfacesContainTypes>false</AndroidBoundInterfacesContainTypes>
will globally
revert to the old behavior.
If you wish to use a hybrid approach, for example, to keep existing nested types moved to a top-level
type, but allow any future nested types to remain nested, you can specify this at the interface
level using
metadata
to set the unnest
attribute.
Setting it to true
will result in "un-nesting" any nested types (legacy behavior):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>
Setting it to false
will result in nested types remaining nested in the interface
(.NET 6+ behavior):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>
Using this approach, you could leave <AndroidBoundInterfacesContainTypes>
as true
and set unnest
to
true
for every interface
with nested types you have today. These will always remain top-level
types, while any new nested types introduced later will be nested.
Traditionally, C# has not allowed interfaces to contain static
members and default
methods.
public interface Foo {
public static void Bar () { ... }
public default void Baz () { ... }
}
Static members on interfaces has been supported by moving them to a sibling class
:
public interface IFoo { }
public class Foo {
public static void Bar () { ... }
}
default
interface methods have traditionally not been bound, since they are not required and there
wasn't a C# construct to support them.
With C# 8, static
and default
members are supported on interfaces, mirroring the Java interface:
public interface IFoo {
public static void Bar () { ... }
public default void Baz () { ... }
}
However this means the alternative sibling class
containing static
members will no longer be generated.
Setting <AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods>false</AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods>
will globally
revert to the old behavior.
Support for Nullable Reference Types (NRT) was added in Xamarin.Android 11.0.
This continues to be enabled/disabled using the same mechanism as all .NET projects:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
As the default for .NET 6+ is disable
, the same applies for Xamarin Android projects.
Use enable
as shown above to enable NRT support.
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
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
in the root namespace:
error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'
Or in the case of AndroidX, we have project files with -
in the name such as
androidx.window/window-extensions.csproj
. This results in the root namespace window-extensions
and invalid C# in Resource.designer.cs
:
error CS0116: A namespace cannot directly contain members such as fields, methods or statements
error CS1514: { expected
error CS1022: Type or namespace definition, or end-of-file expected
To disable Resource.designer.cs
generation, set $(AndroidGenerateResourceDesigner)
to false
in your .csproj
:
<PropertyGroup>
<AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>