Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Callback from Android to QML
Qt 6.11 is out! See what's new in the release blog

Callback from Android to QML

Scheduled Pinned Locked Moved Solved Mobile and Embedded
3 Posts 2 Posters 1.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SyntaXS Offline
    SyntaXS Offline
    SyntaX
    wrote on last edited by
    #1

    Hey everyone :D
    I am relatively new to Qt / QML, so please excuse me, if I am not getting everything right.

    Currently I am integrating several Plugins into an existing Qml Application, with specific implementations for Android and iOS.

    Basically, my project looks something like the following.

    To achieve this, I have a myfunctions.h header file, where I specified all my methods:

    #ifndef MYFUNCTIONS_H
    #define MYFUNCTIONS_H
    
    #include <QQuickItem> // QObject, QString, ...
    
    class MyFunctions : public QObject {
    
        Q_OBJECT
        Q_DISABLE_COPY(MyFunctions)
    
        Q_PROPERTY(QString myString READ myString WRITE setMyString NOTIFY myStringChanged)
    
    public:
        explicit MyFunctions(QObject *parent = 0);
    
        void setMyString(const QString &string);
        QString myString() const;
    
    
    signals:
        void myStringChanged();
    
    private slots:
        void updateMyString();
    
    private:
        QString m_myString;
    
    };
    #endif // MYFUNCTIONS_H
    
    

    Now I am able to implement the iOs calls in an myfunctions_ios.mm file:

    #include "myfunctions.h"
    // include native libraries and functions
    
    // For Native iOS Functions
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    
    @interface QIOSApplicationDelegate
    @end
    
    @interface QIOSApplicationDelegate(AppDelegate)
    @end
    
    @implementation QIOSApplicationDelegate (AppDelegate)
    @end
    
    MyFunctions:: MyFunctions(QObject *parent) : QObject(parent){
        connect(this, SIGNAL(myStringChanged()), this, SLOT(updateMyString()));
    }
    
    void MyFunctions::setMyString(const QString &string) {
        m_myString = string;
        emit myStringChanged();
    }
    
    QString MyFunctions::myString() const {
        return m_myString;
    }
    
    void MyFunctions::updateMyString() {
        NSLog(@"iOS updateMyString with current value: %@", m_notification.toNSString());
    
        // call external Library
        // [LIB function: params]
    }
    
    

    and for android in myfunctions_android.cpp:

    #include "myfunctions.h"
    
    #include <QtAndroidExtras>
    
    
    MyFunctions:: MyFunctions(QObject *parent) : QObject(parent){
        connect(this, SIGNAL(myStringChanged()), this, SLOT(updateMyString()));
    }
    
    void MyFunctions::setMyString(const QString &string) {
        m_myString = string;
        emit myStringChanged();
    }
    
    QString MyFunctions::myString() const {
        return m_myString;
    }
    
    void MyFunctions::updateMyString() {
        // call JNI function
        QAndroidJniObject javaNotification = QAndroidJniObject::fromString(m_myString);
        QAndroidJniObject::callStaticMethod<void>("path/to/my/class",
                                           "method name",
                                           "(Ljava/lang/String;)V",
                                           javaNotification.object<jstring>());
    }
    
    

    So I need an additional .java file to implement the function called per JNI from above.
    I have managed to get along with this so far,
    but now I need a callback or something like this, to return changes from inside the iOs/Android Application back to my QML app.

    For iOs this wasn't much of a problem, because I was able to just emit signals directly from the myfunctions_ios.mm file.

    But how do I achieve this in Android?

    Is there a way back from my Android .java code, back to Qml?
    How can I notify my QML app if something on the android device is changed (for example permissions, push-notifications, ...) ?

    Can anyone suggest me, how to solve this or point me into any direction?

    best Regards,
    SyntaX

    1 Reply Last reply
    0
    • M Offline
      M Offline
      Marc_Van_Daele
      wrote on last edited by
      #2

      This should help: https://doc.qt.io/qt-5/qandroidjniobject.html#java-native-methods
      Basically you have to

      • define your C++ functions that will be called from Java
      • register these functions
      • declare them in java using the "native" keyword
      • call them in java as normal functions

      Hope this helps,

      Marc

      1 Reply Last reply
      1
      • SyntaXS Offline
        SyntaXS Offline
        SyntaX
        wrote on last edited by
        #3

        thanks for your reply, this was indeed very helpful :D

        I declared my "callback" function in the .java file with the native keyword:

        public class MyJavaClass {
        
            // callback handler to send notifications back to c++
            public static native void StringChanged(String mystring);
        
            public void doSomeStuff () {
                // do stuff, then emit changes back to c++
                StringChanged("my new string");
            }
        }
        

        Then I registered those functions in my implementation

        void StringChangeReceived(JNIEnv *env, jobject obj, jstring newstring) {
        
            Q_UNUSED(obj)
        
            QString qString(env->GetStringUTFChars(newstring, 0));
            qDebug().noquote().nospace() << "callback from Android received: " << qString;
        
            // to be able to emit the changes I either need an instance or (what I decided) a classic singleton
            if (nullptr != instance) {
                instance->myStringChanged(qString);
            }
        }
        
        void init () {
            // install callback for notifications received
            QAndroidJniEnvironment env;
            JNINativeMethod methods[] = {
                {
                    "StringChanged",
                    "(Ljava/lang/String;)V",
                    reinterpret_cast<void*>(StringChangeReceived)
                }
            };
            QAndroidJniObject javaClass("path/to/my/JavaClass");
            jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
        
            env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0]));
            env->DeleteLocalRef(objectClass);
        }
        

        With this I realised at least a most basic full roundtrip, from my qml -> over the c++ class -> to the native java class on the android device -> and back over c++ -> to qml. :DDD

        Is it common practice to use that in combination with singletons? (Because I think I need them everywhere because of the static call?)
        Are there best practices or key values to that kind of implementation?

        best regards
        an thank you very much,

        SyntaX

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved