en / de
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

Qt for Android: How to integrate Java code into your application using Qt Android Extras

Building Android Apps with Qt can have many reasons and benefits:

But now and then we are facing the problem that we need Android specific services such as Intents. This is where the Qt Android Extras module comes in.

The Qt Android Extras module is basically a wrapper of the Java Native Interface (JNI). In other words, we can call every Java function from our C++ code and can even write our own Java class – How cool is that!

Let’s jump right into our example where we will implement Android Intents in Qt.

Example

An Intent is used to communicate between two Android Activities, which is primarily one site or tab of an app. With an Intent I can start another Activity and append an optional Extra message. Furthermore, an Intent can start an Activity that is contained in a separate app and that is exactly what we are going to do in our example.

In this very basic example we will create two apps: The first app is our Intent sender and starts our second app, the Intent receiver. Additionally a message can be typed which is sent with the Intent as an Extra message. The Intent receiver will then display our message. You can download the complete source code from this link. If you just want to download the APKs to test it out, check the release tab in the github repository.

Intent Sender

After setting up the project in Qt, we first need to add the Qt Android Extras module to our .pro File. Note that the module is only available if Android was selected as our kit.

QT += androidextras

For our Intent actions, we create a new C++ class calledIntent. In this class we need to include the definitions of the androidextras module’s classes:

#include <QtAndroidExtras>

Then add the following code to oursend()method. The string we want to send will be the argument of this method (extraMessage).

void Intent::send(const QString &extraMessage)
{
    QAndroidJniObject intent("android/content/Intent","()V");
    if (intent.isValid())
    {
        QAndroidJniObject param1 = QAndroidJniObject::fromString("org.qtproject.IntentReceiver");
        QAndroidJniObject param2 = QAndroidJniObject::fromString("org.qtproject.qt5.android.bindings.QtActivity");

        if ( param1.isValid() && param2.isValid())
        {
            intent.callObjectMethod("setClassName","(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",param1.object<jobject>(),param2.object<jobject>());
            QAndroidJniObject subject = QAndroidJniObject::fromString("EXTRA_MESSAGE");
            QAndroidJniObject messageObject = QAndroidJniObject::fromString(extraMessage);
            intent.callObjectMethod("putExtra", "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", subject.object(), messageObject.object());
            QtAndroid::startActivity(intent,0);
        }
    }
}

First we create the Intent and then check if it is valid. The reason for this is discussed in the second last chapter. Then we need to specify which activity we want to run. This is done by creatingparam1andparam2.param1contains the package name of our Intent receiver app. These parameters are used to set the class name.

The Intent Extra is a key-value pair, therefore we specify the key as «EXTRA_MESSAGE» and the value as the string we passed to oursend()method. After that, call theputExtra()Java method and start the Activity with the Intent.

But wait, what are all these long incomprehensible strings?
Here are a few basics:
We can access Android Java methods by callingcallObjectMethod()orcallStaticObjectMethod()for static functions. The first parameter is the function we want to call, followed by the function’s signature «(Arguments)ReturnType» with the fully-qualified class name and then the parameters. The notation has some specific rules: some strings have an «L» as prefix and «;» as suffix. The following documentation will give you a detailed explanation: https://doc.qt.io/qt-5/qandroidjniobject.html

Qt is also working on further abstractions, as you can see in the last function callstartActivity(). If you have a look at the source code, you will see that this function calls the related Java methods the same way we did it above.

For our desired functionality, we create a newIntentobject inside theon_btnSend_clicked()method, read the text from thelineEditelement and pass it as an argument to oursend()method.

void MainWindow::on_btnSend_clicked()
{
    Intent intent;
    intent.send(ui->lineEdit->text());
}

That’s it. Let’s build our Intent receiver app.

Intent Receiver

Now for our Intent receiver, add the following code in the mainwindow source file. Don’t forget to add the module and includes!

auto myActivity = QtAndroid::androidActivity();
if(myActivity.isValid()){
    QAndroidJniObject intent = myActivity.callObjectMethod("getIntent", "()Landroid/content/Intent;");
    if(intent.isValid()) {
        QAndroidJniObject subject = QAndroidJniObject::fromString("EXTRA_MESSAGE");
        jboolean hasExtras = intent.callMethod<jboolean>("hasExtra", "(Ljava/lang/String;)Z", subject.object());
        if(hasExtras){
            QAndroidJniObject extras = intent.callObjectMethod("getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;", subject.object());
            if(extras.isValid()){
                ui->lblReceivedExtra->setText(extras.toString());
            }else{
                ui->lblReceivedExtra->setText("Extras is not valid");
            }
        }else{
            ui->lblReceivedExtra->setText("Intent does not have extras");
        }
    }
}

Note that thehasExtra()call is a little bit different. This is because the function returns a primitive native Java datatype (boolean). This is specified as jboolean and the function’s signature contains a «Z» without the semicolon suffix! All this is explained in the Qt documentation and is very similar to the original JNI (https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html).

Common Pitfalls

While using the Qt Android Extras module, a few things need to be considered. ThecallMethod()functions need the Java methods as a string. This means we won’t get any instant feedback from the compiler if we spelt something wrong. Therefore it is easy to make mistakes. If we have typos in our called method, this will give us a DeadObject Exception during runtime, thus it is helpful to always check if aQAndroidJniObjectis valid.

Another thing to keep in mind is that the notation when receiving primitive Java datatypes as return value is different. If you read the documentation carefully you should not have any trouble.

Conclusion

The Qt Android Extras module and its related methods is a simple way to call Java functions in our C++ code, once its notation is understood. From this point it will also bring us closer to the JNI if we are developing a non-Qt Project and want to use Java function calls.

Kommentare

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden
NACH OBEN
Zur Webcast Übersicht