Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing strings from java to c++ using JNI

I have an android app that gets unread Facebook notifications and Inbox. The application has to be done in QT, but I barely know QT C++ , so I developed the app in java and just call the java class from QT using JNI. This is working ok, but the thing is I need to send a slot (in QT side) every time there is a new Facebook notification/message.

So my question is: every minute, How do I notify QT from Java that I have a new message and send the string?

This is my java code:

MAIN CLASS:

public class MainActivity extends FragmentActivity {
...
static public void startFacebookActivity() {
    String msgTag = "FACEBOOK_APP";
    try {
        Activity mother = QtNative.activity();
        Intent intent = new Intent(mother, MainActivity.class);
        mother.startActivity(intent);
    } catch (Exception e) {
        Log.e(msgTag, e.toString());
        e.printStackTrace();
    }
}
}

FRAGMENT CLASS (Every minute verifies if there's a new facebook message , if so , It is suppose to notify QT and send the message so QT is able to send a slot )

private static native void publishNotification(String notification);
....
if (newNotification==true)
    publishNotification(responseNotification);
...

QT side

facebookAndroid.cpp

#include "facebookAndroid.h"
#include <QtAndroidExtras>

FacebookAndroid* FacebookAndroid::s_instance = 0;

FacebookAndroid::FacebookAndroid(QObject *parent) : QObject(parent) { s_instance = this;}

void FacebookAndroid::startAndroidFacebook() {
    QAndroidJniObject::callStaticMethod<void>("org.qtproject.example.MainActivity",
                                              "startFacebookActivity",
                                              "()V");
}

FacebookAndroid* FacebookAndroid::instance() {
    return s_instance;
}

static void publishNotification(JNIEnv *env, jclass /*clazz*/, jstring notification)      {
    const char* nativeString = env->GetStringUTFChars(notification, 0);
    FacebookAndroid::instance()->handleNewNotification(QString(nativeString));
}

static JNINativeMethod methods[] = {
    {"publishNotification", "(Ljava/lang/String;)V", (void *)publishNotification}
};

jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK)
        return JNI_FALSE;

    jclass clazz = env->FindClass("org/qtproject/example/MainActivity");
    if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0)
        return JNI_FALSE;

    return JNI_VERSION_1_4;
}

main.cpp

 #include <QtGui/QGuiApplication>
 #include "qtquick2applicationviewer.h"
 #include <QtQuick>
 #include "facebookAndroid.h"

 int main(int argc, char *argv[])
 {
     QGuiApplication app(argc, argv);

     QtQuick2ApplicationViewer viewer;
     FacebookAndroid sa(&viewer);
     viewer.rootContext()->setContextProperty(QString("iniciaFacebook"), &sa);
     viewer.setMainQmlFile(QStringLiteral("qml/FacebookTry/main.qml"));
     viewer.showExpanded();

     return app.exec();
 }

facebookAndroid.h

    #ifndef FACEBOOKANDROID_H
    #define FACEBOOKANDROID_H
    #include <QObject>
    #include <jni.h>

    class FacebookAndroid : public QObject {
        Q_OBJECT

    public:
        FacebookAndroid(QObject *parent = 0);
        FacebookAndroid* instance();
            void handleNewNotification(QString notification);

            protected:
            static FacebookAndroid *s_instance;

    public slots:
        void startAndroidFacebook();
    };

    #endif // FACEBOOKANDROID_H

ERRORS WHILE BUILDING

In function 'void publisNotification(JNIEnv*, jclass,jstring)'

cannot call member function 'FacebookAnddroid::instance()' without object
   FacebookAndroid::instance()->handleNewNotification(QString(nativeString));
   in facebookAndroid.cpp

every help would be very helpful

like image 462
Dany19 Avatar asked Aug 06 '14 15:08

Dany19


1 Answers

If I had t do it, I will probably choose this path:

  • Define a native Java method. It will be use as your "signal" from the Java side
  • Implement a C++ implementation for your native method. Manipulate the instance to be advertised (the slot owner)
  • Register your native method

In in your Java class:

class Main Activity {
// ...
private static native void publishNotification(String notification);
// Call it from your Java code as it has a proper implementation

//...
    if (newNotification) {
        publishNotification(notification);
    }
//...

On the C++/Qt side:

Singleton implementation:

//in facebookandroid.h
class FacebookAndroid {
    public:
    FacebookAndroid* instance();
    void handleNewNotification(QString notification);

    protected:
    static FacebookAndroid *s_instance;
};

//in facebookandroid.cpp
FacebookAndroid* FacebookAndroid::s_instance = 0;

FacebookAndroid::FacebookAndroid(QObject *parent) : QObject(parent) {
    s_instance = this; // remind your first instanciation here
}

FacebookAndroid* FacebookAndroid::instance() {
    return s_instance;
}

Native method implementation:

//In facebookandroid.cpp
static void publishNotifcation(JNIEnv *env, jclass /*clazz*/, jstring notification)      {
    const char* nativeString = env->GetStringUTFChars(notification, 0);
    FacebookAndroid::instance()->handleNewNotification(QString(nativeString));
}

As we can only do this by a static method, I have to define a singleton out of my class to access only one instance in particular.

Method registration:

//In facebookandroid.cpp
static JNINativeMethod methods[] = {
    {"publishNotification", "(Ljava/lang/String;)V", (void *)publishNotification}
};

jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_4) != JNI_OK)
        return JNI_FALSE;

    jclass clazz = env->FindClass("org/qtproject/example/MainActivity");
    if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0)
        return JNI_FALSE;

    return JNI_VERSION_1_4;
}

After some research, I found a particularly useful and complete example. Its purpose is to implement InApp purchase, but the mechanism are exactly the same I describe in this answer.

like image 103
epsilon Avatar answered Oct 19 '22 09:10

epsilon