QtOnAndroid

Using JNI to run own Java code on Android

JNI | | Using JNI to show an Android notification

Using Java code from inside a Qt Android C++ app is achieved with the Qt AndroidExtras module.

This page follows the (poorly documented) Qt AndroidExtras Notification Example.

To access Java code we need to put the Java code as static methods into our own Java class, which lives in the same name space as the Qt main Android activity. In other words, our class extends the main Qt activity.

Let’s demonstrate the procedure with a static method “doSomething” that just logs the package name, for example:

package org.my.example;

import android.util.Log;

public class ExampleActivity extends org.qtproject.qt5.android.bindings.QtActivity
{
    private static ExampleActivity activity_;

    public ExampleActivity()
    {
        activity_ = this;
    }

    public static void doSomething()
    {
        Log.d("Example", "ExampleActivity.doSomething: package=" + activity_.getPackageName());
    }
}

Then we can call the static method “doSomething” of the class “ExampleActivity” from C++ using AndroidExtras:

#include <QtAndroidExtras>

bool avail = QAndroidJniObject::isClassAvailable("org/my/example/ExampleActivity");

if (avail)
   QAndroidJniObject::callStaticMethod<void>("org/my/example/ExampleActivity", "doSomething");
else
   qDebug() << "class not available";

There’s still one thing missing: we need to add the Java code to the Android package. For that purpose we tell qmake where the android source directory is located by adding the following line to the qmake project file:

ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android

Under the so defined path we create a source hierarchy which matches the Java class hierarchy and put our Java classes into that hierarchy. The hierarchy needs to start with the “src” top-level directory. Each source file must be acknowledged in the qmake project file so that it can be included into the Android apk for deployment. It is also necessary to add an Android manifest, which properly defines the package name to match the one used in the Java sources (in our example “org.my.example”):

OTHER_FILES += \
    android/src/org/my/example/ExampleActivity.java \
    android/AndroidManifest.xml

Next we need to modify the Android manifest in order to replace the standard Qt5 activity with our extended activity. Open the Android manifest, change the view mode to XML and edit the line starting with “<activity …” to show the proper class:

        <activity ... android:name="org.my.example.ExampleActivity" ...>

Now we are ready to deploy the app with the above extended Java class as main activity.

To see the log messages of our example when it is started (and the system messages), we open a shell and use the adb tool in the android-sdk*/platform-tools directory:

adb logcat "Example:D" "*:S"

To see only the debug messages without the default filter rules, we use:

adb logcat -s "Example:D"

To see all the debug messages of the ActivityManager as well, use the following line:

adb logcat "ActivityManager:I" "Example:D" "*:S"

The output should be something like that:

I/ActivityManager(  463): Start proc org.my.example for activity org.my.example/.ExampleActivity: pid=2263 uid=10104 gids={3003, 1015, 1028}
...
D/Example ( 2263): ExampleActivity.doSomething: package=org.my.example
...
I/ActivityManager(  463): Process org.my.example (pid 2263) has died.


JNI | | Using JNI to show an Android notification

Options: