jpobst / Prototype.Android.MavenBindings

Prototype of MSBuild tasks to facilitate binding of Java libraries from Maven repositories
MIT License
5 stars 3 forks source link

Proposal: Untyped Slim Bindings #8

Open jpobst opened 1 year ago

jpobst commented 1 year ago

Summary

Another potential way to implement "bind only what you need" would be to remain fully in C# and place the burden on the user to provide the metadata needed to perform JNI interop. While this can be cumbersome and tricky for lots of API, for a few small uses it might be acceptable.

Downsides:

Open questions:

Proposed API

// Create a new "com.googleplay.services.ApiClient" type instance
var api_client = new UntypedJavaObject ("com.googleplay.services", "ApiClient");

// or with constructor parameters
var api_client = new UntypedJavaObject ("com.googleplay.services", "ApiClient", "my_api_key");

// Invoke a method with 'void' return
api_client.InvokeMethod ("setApiKey", "my_api_key");

// Invoke a method with 'int' return
var quota = api_client.InvokeMethod<int> ("getRemainingQuota");

// Get an 'int' field
var quota = api_client.GetField<int> ("API_VERSION");

// Set an 'int' field
api_client.SetField ("API_VERSION", 34);

Would also need a static version:

var api_client = new UntypedStaticJavaObject ("com.googleplay.services", "ApiClient");
var quota = api_client.GetField<int> ("API_VERSION");

Interop with Classic Java.Lang.Object

Use a JLO as an "untyped" parameter type

var view = FindViewById (Resources.layout);
var map = new UntypedJavaObject ("com.mapbox.maps", "MapView");

map.InvokeMethod ("attachToView", view);

Return a JLO from an "untyped" return type

var map = new UntypedJavaObject ("com.mapbox.maps", "MapView");
var view = map.InvokeMethod<Android.Views.View> ("getAttachedView");

Cast a JLO that was bound as Object to an "untyped" type

var view = FindViewById (Resources.layout);
var unknown_jlo = view.GetThing ();

var untyped = UntypedJavaObject.FromObject (view);

Cast an "untyped" type to a known JLO

var map = new UntypedJavaObject ("com.mapbox.maps", "MapView");
var untyped = map.InvokeMethod<UntypedJavaObject> ("getAttachedView");

var view= untyped.JavaCast<Android.Views.View> ();

Execute an unbound method on a JLO

var view = FindViewById (Resources.layout);
var untyped = UntypedJavaObject.FromObject (view);

untyped.InvokeMethod ("newUnboundMethod");

Sample

Converting the sample from https://github.com/Redth/MapboxSlimBindingDemo/tree/main:

public class MainActivity : Activity
{
    protected override void OnCreate (Bundle? savedInstanceState)
    {
        base.OnCreate (savedInstanceState);

        // Create new MapView ('this' is 'Android.Content.Context')
        var mapview = new UntypedJavaObject ("com.mapbox.maps", "MapView", this);

        // MapView inherits Android.Views.View
        var view = mapview.JavaCast<Android.Views.View> ();

        // Set as our view
        SetContentView (view);
    }
}