Climbing Gumdrop Mountain - Or How To Create Xamarin Android Bindings

Remember way, way back into the distant past (yeah, it’s been a while since I posted) to the Stranger In A Strange Land post about Xamarin iOS bindings? And how strange Objective-C is, at least to a C# developer trying to bind an Objective-C library for use in a Xamarin project?

Now imagine you leave the friendly confines of iOS and venture into a land where the air smells sugary sweet and the locals speak a language that you can kind of understand – just tinged with a weird local dialect (hey… kind of like Northern Wisconsin), but the way they go about daily life is … well … different.

All the cities in this land named after candy! KitKat, Lollipop, and (mmmm…) Jelly Bean! But some of these candy cities are very, very old and don’t have the amenities of the newer ones. So we have to be careful how we develop so as to not leave anybody out.

This land offers a million ways to do anything – some are as satisfying as floating in down a chocolate river. Others can be as painful as having little orange fellows with green hair shove you down a garbage shoot!

Welcome to the land of Java and Android, the Willy Wonka world of mobile development.

In this post we’re going to explore how to take an Android library and bind it to C# for use in a Xamarin Android project. And as a real treat, creating the actual binding from Java to C# can be much easier than it is with Objective-C. Of course, you have to watch out for cavities, as the bindings can get real nasty.

But fear not – after creating a couple of bindings and figuring out which bumps you’re likely to hit – it becomes fun to work with Java (probably because we’re using C# to access it)!

The Theory of Binding Java to C#

Before we get to the fun stuff – let’s talk about how Xamarin.Android communicates with the Dalvik virtual machine. Understanding this gives context to the whole “binding” process. (And yes – Dalvik is going away with Android 5.0 – but since apps written for Dalvik will still (should) run on ART, the theory here is still relevant).

First off, the Dalvik virtual machine takes care of running applications written for Android. Right or wrong, I kind of think of it as Android itself. Mono runs along side Dalvik on top of a Linux kernel and communicates to Dalvik via Managed Callable Wrappers (MCW). MCW’s are a JNI bridge which allow managed C# to invoke Android platform methods.

On the flip side are Android Callable Wrappers (ACW). An ACW is another JNI bridge that allows the Dalvik VM invoke managed code in the mono runtime. This is how java interfaces can be implemented in C#, but still invoked on the java side.

Here is a diagram from Xamarin which illustrates the situation.

Binding Project Types

Of course, when we talk about binding a Java library to Xamarin.Android and C#, we’re talking about consuming a native Java library within an application written in C#, and running on Android. There are a couple of ways we can go about implementing this.

  1. Java Binding Projects
  2. Directly with JNI
  3. Port Java code to C#

Option 2 is powerful, but can be a mess … check out the documentation (long, but worth a read)!

As far as option 3 goes… that just sounds like we’re asking for trouble.

So let’s talk about java binding projects.

Java Binding Project

This is the gumdrop mountain of getting java Android libraries to work with Xamarin.Android. Very simple and delicious, but it is also very easy to slide down the sides and get mired in a sticky mess.

The Java Binding Project is going to take care of setting up the JNI bridge for our managed C# code to invoke Android via MCWs and also allow Android to call back into the managed code via ACWs.

You create a java binding project pretty much in the same way you’d expect. (We’re going to use Xamarin Studio, but the steps with Visual Studio will be analogous). Start to create a new project and select “Android Java Bindings Project” from the list under C# -> Android node.

From there, you’ll notice 3 folders that are specific to Java binding projects:

  • Additions
  • Jars
  • Transforms

Ignore the Properties folder! 🙂

Let’s tackle these in order of importance.

Jars Folder

It’s in here that we’re going to place the JAR or AAR files that we’re going to bind to. In addition to the ones that we want to create the bindings for, we’ll place “reference” jars in here as well. A reference jar is required by the jar we’re building the bindings for, but none of its methods need to be exposed.

Adding JARs or AARs to this folder is as simple as dragging them in, or adding a new file to the project. Once they’re in there, we’ll have to set the proper build action on them. The following are the most common build actions and what they’re used for.

  • Embedded Jar – this is the build action for file we’re creating the bindings for.
  • Library Project Zip – build action for an AAR file (which is a JAR + some resources).
  • Embedded Reference Jar – build action for JAR file one of the 2 above require, but we don’t want to create bindings for.

Transforms Folder

This folder contains XML files which map java types to managed types and also allow us to transform the exposed namespaces, methods and fields in the jar file to our liking. It contains 3 files:

  • EnumFields.xml -> used to convert java int constants into .NET enums
  • EnumMethods.xml -> if a java method returns an int constant, use this to specify .NET enum return value
  • Metadata.xml -> this is the heart and soul of the java binding projects, and a file we’ll talk about in depth later

Additions Folder

It is within this folder we can add partial classes to extend the functionality of the bound library and generally make life easier on the .Net end of things. For example, we could add another constructor to make initializing easier.

Creating The Binding

Wow… did it really take me about 1000 words before I finally got around to showing how to create the binding? Well, here are the complete steps…

  1. Create the binding project
  2. Add the jar file(s) to it
  3. Build it

Really – that’s all there is to it! (I told you it was easier than binding Objective-C!) There are situations which you’ll have to do more, and we’ll cover how to work around those below, but it can be easy as building the project. Then you’ll have a java binding DLL ready to be added to an Xamarin.Android app and be done with it.

But … what if you do get some build errors? Or we want to make the library easier to consume or adhere to .Net conventions? This is where we get into the files of the Transforms folder.

EnumFields.xml and EnumMethods.xml

To continue the candy metaphor, the EnumFields.xml and EnumMethods.xml are akin to the hard candy shell or milk chocolate covering (depending on your particular sweet tooth) of our binding. They’re the candy coating because they can almost be an afterthought and not used in the binding’s implementation, but when needed, they hold the whole thing together.

In Java instead of using enums as we would in C#, constant int values are used instead. In order to properly consume those in our managed code we need to map the int constants to enums. The syntax of doing so looks like this:

<enum-field-mappings>
 
  <mapping clr-enum-type="Com.DD.ProgressType" jni-class="com/dd/CircularProgressButton">
    <field clr-name="ErrorStateProgress" jni-name="ERROR_STATE_PROGRESS" value="-1" />
    <field clr-name="IdleStateProgress" jni-name="IDLE_STATE_PROGRESS" value="0" />
    <field clr-name="IndeterminateStateProgress" jni-name="INDETERMINATE_STATE_PROGRESS" value="50" />
    <field clr-name="SuccessStateProgress" jni-name="SUCCESS_STATE_PROGRESS" value="100" />
  </mapping>
 
</enum-field-mappings>

All of the attributes that start with “clr” are mapping to managed code (or what we’ll invoke from our binding). The “jni” attributes are the JNI name of the element we’re looking for.

Analogously, if a method accepts a constant java int type and we need to map it to the enum, it would look like this:

<mapping jni-interface="com/dd/CircularProgressButton">
    <method jni-name="setProgress" parameter="p0" clr-enum-type="Com.DD.ProgressType" />
</mapping>

Metadata.xml

The ooey-gooey center of the binding project is the Metadata.xml file. It allows us to make changes to the final generated binding. Here we can rename methods, parameters, classes or namespaces. We can also change the visibility of classes, remove methods, move a class to a different namespace, or even add classes.

If any errors do occur during the building of the java bindings project, most likely it’s in this file where we’ll fix them.

The basic format of the Metadata.xml’s XML looks like this:

<metadata>
 
  <!--- Change the name of the toggle button class -->
  <attr path="/api/package/class[@name='ToggleButton']" name="managedName">TheButton</attr>
 
  <!--- Change the parameter names for the constructor -->
  <attr path="/api/package/class[@name='ToggleButton']/constructor[@name='ToggleButton' and count(parameter)=2 and parameter[1][@type='android.content.Context'] and parameter[2][@type='android.util.AttributeSet']]/parameter[@name='p0']"
    name="managedName">theContext</attr>
 
</metadata>

There is a metadata tag which can be followed by a attr``add-node``remove-node or move-node tags.

The one we’ll end up using the most often is the attr tag. This is the tag that allows us to rename a class, method, etc. The other tags are used far less, and supporting documentation for them can be found here.

The attr tag can take 2 parameters: path and name . path is an XPath used to find the element you wish to transform. The name parameter specifies which transform to apply. Finally, the value of the attr element is what you want to transform to.

Let’s take a look at an example:

<attr path="/api/package/class[@name='ToggleButton']" name="managedName">TheButton</attr>

Here we’re saying, find the class name ‘ToggleButton’ inside a structure of /api/package/class. We want to transform the managedName (or C# name) to ‘TheButton’.

I know what you’re thinking… how in the world do I find the proper path value? Well, at least that’s the first thing I thought.

The answer can be found in a generated file named API.xml. This file is created whenever a library is built and represents the packages, types and members that can be found within the jar file you’re binding to. The file itself is based off of the Google AOSP format, but that’s probably more than you wanted to know. You can find the file at ~{project directoryobjDebugapi.xml. By tracing down this file, we can find everything that we’d need.

Don’t want to actually figure out the XPaths? The generated C# file which defines all the bindings will give us the proper XPaths as well. We can find that file here: ~{project directoryobjDebuggeneratedsrc{classname}.cs. Opening that file and browsing through it, you’ll see comments that start with “Metadata.xml” – and sure enough – the full XPath will be listed there.

The transforms we can apply, or the value of the name attribute include:

  • managedName – to change the name of a member
  • eventName – used to provide a name for an event. Placed on “setXXXListener” or the interface’s method itself. If left empty, will prohibit the event from being generated.
  • sender – used to specify which parameter of a method tied to an event should be the “sender” parameter
  • managedReturn – used to change the return type of a method
  • hidden – causes a member to be ignored by the generator

You will definitely find yourself using the Metadata.xml file a lot to rename the parameters for methods – they all default to p0, p1, p2, etc. Needless to say, applying meaningful names to them can help … just a bit.

So with all that said, let’s see the transforms in action.

Here is the intellisense of a binding before any transforms have been applied:

Now – after applying the following transforms to give the constructor’s parameter a name, and also to change the name of the class itself:

<metadata>
 
    <attr path="/api/package[@name='com.dd']/class[@name='CircularProgressButton']/constructor[@name='CircularProgressButton' and count(parameter)=1 and parameter[1][@type='android.content.Context']]/parameter[@name='p0']" 
        name="managedName">theContext</attr>
 
    <attr path="/api/package[@name='com.dd']/class[@name='CircularProgressButton']" name="managedName">CPButton</attr>
 
</metadata>

We get the following:

It’s a trivial example, yes – but hopefully will give you some idea of what is all possible with these bindings.

Using The Binding

Now we get to sit down and eat our candy! In order to use the java library in our project, all we need to do is build the project, generate the DLL and then add it to our Xamarin.Android project. That’s it – tasty, tasty deliciousness.

There may be some bumps that you hit when trying to use it, and we’ll cover those in a later post, but overall, it’s a pretty easy process.

Summary

Creating a binding to a Java Android library can be much easier than creating one for an Objective-C iOS library. If we’re lucky, all we need to do is add the JAR or AAR file to the project, build it, and we can go back to eating jelly beans. But we’ll probably have to monkey around with some transform files to get everything to work properly.

However, once you’re familiar with the syntax of the various XML files, it becomes pretty easy to create them and almost as enjoyable as eating caramel popcorn!

I hope this post took some of the mystery out of creating Java Android bindings to Xamarin, and please feel free to reach out via email at msoucoup@codemilltech.com, twitter at @codemillmatt, or in the comments if you have any questions. I’m more than happy to help.