Consuming Java Libraries from C# For Xamarin Development - Part 2

On a previous blog post on Xamarin mobile app development and Android, we talked about how third-party libraries help to significantly cut down on the mobile development time by allowing app developers to not worry about building certain things, like a custom UI control or a client service. We also learned about binding and converting as well as what sort of things we should consider before getting started, like having a proper Java decompiler ready.

With all of these things set up and ready to go we can dive deep in some work!

CONSUMING JAVA LIBRARIES Part 2

Getting Started

We start by creating a new Android Java Bindings project

Android java Bindings

 

After Xamarin creates and loads the project, your Solution Explorer will have this content:

Xamarin Solution explorer

 

I'm going to explain what each folder is for:

* Additions: allows you to add C# arbitrarily to the generated classes before they are compiled. This can be helpful for providing convenience and extra functionality like new methods to have pure C# classes.
* Jars: this is the jar files in which the bindings should be generated.
* Transforms: usually, you will need to access to the transform files after the bindings project reads out all the information from the jar; so you've got to use these files to modify the library before it becomes an assembly. The reasons to interact with these files are:

               - To fix issues with the binding (very common)

               - To customize the API design by changing names or types, by removing unused pieces, etc.

Now, start by adding the Jar file into Jars folders. In this case we want to create link of this native code to C#, so in Properties Window you need to make sure to change Build Action to EmbeddedJar. If the Jar is only a dependency of another one and you don´t necessarily need to link the code, you'll set EmbeddedReferenceJar (although this is not case).

After doing that, if you build the project (F8) you'll receive 12 errors. But don't worry, this is a typical process when you're binding a native library.

JAr files errors

As I previously pointed out, you'll touch the Transform files to fix binding issues.

Unfortunately, in the Xamarin documentation there is not too much information about how to fix these kind of errors.

I strongly recommend that you use a reflection/decompiler program like JD-GUI to inspect which objects are causing trouble, then load the jar assembly.

The first thing you will see is the namespaces composed. Let's start by detecting and fixing those errors.

1.  The type or namespace 'IUserAuthentication' does not exist in the namespace (Org.Jivesoftware.Smack)

Let's use reflection and navigate until that we get to that namespace.

6 resized 600

Did you realize that there is no IUserAuthentication interface? That’s because C# linking uses conventions for the interfaces by adding the letter “I” at the beginning. So we need to specify in Metadata.xml file which is the correct name of the interface.

<span style="font-size: 13px;"><em>&lt;attr path="/api/package[@name='org.jivesoftware.smack']/interface[@name='UserAuthentication']" name="visibility"&gt;public&lt;/attr&gt;</em></span>

Note that you have to specify the original name of the assembly. Sometimes you can deduce it but in another time wouldn’t work that way. 

2. Inconsistent accessibility: base class 'Org.Jivesoftware.Smack.Util.Collections.AbstractHashedMap.EntrySet' is less accessible than class 'Org.Jivesoftware.Smack.Util.Collections.AbstractReferenceMap.ReferenceEntrySet'

When we talk about accessibility, we refer to modifiers. Change these classes to visibility public

<span style="font-size: 13px;"><em>&lt;attr path="/api/package[@name='org.jivesoftware.smack']/interface[@name='UserAuthentication']" name="visibility"&gt;public&lt;/attr&gt;--&gt;</em></span>
<attr path="/api/package[@name='org.jivesoftware.smack.util.collections']/class[@name='AbstractHashedMap.EntrySet']" name="visibility">public</attr> 

<attr path="/api/package[@name='org.jivesoftware.smack.util.collections']/class[@name='AbstractReferenceMap.ReferenceEntry']" name="visibility">public</attr>

<attr path="/api/package[@name='org.jivesoftware.smack.util.collections']/class[@name='AbstractHashedMap.HashEntry']" name="visibility">public</attr>

<attr path="/api/package[@name='org.jivesoftware.smack.util.collections']/class[@name='AbstractHashedMap.KeySet']" name="visibility">public</attr>

<span style="font-size: 13px;"><em>&lt;attr path="/api/package[@name='org.jivesoftware.smack.util.collections']/class[@name='AbstractHashedMap.Values']" name="visibility"&gt;public&lt;/attr&gt;</em></span>
<attr path="/api/package[@name='org.jivesoftware.smack.util.collections']/class[@name='AbstractEmptyIterator']" name="visibility">public</attr> 

3. Now, if we build the solution we're going to receive more errors.

We might continue solving these errors. But as you notice, more errors are appearing than we are fixing. You could end up fixing more than 1000 issues. “Hey Xamarin, are you out of your mind?” maybe if you read very well the purposes of Transforms folders, I add this one: To customize the API design by changing names or types, by removing unused pieces, etc.

So I recommend just using those API’s or functions you do need in your project. So you can omit removing namespaces in the binding library and of course they will be there but you cannot access them.

Reviewing the documentation of the library in the project, we really need the namespace org.jivesoftware.smack to create a socket communication for the chat. Then, we can remove the namespace that we do not need.

