如何在调用JNI方法时获取Android上下文实例?

问题描述:

我已经阅读了一些与stackoverflow相关的答案,但似乎没有人回答我的问题。我会从本地代码中获取android ID,在C代码中调用方法getAndroidIDfromNativeCode(因此JVM通过create_vm方法在本机代码中进行插入),您知道调用方法getContentResolver时,必须使用一个Android上下文实例来调用它,所以如何得到这个上下文实例如何在调用JNI方法时获取Android上下文实例?

static jstring 
    native_code_getAndroidID(JNIEnv *env, jobject thiz) 
    { 
     jclass c_settings_secure = (*env)->FindClass(env, "android/provider/Settings$Secure"); 
     jclass c_context = (*env)->FindClass(env,"android/content/Context"); 
     if(c_settings_secure == NULL || c_context == NULL){ 
      return NULL; 
     } 
     //Get the getContentResolver method 
     jmethodID m_get_content_resolver = (*env)->GetMethodID(env, c_context, "getContentResolver", 
                   "()Landroid/content/ContentResolver;"); 
     if(m_get_content_resolver == NULL){ 
      return NULL; 
     } 
     //Get the Settings.Secure.ANDROID_ID constant 
     jfieldID f_android_id = (*env)->GetStaticFieldID(env, c_settings_secure, "ANDROID_ID", "Ljava/lang/String;"); 

     if(f_android_id == NULL){ 
      return NULL; 
     } 
     jstring s_android_id = (*env)->GetStaticObjectField(env, c_settings_secure, f_android_id); 

     //create a ContentResolver instance context.getContentResolver() 
     /* 
      where can I get the context instance from Anroid APP?? 
     */ 
     jobject o_content_resolver = (*env)->CallObjectMethod(env, context, m_get_content_resolver); 
     if(o_content_resolver == NULL || s_android_id == NULL){ 
      return NULL; 
     } 
     //get the method getString 
     jmethodID m_get_string = (*env)->GetStaticMethodID(env, c_settings_secure, "getString", 
                  "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;"); 

     if(m_get_string == NULL){ 
      return NULL; 
     } 
     //get the Android ID 
     jstring android_id = (*env)->CallStaticObjectMethod(env, c_settings_secure, 
                  m_get_string, 
                  o_content_resolver, 
                  s_android_id); 
     return android_id; 
    } 

    JNIEnv* create_vm() { 
     JavaVM* jvm; 
     JNIEnv* env; 
     JavaVMInitArgs args; 
     JavaVMOption options[1]; 

     /* There is a new JNI_VERSION_1_4, but it doesn't add anything for the purposes of our example. */ 
     args.version = JNI_VERSION_1_4; 
     args.nOptions = 1; 
     options[0].optionString = "-Djava.class.path=-jar-path"; 
     args.options = options; 
     args.ignoreUnrecognized = JNI_FALSE; 

     JNI_CreateJavaVM(&jvm, (void **)&env, &args); 
     return env; 
    } 

    char *jstringTostr(jstring android) 
    { 
     ... 
    } 

    //I will call this function from native code. 

    char *getAndroidIDfromNativeCode() 
    { 

     JNIEnv* env = NULL; 

     env = create_vm(); 
     jstring androidID = native_code_getAndroidID(env,NULL); 
     return jstringTostr(androidID); 

    } 
+0

只是好奇,你为不同的Android拱门部署了多少本地代码? –

+0

@UsagiMiyamoto只是改进一些Android媒体播放器的本地代码,它是开源的,有很多。 –

+0

我的意思是说,我自己知道至少有两个不同的Android版本:Intel Atom和ARM7 + ...您计划为每个版本提供您的本机代码? –

以下方法可以得到一个上下文实例

static jobject getGlobalContext(JNIEnv *env) 
{ 

    jclass activityThread = (*env)->FindClass(env,"android/app/ActivityThread"); 
    jmethodID currentActivityThread = (*env)->GetStaticMethodID(env,activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 
    jobject at = (*env)->CallStaticObjectMethod(env,activityThread, currentActivityThread); 

    jmethodID getApplication = (*env)->GetMethodID(env,activityThread, "getApplication", "()Landroid/app/Application;"); 
    jobject context = (*env)->CallObjectMethod(env,at, getApplication); 
    return context; 
} 

jobject类型的最后一个参数是要在其中保持固有方法声明的类的实例。

所以,如果你在一个活动中声明你的方法,你可以直接使用最后一个参数thiz作为你的上下文的一个实例。

否则,您需要在方法定义中在您的本地声明中添加Context类型的另一个参数,并键入jobject

+0

对不起,我的意思是,我应该传递给jobject或“另一个参数”的值是什么;当java调用c时,我们可以自动得到thiz,但是当调用java时,我们需要自己传递参数。 –