• HOME
  • ABOUT US
  • SERVICES
  • PORTFOLIO
  • BLOG
Connection Quest Connection Quest
  • HOME
  • ABOUT US
  • SERVICES
  • PORTFOLIO
  • BLOG
Connection Quest

Java Native Interface with Qt

Home / Tips & Tricks / Java Native Interface with Qt

Java Native Interface with Qt

By Marko Jovic inTips & Tricks

Java Native Interface (JNI) is a neat thing. It allows running Java code from native applications and libraries written in other languages such as C, C++ and assembly. Java, as you surely know, is one of the officially supported languages for developing Android applications. If you develop with Qt, however, you probably use C++ or Python. And there’s the catch, by providing several classes which make using JNI pretty straightforward, Qt effectively enables you to write Android applications utilizing the best of both worlds.

Now you might be asking yourself, why should I need to use JNI if Qt already has multiple interfaces ready to access Android internals directly from C++? Well, you certainly can, but during the development of multiple Qt/Android projects here at Connection Quest, we found out that there are a lot of use-cases where you’re better off interacting with the Android framework from Java, as you would if writing a native Android application.

Therefore, our quest for this post is to explore how to bridge this language gap and augment your Android development experience.

Running Java code from C++

At this point I will assume that you have written the required Java class. To use it from C++, put the .java file in the subfolder path /src/com/myCompanyName/myAppName starting from the location of AndroidManifest.xml. Furthermore, add the Android Extras module to the project file as shown in the following snippet:

QT += androidextras
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
DISTFILES += android/AndroidManifest.xml
OTHER_FILES += android/src/com/myCompanyName/myAppName/myJavaClass.java

Before I get into details on setting up the interface, there are a few important points we have to cover:

  • always use fully-qualified class names, such as java/lang/Class
  • method signatures are structured as (A)R, where A is the argument type and R is the return type
  • all object types are returned as a QAndroidJniObject

Let’s get started then, to instantiate your Java class use the following syntax:

QAndroidJniObject javaClass = 
QAndroidJniObject("com/myCompanyName/myAppName/myJavaClassName");

There are cases where its useful to have the application activity and/or context inside the Java code. To get them, use the appropriate functions from the QtAndroid namespace and send the corresponding object to the Java class constructor.

javaClass = QAndroidJniObject("com/myCompanyName/myAppName/myJavaClassName", 
"(Landroid/content/Context;Landroid/app/Activity;)V", 
QtAndroid::androidContext().object<jobject>(), 
QtAndroid::androidActivity().object<jobject>());

Great, your Java class is now up and running. So how would you call a specific function from that class? If the function takes no arguments and does not return anything, simply use:

javaClass.callMethod<void>("javaFunctionName");

However, to invoke some more complex functions, you need to supply the correct function signature*. It is important to note that array types in the signature have the [ suffix and fully-qualified types have the L prefix and ; suffix.

For example, to call a function that takes a string argument and returns an integer:

jint integerVariable = javaClass.callMethod<jint>("javaFunctionName", 
"Ljava/lang/String;)I", "argument");

Callback a C++ function from Java

That’s it, you just learned how to run Java code from C++ using some Qt classes. But wait, we still have some things to try. Can you do the same, just the other way around? Can you call C++ functions from Java?

Of course you can. First, create a corresponding function declaration in Java and prefix it with the native keyword. Besides that, you need to map all Java native functions to their corresponding C++ variants. Luckily, there is a useful function called RegisterNatives just for that.

// An array of JNI native methods in java code
JNINativeMethod methods[] = {
    {"firstNativeFunction", "(DDLjava/lang/String;FI)V", 
    reinterpret_cast<void*>(cppFunctionOne)},
    {"secondNativeFunction", "(I)V", reinterpret_cast<void*>(cppFunctionTwo)}
};

QAndroidJniEnvironment env;
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
    
env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0]));
env->DeleteLocalRef(objectClass);

Here, firstNativeFunction and secondNativeFunction represent native functions in Java code:

public native void firstNativeFunction(double a, double b, String c, float d, int e);
public native void secondNativeFunction(int f);

while cppFunctionOne and cppFunctionTwo are static C++ functions:

static void cppFunctionOne(JNIEnv *env, jobject obj, jdouble a, jdouble b, jstring c, 
jfloat d, jint e) {
    ...
}
static void cppFunctionTwo(JNIEnv *env, jobject obj, jint f) {
    ...
}

Now, by invoking firstNativeFunction from Java, you’ll actually pass the execution to the cppFunctionOne in your C++ code. Because most objects received from Java are local references, they are only valid in the scope you received them. Be sure to delete that reference once the registration is complete.

That’s actually it. After getting over the slightly awkward syntax you’ll discover a lot of great possibilities of being able to run your Java code from C++ and vice versa.

Stay tuned and happy coding.

*Here is a list of tables containing specific JNI types from the Qt website:

JNI object types

TypeSignature
jobjectLjava/lang/Object;
jclassLjava/lang/Class;
jstringLjava/lang/String;
jthrowableLjava/lang/Throwable;
jobjectArray[Ljava/lang/Object;
jarray[<type>

JNI primitive types

TypeSignature
jbooleanZ
jbyteB
jcharC
jshortS
jintI
jlongJ
jfloatF
jdoubleD

Other types

TypeSignature
voidV
Custom typeL<fully-qualified-name>;
AndroidAndroid DevelopmentC++JavaJava Native InterfaceJNIQtSoftwareSoftware Development
15 Posts
Marko Jovic
  • Forming class(es)
    Previous PostForming class(es)
  • Next PostBe generic
    Forming class(es)

1 Comment

  1. OUEFO ALIOUNE AZIZ OUEDRAOGO
    Reply
    26 December 2021

    Hi !

    QString = “Hello World”

    QAndroidIntent activityIntent(QtAndroid::androidActivity().object(),
    “org/qtproject/example/activityhandler/CustomActivity”);

    QtAndroid::startActivity(
    activityIntent.handle(), REQUEST_CODE,
    [this](int requestCode, int resultCode, const QAndroidJniObject &data) {

    activityReceiver(requestCode, resultCode, data);
    });

    how to get “Hello World” in a method of the activity after it is started.

    Reply

Leave a Reply to OUEFO ALIOUNE AZIZ OUEDRAOGO (Cancel reply)

Your email address will not be published. Required fields are marked *

*
*

© 2025 Connection Quest j.d.o.o. All rights reserved.

Copy