7 Stimmen

Übertragung von Zeichenfolgen von Java nach C++ mit JNI

Ich habe eine Android-App, die ungelesene Facebook-Benachrichtigungen und Posteingänge abruft. Die Anwendung muss in QT erstellt werden, aber ich kenne QT C++ kaum, deshalb habe ich die App in Java entwickelt und rufe die Java-Klasse einfach von QT aus mit JNI auf. Das funktioniert gut, aber ich muss jedes Mal einen Slot (auf der QT-Seite) senden, wenn es eine neue Facebook-Benachrichtigung/Nachricht gibt.

Also meine Frage ist: Wie benachrichtige ich QT aus Java heraus jede Minute darüber, dass ich eine neue Nachricht habe und die Zeichenfolge sende?

Das ist mein Java-Code:

Hauptklasse:

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();
    }
}
}

Fragmentklasse (Überprüft jede Minute, ob eine neue Facebook-Nachricht vorhanden ist. Wenn ja, sollte sie QT benachrichtigen und die Nachricht senden, damit QT in der Lage ist, einen Slot zu senden.)

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

QT-Seite

facebookAndroid.cpp

#include "facebookAndroid.h"
#include 

FacebookAndroid* FacebookAndroid::s_instance = 0;

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

void FacebookAndroid::startAndroidFacebook() {
    QAndroidJniObject::callStaticMethod("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(&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 
 #include "qtquick2applicationviewer.h"
 #include 
 #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 
    #include 

    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

FEHLER BEIM BAUEN

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

kann die Membervariable 'FacebookAnddroid::instance()' nicht ohne Objekt aufgerufen werden
   FacebookAndroid::instance()->handleNewNotification(QString(nativeString));
   in facebookAndroid.cpp

Jede Hilfe wäre sehr hilfreich.

4voto

epsilon Punkte 2849

Wenn ich es tun müsste, würde ich wahrscheinlich diesen Weg wählen:

  • Definieren Sie eine native Java-Methode. Diese wird auf der Java-Seite als Ihr "Signal" verwendet
  • Implementieren Sie eine C++-Implementierung für Ihre native Methode. Manipulieren Sie die Instanz, die beworben werden soll (der Slot-Besitzer)
  • Registriere deine native Methode

In Ihrer Java-Klasse:

class MainActivity {
// ...
private static native void publishNotification(String notification);
// Rufen Sie es aus Ihrem Java-Code auf, da es eine ordnungsgemäße Implementierung hat

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

Auf der C++/Qt-Seite:

Singleton-Implementierung:

// 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; // erinnern Sie an Ihre erste Instanziierung hier
}

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

Native Method-Implementierung:

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

Da wir dies nur über eine statische Methode tun können, muss ich einen Singleton außerhalb meiner Klasse definieren, um nur auf eine bestimmte Instanz zuzugreifen.

Methodenregistrierung:

// 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(&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;
}

Nach einigen Recherchen habe ich ein besonders nützliches und vollständiges Beispiel gefunden. Sein Zweck ist es, In-App-Käufe zu implementieren, aber der Mechanismus ist genau derselbe, den ich in dieser Antwort beschreibe.

0voto

astre Punkte 807

Da Sie regelmäßig nach Benachrichtigungen in Java suchen, wäre es möglich, dass Sie regelmäßig die Java-Klasse von Qt/C++ aus aufrufen, die dann die Daten empfängt. Dies könnte einfach mit QTimer erledigt werden und ich sehe, dass Sie bereits die Java-Klasse von Qt aus aufgerufen haben.

0voto

mesh Punkte 849

Ich denke, RegisterNatives ist hier der Schlüssel:

http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp17734

static void sendToQT(JNIEnv *env, jclass clazz, jstring notification) {
  const char *GotInQTTheNotification = (*env)->GetStringUTFChars(env, notification, NULL);
      printf("Hallo %s\n", GotInQTTheNotification );
      (*env)->ReleaseStringUTFChars(env, notification, GotInQTTheNotification );
  }
}

static JNINativeMethod method_table[] = {
  { "sendToQT", "(Ljava/lang/String;I)V", (void *) sendToQT }
};

int main(int argc, char *argv[])
{
    JavaVM *vm;
    JNIEnv *env;
    /*
     * mehr Code
     */
    jclass clazz = (*env)->FindClass(env, "org/qtproject/example/MainActivity");
    jint ret = (*env)->RegisterNatives(env, clazz, method_table, method_table_size);    

    vm->DestroyJavaVM();

    return 0;
}

Fügen Sie eine native Deklaration in Ihrer MainAcitivty.java hinzu.

public static void native sendToQT(String notification);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X