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
Forum Updated to NodeBB v4.3 + New Features

Callback from Android to QML

Scheduled Pinned Locked Moved Solved Mobile and Embedded
3 Posts 2 Posters 921 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