How do I load my own Java class in C on Android?

后端 未结 2 1998
刺人心
刺人心 2020-12-08 06:22

I am trying to call some Java code that I wrote from C using the Android NDK. The application is a NativeActivity application. I have to access some functionality that is

相关标签:
2条回答
  • 2020-12-08 06:29

    Here is what I have abstracted from this link as mentioned by Klaimmore.

    There are a few ways to work around this:

    Do your FindClass lookups once, in JNI_OnLoad, and cache the class references for later use. Any FindClass calls made as part of executing JNI_OnLoad will use the class loader associated with the function that called System.loadLibrary (this is a special rule, provided to make library initialization more convenient). If your app code is loading the library, FindClass will use the correct class loader.*

    Pass an instance of the class into the functions that need it, by declaring your native method to take a Class argument and then passing Foo.class in.

    Cache a reference to the ClassLoader object somewhere handy, and issue loadClass calls directly. This requires some effort.

    0 讨论(0)
  • 2020-12-08 06:48

    The subtlety of my question, and why the documentation linked to by Klaimmore and Winston does not quite resolve the issue, stems from the fact that I am writing an app using the NativeActivity class. This means that there is never a Java stack with a local class loader available to me. There is no JNI_OnLoad call, there is no Java method calling into my native function, and there is no other way (that I am aware of) of getting ahold of a local ClassLoader object. Unfortunately, most of the Android JNI documentation is simply not written with NativeActivity in mind.

    However, there is a straightforward solution to this problem that can make your life much easier when writing apps using NativeActivity. Simply subclass NativeActivity in Java. This allows you to write and access arbitrary Java code from the beginning of your NativeActivity's instantiation, while still doing everything else in C as NativeActivity allows. It also allows you to set up your JNI calls from C in the manner described in those documents. Doing this looks something like the following:

    package com.example.my.package;
    
    import android.app.NativeActivity;
    import android.util.Log;
    
    public class MyNativeActivity extends NativeActivity {
      static {
        System.loadLibrary("my_ndk_lib");  
      }
    
      private static String TAG = "MyNativeActivity";
    
      public MyNativeActivity() {
        super();
        Log.v(TAG, "Creating MyNativeActivity");
      }
    
      public static void MyUsefulJavaFunction() {
        doSomethingAwesome();
      }
    }
    

    And in your C library:

    jint JNI_OnLoad(JavaVM* vm, void* reserved)
    {
      JNIEnv* env;
      if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
        return -1;
    
      globalMyNativeActivityClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "com/example/my/package/MyNativeActivity"));
    
      return JNI_VERSION_1_6;
    }
    

    Then at some point in C, you can do:

    // Some file.c
    void doSomethingAwesomeInJava() {
      JavaVM *vm = AndroidGetJavaVM(); // This returns a valid JavaVM object
      JNIEnv* env;
      (*vm)->AttachCurrentThread(vm, &env, 0);
    
      jmethodID myUsefulJavaFunction = (*env)->GetStaticMethodID(env, globalMyNativeActivityClass, "MyUsefulJavaFunction", "()V");
      (*env)->CallStaticVoidMethod(env, theActivityClass, myUsefulJavaFunction);
    
      (*env)->DeleteLocalRef(env, myUsefulJavaFunction);
    
      (*vm)->DetachCurrentThread(vm);
    }
    

    And that is the way I found to incorporate my own new Java classes with a NativeActivity app. Hopefully this will be useful to someone besides me.

    0 讨论(0)
提交回复
热议问题