<span style="font-size: 13px;">&lt;remove-node path="/api/package[@name='org.xbill.DNS']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.apache.harmony.javax.security.auth.callback']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.apache.harmony.javax.security.auth']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.apache.qpid.management.common.sasl']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smack.sasl']/class[@name='SASLMechanism']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smack.util']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smack.util.dns']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smack.util.collections']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smackx.bytestreams.ibb']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smackx.muc']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smackx.pubsub']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smackx.commands']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smackx.packet']" /&gt;</span>
<span style="font-size: 13px;">    &lt;remove-node path="/api/package[@name='org.jivesoftware.smackx.filetransfer']" /&gt;</span>
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.bytestreams.socks5']" />

4. Now, we build again

8 resized 600We only see only one error inside of the namespace we're interested in.

'Org.Xmlpull.Mxp1.MXParser' does not implement interface member 'Org.XmlPull.V1.IXmlPullParser.EventType'. 'Org.Xmlpull.Mxp1.MXParser.EventType' cannot implement 'Org.XmlPull.V1.IXmlPullParser.EventType' because it does not have the matching return type of 'Org.XmlPull.V1.XmlPullParserNode'.

<attr path="/api/package[@name='org.xmlpull.mxp1']/class[@name='MXParser']/method[@name='getEventType']" name="managedReturn">

        Org.XmlPull.V1.XmlPullParserNode

<span style="font-size: 13px;"><em>&lt;/attr&gt; </em></span>

5. At the end, we will get more errors but just a few of them. The result is this.

 

<metadata>
    <!-- different scoping rules in .NET, so we make these public -->
    <attr path="/api/package[@name='org.jivesoftware.smack']/interface[@name='UserAuthentication']" name="visibility">public</attr>

    <remove-node path="/api/package[@name='org.xbill.DNS']" />
    <remove-node path="/api/package[@name='org.apache.harmony.javax.security.auth.callback']" />
    <remove-node path="/api/package[@name='org.apache.harmony.javax.security.auth']" />
    <remove-node path="/api/package[@name='org.apache.qpid.management.common.sasl']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smack.sasl']/class[@name='SASLMechanism']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smack.util']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smack.util.dns']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smack.util.collections']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.bytestreams.ibb']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.muc']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.pubsub']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.commands']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.packet']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.filetransfer']" />
    <remove-node path="/api/package[@name='org.jivesoftware.smackx.bytestreams.socks5']" />
    
    <!-- Return -->

 

    <attr path="/api/package[@name='org.xmlpull.mxp1']/class[@name='MXParser']/method[@name='getEventType']" name="managedReturn">
        Org.XmlPull.V1.XmlPullParserNode
    </attr>
    <attr path="/api/package[@name='org.jivesoftware.smackx.packet']/class[@name='LastActivity']/field[@name='lastActivity']" name="managedName">
        LastActivity2    
    </attr>

    <attr path="/api/package[@name='org.jivesoftware.smack.packet']/class[@name='IQ']/method[@name='getType' and count(parameter)=0]" name="managedName">
        GetTypeImpl
    </attr>
    <attr path="/api/package[@name='org.jivesoftware.smack.packet']/class[@name='Message']/method[@name='getType' and count(parameter)=0]" name="managedName">
        GetTypeImpl
    </attr>
    
    <attr path="/api/package[@name='org.jivesoftware.smack.packet']/class[@name='Presence']/method[@name='getType' and count(parameter)=0]" name="managedName">
        GetTypeImpl
    </attr>
    <attr path="/api/package[@name='org.jivesoftware.smack.packet']/class[@name='PrivacyItem']/method[@name='getType' and count(parameter)=0]" name="managedName">
        GetTypeImpl
    </attr>
    <attr path="/api/package[@name='org.jivesoftware.smack.packet']/class[@name='XMPPError']/method[@name='getType' and count(parameter)=0]" name="managedName">
        GetTypeImpl
    </attr>
</metadata>

 

Now, build the project and you’re ready to consume the data on an Android Project.

Referencing the Binding Library

Create your target project to consume the assembly and tap contextual menu on Referencesfolder. Click Edit References and check it.

Binding library

Now, try to access one class of the assembly in the activity.

10 resized 600

You’ll see it is available to utilize the logic into your target project.

Final Thoughts

I know it can get tedious to see so many errors the first time. But at the end it is more reliable by utilizing third party libraries which use standards and have been tested by many users or when there's no .NET assembly to consume directly in your project.

Happy Decompiling :)

About the Author

Oscar Fimbres is a Computer Science specialist. He has been involved in ASP.NET MVC and Windows RT projects. Also he is a Microsoft Student Partner since 2011 spreading the word about Microsoft Technologies.

Oscar Salas

Written by Oscar Salas

Oscar Salas is a B2B Digital Marketing Specialist with 5 years of experience, who has helped organizations to grow and expand through strategic brand development and marketing programs. Analytical thinker, cat lover, he enjoys to play the piano and listening to Led Zeppelin He's currently leading the iTexico Demand Gen strategies.

Explore iTexico, The Nearshore + Company 

Explore The Nearshore Services

Read More

Java Competency Center

Recent Posts