Pasando cadenas de Java a C++ usando JNI
qt signals-slots (3)
Tengo una aplicación para Android que recibe notificaciones de Facebook y Bandeja de entrada no leídos. La aplicación tiene que hacerse en QT, pero apenas conozco QT C ++, así que desarrollé la aplicación en Java y llamé a la clase java desde QT usando JNI. Esto está funcionando bien, pero el problema es que necesito enviar un espacio (en el lado de QT) cada vez que haya un nuevo mensaje / notificación de Facebook.
Entonces mi pregunta es: cada minuto, ¿cómo notifico a QT de Java que tengo un nuevo mensaje y envío la cadena?
Este es mi código de Java:
CLASE PRINCIPAL:
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();
}
}
}
CLASE DE FRAGMENTOS (cada minuto verifica si hay un nuevo mensaje de Facebook, en caso afirmativo, se debe notificar a QT y enviar el mensaje para que QT pueda enviar un espacio)
private static native void publishNotification(String notification);
....
if (newNotification==true)
publishNotification(responseNotification);
...
Lado 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
ERRORES MIENTRAS CONSTRUYE
In function ''void publisNotification(JNIEnv*, jclass,jstring)''
cannot call member function ''FacebookAnddroid::instance()'' without object
FacebookAndroid::instance()->handleNewNotification(QString(nativeString));
in facebookAndroid.cpp
cada ayuda sería muy útil
Como está comprobando periódicamente las notificaciones en Java, ¿podría llamar periódicamente a la clase Java de Qt / C ++ que luego recibe los datos? Esto podría hacerse fácilmente usando QTimer y veo que ya has implementado la llamada de la clase java desde Qt.
Creo que RegisterNatives es la clave aquí:
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;
}
Incluya una declaración nativa en su MainAcitivty.java.
public static void native sendToQT(String notification);
Si no lo hiciera, probablemente elijo este camino:
- Definir un método nativo de Java. Se usará como su "señal" desde el lado de Java
- Implemente una implementación C ++ para su método nativo. Manipular la instancia que se anunciará (el propietario de la ranura)
- Registre su método nativo
En tu clase de 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);
}
//...
En el lado C ++ / Qt:
Implementación Singleton:
//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;
}
Implementación de método nativo:
//In facebookandroid.cpp
static void publishNotifcation(JNIEnv *env, jclass /*clazz*/, jstring notification) {
const char* nativeString = env->GetStringUTFChars(notification, 0);
FacebookAndroid::instance()->handleNewNotification(QString(nativeString));
}
Como solo podemos hacerlo mediante un método estático, tengo que definir un singleton de mi clase para acceder solo a una instancia en particular.
Registro de método:
//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;
}
Después de algunas investigaciones, encontré un ejemplo particularmente útil y completo . Su propósito es implementar la compra de InApp, pero el mecanismo es exactamente el mismo que describo en esta respuesta.