This is a super quick prototype of using Roslyn source generators to create managed "slim" Android for .NET bindings. This relies on the user creating the desired C# type binding and annotating it with attributes that control how the needed infrastructure will be generated.
Additional context is available on the GitHub proposal.
Note
As this is a quick prototype, there are many, many limitations:
- Classes only, no interfaces
- Instance classes only, no static classes
- Instance methods only, no static methods
- Final methods only, no virtual methods
- No support for Java callbacks
- Only primitive method parameter and return types (byte, bool, char, double, float, int, long, short)
- No support for arrays
Future work on this prototype, if it happens, would be to work on supporting the above cases.
We are going to use this prototype to bind this simple Java file.
Start with a basic .NET for Android application:
dotnet new android
Add the prototype source generators NuGet package:
dotnet add package XamPrototype.Android.Binding.SourceGenerator --version 0.0.1
Download the compiled Java .jar we are going to bind and place it in the project root direction.
By default, .NET for Android will automatically bind this library. We want to do it with the source
generators instead, so we need to disable the default binding in the .csproj
:
<ItemGroup>
<AndroidLibrary Update="test.jar" Bind="false" />
</ItemGroup>
Additionally, we need to allow unsafe
code for the binding:
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
Create a new class called Mathinator
that uses the source generator attributes to define the
API we wish to bind:
using Android.Runtime;
using Java.Interop.Binding.SourceGenerator;
namespace sample;
[JavaBindingType ("com.example.Mathinator")]
public partial class Mathinator : Java.Lang.Object
{
[JavaBindingMethod ("add")]
public unsafe partial int Add (int a, int b);
[JavaBindingMethod ("setVersion")]
public unsafe partial void SetVersion (int version);
[JavaBindingMethod ("getVersion")]
public unsafe partial int GetVersion ();
}
When the project is compiled, infrastructure for this class and its 3 methods will be generated in
the background. These methods can now be called in MainActivity.cs
:
protected override void OnCreate (Bundle? savedInstanceState)
{
base.OnCreate (savedInstanceState);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.activity_main);
var mathinator = new sample.Mathinator ();
Toast.MakeText (this, $"5 + 15 = {mathinator.Add (5, 15)}", ToastLength.Long).Show ();
}
Running the app should now show a toast with the Java library being called:
dotnet run