使用JNI将字符串从java传递到c ++

时间:2014-08-06 15:08:46

标签: java c++ qt java-native-interface signals-slots

我有一个Android应用程序,可以获取未读的Facebook通知和收件箱。应用程序必须在QT中完成,但我几乎不了解QT C ++,因此我在java中开发了应用程序,并使用JNI从QT调用java类。这工作正常,但问题是我每次有新的Facebook通知/消息时都需要发送一个插槽(在QT端)。

所以我的问题是:每分钟,如何从Java通知QT我有新消息并发送字符串?

这是我的java代码:

主要课程:

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(每分钟验证是否有新的Facebook消息,如果是,则假设通知QT并发送消息,以便QT能够发送一个插槽)

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

QT方

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

建筑时的错误

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

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

每一个帮助都会非常有帮助

3 个答案:

答案 0 :(得分:2)

如果我没有这样做,我可能会选择这条道路:

  • 定义本机Java方法。它将用作您的信号&#34;来自Java方面
  • 为您的本机方法实现C ++实现。操纵要通告的实例(插槽所有者)
  • 注册您的原生方法

在Java类中:

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);
    }
//...

在C ++ / Qt方面:

单身实施:

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

本机方法实现:

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

由于我们只能通过静态方法执行此操作,因此我必须在类中定义一个单例,以便仅访问一个实例。

方法注册:

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

经过一番研究,我发现了一个特别有用的complete example。它的目的是实现InApp购买,但机制与我在这个答案中描述的完全相同。

答案 1 :(得分:0)

由于您定期检查Java中的通知,您是否可以定期从Qt / C ++调用Java类,然后接收数据。这可以使用QTimer轻松完成,我发现你已经实现了从Qt调用java类。

答案 2 :(得分:0)

我认为RegisterNatives是关键所在:

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("Hello %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;
    /*
     * more of 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;
}

在MainAcitivty.java中包含原生声明。

public static void native sendToQT(String notification);