You are on page 1of 8

Qt android: interface C++ and java through JNI

March 21, 2015

The latest revisions Qt framework allow to port application developed in C++ code to run
in Android OS also. For standard app the Qt framework provide all the required features
but in some case is necessary to interact with the system using native java code. For
make such task Qt provide some specific objects able to allow a more easy work.

Create java class


First point is to create a java source file with inside our java class we'll use for interact
with the system. An example of such class can be as follow:

public class MyJavaClass

private final Activity m_MainActivity;

public MyJavaClass(final Activity MainActivity)

// Save the main activity pointer

m_MainActivity = MainActivity;

}
Please note, although not necessary in this example we'll pass as class constructor
param the pointer to the main activity object created by the Qt app. This because this
object will be necessary in case you need to make calls to some native views. Indeed if
you want to interact with native views it's usually require to call view function from UI
thread. This class and all call made from Qt are not part of UI thread than many of then
will dont' work. The common workaround is to use the following "wrapper" code:

m_MainActivity.runOnUiThread(new Runnable()

@Override

public void run()

// Here you can call directly native views

});

As you can note we use the main activity object just saved to run a code in a UI thread
for allow operation with native views. For allow Qt Creator to compile and include this
java class inside final apk you have to insert into your .pro project file as follow:

ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android

DISTFILES += android/AndroidManifest.xml

OTHER_FILES +=
android/src/com/mycompanyname/myappname/MyJavaClass.java
An important point you must to know is if you want Qt Creator to correctly compile your
java file you have to put the file in the subfolder
path /src/com/mycompanyname/myappname/ starting from the point where you place
the AndroidManifest.xml file (the android folder in our example). Once created your java
class file you can load it from C++ Qt side as follow:

QAndroidJniObject MyJavaClass;

MyJavaClass =
QAndroidJniObject("com/mycompanyname/myappname/MyJavaClass",

"(Landroid/app/Activity;)V",

QtAndroid::androidActivity().object<jobject>()

);

Now we have a Qt object to use for communicate with our java class just loaded. Note
the param to pass the main activity pointer to the class as explained above.

From C++ to java


Once loaded the class as just explained we can call java methods from C++ code. At first
we'll add the java method to call from C++ as follow:

public class MyJavaClass

{
private final Activity m_MainActivity;

public MyJavaClass(final Activity MainActivity)

// Save the main activity pointer

m_MainActivity = MainActivity;

public void TestCallMe(int param1, string param2)

// Do something here

As you can see a new function called TestCallMe has been added with two example
params, one integer and one string. Using Qt class is possible to call this method from
C++ side as follow:

int Param1;

QString Param2;

MyJavaClass.callMethod<void>("TestCallMe",

"(ILjava/lang/String;)V",
Param1,

QAndroidJniObject::fromString(Param2).object<jstring>()

);

Basically here we have to specify, in add of method name, the params accepted using
the JNI format specification. You can read more about the syntax here. Native variable
like integer doesn't need specific conversion but some more complex element, like
QString as in example, require a conversion to the JNI native format jstring. Anyway
reading the JNI types map it will be possible to exchange the majority of common format
available.

From java to C++


Here the process is a bit more complex. At first we need to define a native function
declaration inside java code. For convenience we'll create a dedicated java class as
container for native functions as follow:

class MainQtApp

public static native void nativeQtTestFuction(int param1);

This can be used for invoke function connection from java code in the form:
MainQtApp.nativeQtTestFuction(1234);

This is all from java side since all the job is made from C++ side. Basically we have to
include in our C++ code a special function called from JNI engine at startup where is
registered inside the same JNI engine a "connection" between the java functions and
the C++ function. The following code will explain better:

static void QtTestFuction(JNIEnv *env, jobject obj, jint Param1)

// Here call Qt object

static JNINativeMethod methodsArray[] =

{"nativeQtTestFuction", "(I)V", (void *)QtTestFuction},

};

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)

jclass javaClass;

JNIEnv* env;
if(vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) !=
JNI_OK)

return JNI_ERR;

javaClass = env-
>FindClass("com/mycompanyname/myappname/MainQtApp");

if(!javaClass)

return JNI_ERR;

if(env->RegisterNatives(javaClass, methodsArray,
sizeof(methodsArray) / sizeof(methodsArray[0])) < 0)

return JNI_ERR;

return JNI_VERSION_1_6;

As you can see the function JNI_OnLoad() is called automatically at app startup. Inside,
after some validity check, the code look for the "container" class MainQtApp with inside
the java native methods. Once found register the connection between java and C++ code
using the special array JNINativeMethod containing the string name of java method with
the corresponding params in JNI format, as explained above, and the C++ function code
to call. Please note the function is in C format since is more easy to pass a static function
pointer through the array and also because JNI manage only C format (this is a very
important point to remember). From inside the C function you can call directly your Qt
object class using different methods. It's all, not very difficult but a bit annoying to
develop.

You might also like