Mono for Android let’s you write Android applications in a .NET language (for example, C#). It comes with wrappers for almost the entire Android API so building “standard” apps is easy enough. However, sometimes you may need to work with third party Java classes that aren’t part of Android itself. These classes usually come as a .jar file. Fortunately, Mono for Android provides a way to access those Java classes. Unfortunately, this way is a “little” bit tricky and documentation on this is (currently) quite limited.
This article will show some basic example of how to call a method of a Java class from Mono for Android. We will use Visual Studio 2010 in this article, as it is (in my opinion) currently superior to Mono Develop.
One last word before we start:
Prerequisites ¶
For this article I’ll assume you know your way around in Java and C#, and have installed:
Native Java Library ¶
To demonstrate accessing a Java library, let’s create a very simple one.
Create a new Android project called “JarLibForMonoDroid” (without an Activity). Then open the project settings and under Android activate Is Library.
Note: A working project is provided in the example source code available in the Download section below.
Create a class called JniTest in package com.mayastudios.jnitest. Here’s its contents:
package com.mayastudios.jnitest;
public class JniTest {
public JniTest() {
// Force the user to create an instance
}
public String getGreetingText() {
return "Hello, " + android.os.Build.MODEL;
}
}
Save the Java file. The ADT should now have created a .jar file in the bin directory. (If it’s not there, make sure you’ve activated Is Library in the Android project settings.) That’s it.
Note: Normally, you don’t need an Android project but could create a pure Java project as well. In this example, we use an Android project to demonstrate the ability to access the Android API from within the Java classes and to have an easy way to create a .jar file for our project.
Accessing the Java Class from Mono ¶
Create a simple Mono for Android project in Visual Studio.
Add jar to the project ¶
The first step is to add the .jar file that was created in the previous section to the project (via Add existing item). For ease of use you should add this file as a link (by clicking on the down arrow at the Add button) like shown in the screenshot. If you don’t do this, the .jar file will be copied into the project directory and you need to re-copy it every time it changes.
You should now have an entry for the .jar file in your Solution Explorer pane. Note that there’s a small arrow in the jar’s icon indicating that it’s a link.
The last thing you need to do is to open up the jar’s Properties (via context menu or Alt+Return) and set the Build Action to AndroidJavaLibrary. This makes the classes contained in the jar accessible to JNI.
Important: You need to rebuild the project every time the .jar file has changed. The Mono for Android Add-In currently doesn’t detect the change automatically.
Add JNI code ¶
Now, let’s access the Java class. For this, in Mono for Android you use a Mono version of JNI. With JNI in Java native libraries written in C++ can access Java objects. So, with JNI in Mono .NET classes can access Java objects.
To get started, in the Activity1 class, create a new method (called GetGreetingText) and change button’s Click event handler to set the button’s text with the return value of the method. (This all assumes that Xamarin didn’t change the default project example code when you read this. Otherwise you need to adapt the code.) The code should now look similar to this:
[Activity(Label = "MonoJniExample", MainLauncher = true, Icon = "@drawable/icon")]
public class Activity1 : Activity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += (s, e) => { button.Text = GetGreetingText(); }; }
string GetGreetingText() {
// Code to be added here
}
}
We will now add the necessary JNI code to GetGreetingText. In the end it’ll return “Hello, <Your Device Name here>”. The code should be pretty much self-explanatory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
string GetGreetingText() {
// Get a pointer to the Java class.
IntPtr nativeJavaClass = JNIEnv.FindClass("com/mayastudios/jnitest/JniTest");
// Find the parameterless constructor.
IntPtr defaultConstructor = JNIEnv.GetMethodID(nativeJavaClass,
"<init>",
"()V");
// Create a new instance of the class.
IntPtr instance = JNIEnv.NewObject(nativeJavaClass, defaultConstructor);
// Find our example method.
IntPtr method = JNIEnv.GetMethodID(nativeJavaClass,
"getGreetingText",
"()Ljava/lang/String;");
// Call the method.
IntPtr resultPtr = JNIEnv.CallObjectMethod(instance, method);
// Convert pointer to return value into a usable object (here a string).
Java.Lang.String nativeResult
= new Java.Lang.Object(resultPtr, JniHandleOwnership.TransferLocalRef)
.JavaCast<Java.Lang.String>();
// Convert the Java string into a .NET string and return it.
return nativeResult.ToString();
}
|
There are a few that should be noted here:
-
The method JNIEnv.GetMethodID() takes the method name as second parameter and the method signature as third parameter.
- The method name for a constructor is always
<init>.
- The signature is composed of the parameter list followed by the return type of the method. It adheres the JNI rules for specifying the signature. I suggest you use this JNI Cheat Sheet for trying to understand the syntax.
- Some rudimentary description of JNI’s methods can be found in the JNI specification.
-
The JniHandleOwnership enumeration (line 19) hasn’t been documented yet. So I can’t really say anything about it. I’m currently waiting for an answer about this.
You should now be able to run the app and when you tap on the button it should change its text.
Download the Project Files ¶
I’ve compiled a small .zip file containing the source code and all project files.
projectfiles.zip
CodeProject