Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Android register Java native methods
Forum Updated to NodeBB v4.3 + New Features

Android register Java native methods

Scheduled Pinned Locked Moved Solved Mobile and Embedded
4 Posts 2 Posters 2.1k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    Eligijus
    wrote on 4 Jul 2019, 10:23 last edited by
    #1

    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#details

    I can see that there is some kind of example provided.
    What is not clear to me is where should void 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);
    }
    
    R 1 Reply Last reply 4 Jul 2019, 13:29
    0
    • E Eligijus
      4 Jul 2019, 10:23

      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#details

      I can see that there is some kind of example provided.
      What is not clear to me is where should void 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);
      }
      
      R Offline
      R Offline
      raven-worx
      Moderators
      wrote on 4 Jul 2019, 13:29 last edited by
      #2

      @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.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      E 1 Reply Last reply 5 Jul 2019, 06:54
      1
      • R raven-worx
        4 Jul 2019, 13:29

        @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.

        E Offline
        E Offline
        Eligijus
        wrote on 5 Jul 2019, 06:54 last edited by
        #3

        @raven-worx

        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.

        1 Reply Last reply
        0
        • E Offline
          E Offline
          Eligijus
          wrote on 5 Jul 2019, 08:00 last edited by
          #4

          I have found a solution:
          If my java class is
          public class Bar
          then calling registerNativeMethods() somewhere in main works as expected.
          But if my java class extends from QtActivity public class Bar extends org.qtproject.qt5.android.bindings.QtActivity then I have to register it in JNI_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?

          1 Reply Last reply
          0

          1/4

          4 Jul 2019, 10:23

          • Login

          • Login or register to search.
          1 out of 4
          • First post
            1/4
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved