Android register Java native methods
-
Hello,
I am trying to figure out how to call c++ methods from java side. Studying QAndroidJniObject documentation
https://doc.qt.io/qt-5/qandroidjniobject.html#detailsI can see that there is some kind of example provided.
What is not clear to me is where shouldvoid registerNativeMethods()
be called?void registerNativeMethods() { JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)}, {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}}; QAndroidJniObject javaClass("my/java/project/FooJavaClass"); QAndroidJniEnvironment env; jclass objectClass = env->GetObjectClass(javaClass.object<jobject>()); env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0])); env->DeleteLocalRef(objectClass); }
-
@Eligijus said in Android register Java native methods:
What is not clear to me is where should void registerNativeMethods() be called?
as early as possible.
If you have to, you can let your java code know that the methods have been registered by calling a Java method at the end of registerNativeMethods() method. Before that point no calls to native methods are allowed.
But note that Qt runs in a different thread than the Android UI thread, and so are the calls executed in this thread. -
But note that Qt runs in a different thread than the Android UI thread, and so are the calls executed in this thread.
I guess that is exactly my problem because I get this error:
F project.exampl: java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: JNI GetObjectClass called with pending exception java.lang.RuntimeException: Can't create handler inside thread Thread[qtMainLoopThread,5,main] that has not called Looper.prepare()
And I tried to run registerNativeMethods() before creating QGuiApplication after creating it and in qml Component.onCompleted signal handler. Not sure what to do about this.
-
I have found a solution:
If my java class is
public class Bar
then callingregisterNativeMethods()
somewhere in main works as expected.
But if my java class extends from QtActivitypublic class Bar extends org.qtproject.qt5.android.bindings.QtActivity
then I have to register it inJNI_OnLoad
.
Example from https://www.kdab.com/qt-android-episode-5/ :// define our native method static void fibonaciResult(JNIEnv */*env*/, jobject /*obj*/, jint n) { qDebug() << "Computed fibonacci is:" << n; } // step 2 // create a vector with all our JNINativeMethod(s) static JNINativeMethod methods[] = { { "sendFibonaciResult", // const char* function name; "(I)V", // const char* function signature (void *)fibonaciResult // function pointer } }; // step 1 // this method is called automatically by Java VM // after the .so file is loaded JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) { JNIEnv* env; // get the JNIEnv pointer. if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } // step 3 // search for Java class which declares the native methods jclass javaClass = env->FindClass("com/kdab/training/MyJavaNatives"); if (!javaClass) return JNI_ERR; // step 4 // register our native methods if (env->RegisterNatives(javaClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { return JNI_ERR; } return JNI_VERSION_1_6; }
Not sure why it has to be done this way maybe someone with more knowledge could provide more information?