本节实现c调用java的静态方法
1、在jni文件夹下建
MyJniHelper.h,MyJniHelper.cpp 文件
2、编写MyJniHelper.h
#ifndef JNI_MYJNIHELPER_H_
#define JNI_MYJNIHELPER_H_
#include <jni.h>
#include <string.h>
namespace Hym {
typedef struct JniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
class MyJniHelper {
private:
//JavaVM虚拟机
static JavaVM *_psJavaVM;
//ClassLoader类的loadClass方法的MethodID;
static jmethodID _LoadClassMethodID;
//ClassLoader 对象 为全局引用
static jobject _classLoader;
public:
static void setJavaVM(JavaVM *javaVM);
static JavaVM * getJavaVM();
//从MainActivity实例获取 ClassLoader 与 loadClass
static bool setClassLoaderFromInstance(jobject activityInstance);
//获取java的静态方法
static bool getStaticMethodInfo(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode);
private:
//获取当前线程的env
static JNIEnv* getEnv();
//把线程中的env存在线程变量中
static JNIEnv* cacheEnv(JavaVM *jvm);
//获取对应java类的jclass
static jclass getClassID(const char *className);
//设置 JniMethodInfo 信息
static bool setMethodInfo(JniMethodInfo &methodInfo,
const char *className,
const char *methodName,
const char *paramCode);
};
} /* namespace Hym */
#endif /* JNI_MYJNIHELPER_H_ */
3、编写MyJniHelper.cpp文件
<span style="font-size:14px;">#include "MyJniHelper.h"
#include <pthread.h>
/*
* 打开jni.h会发现
* Prototypes for functions exported by loadable shared libs. These are
* called by JNI, not provided by JNI.
* JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);
* JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);
*/
using namespace Hym;
/*
* pthread_key_t
* 为每一个线程中单独存储变量
* 相当于每个线程都有pthread_key_t变量
*/
static pthread_key_t g_key;
JavaVM* MyJniHelper::_psJavaVM =nullptr;
jmethodID MyJniHelper::_LoadClassMethodID=nullptr;
jobject MyJniHelper::_classLoader =nullptr;
/*
* JNIEnv 如何获取 JavaVM->GetEnv()
* JavaVM 如何设置
*
* 首先获取类加载器
* 如何获取类加载器
* 获取类加载器有什么用
*/
/*
* 一、设置JavaVM
* 实现jni.h JNI_OnLoad方法
* 设置线程变量
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
Hym::MyJniHelper::setJavaVM(vm);
return JNI_VERSION_1_4;
}
void _detachCurrentThread(void* a) {
MyJniHelper::getJavaVM()->DetachCurrentThread();
}
void MyJniHelper::setJavaVM(JavaVM *javaVM){
_psJavaVM=javaVM;
/*
* 调用 pthread_key_create() 来创建pthread_key_t变量。
* 该函数有两个参数,
* 第一个参数就是 pthread_key_t 变量,
* 第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。
* 该函数指针可以设成 NULL ,这样系统将调用默认的清理函数。
*/
pthread_key_create(&g_key,_detachCurrentThread);
}
JavaVM * MyJniHelper::getJavaVM(){
return _psJavaVM;
}
/*
* 二、获取 JNIEnv
* 线程查找JNIEnv
* 把JNIEnv变量存入线程变量
*/
//获取 JNIEnv
//如果线程中没有JNIEnv 则去创建并放到线程变量中
JNIEnv* MyJniHelper::getEnv(){
//获取线程变量 JNIEnv
JNIEnv *env=(JNIEnv *)pthread_getspecific(g_key);
if(env==nullptr){
env=MyJniHelper::cacheEnv(_psJavaVM);
}
return env;
}
// 记录每个线程的 env
JNIEnv* MyJniHelper::cacheEnv(JavaVM *jvm){
JNIEnv *env=nullptr;
//GetEnv()
jint ret=jvm->GetEnv((void **)&env,JNI_VERSION_1_4);
switch(ret){
case JNI_OK:
/* no error */
//设置线程变量 JNIEnv
pthread_setspecific(g_key,env);return env;
case JNI_EDETACHED:
/* thread detached from the VM */
//确保它确实attach到Java环境里了。
if(jvm->AttachCurrentThread(&env,nullptr)<0){
return nullptr;
}else{
pthread_setspecific(g_key,env);
return env;
}
case JNI_EVERSION:
/* JNI version error */
default :
return nullptr;
}
}
/*
* 三、获取类加载器
* 1、先获取 getClassLoader 的jmethodID
* 2、通过 MainActivity对象 执行 getClassLoader方法 获取 ClassLoader
* 3、获取 ClassLoader 的 loadClass方法 的 jmethodID
* 4、之后就可以使用 ClassLoader.loadClass 获取 jclass
*/
//设置类加载器
bool MyJniHelper::setClassLoaderFromInstance(jobject activityInstance){
JniMethodInfo _classLoaderMethod;
if(!MyJniHelper::setMethodInfo(_classLoaderMethod,
"android/content/Context",
"getClassLoader",
"()Ljava/lang/ClassLoader;")) {
return false;
}
//activityInstance.getClassLoader()
jobject _classLoader = MyJniHelper::getEnv()->CallObjectMethod(activityInstance,
_classLoaderMethod.methodID);
if(nullptr== _classLoader){
return false;
}
//获取类加载器的loadClass方法
JniMethodInfo _loadClassMethod;
if (!MyJniHelper::setMethodInfo(_loadClassMethod,
"java/lang/ClassLoader",
"loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;")) {
return false;
}
//全局引用
MyJniHelper::_classLoader =MyJniHelper::getEnv()->NewGlobalRef(_classLoader);
MyJniHelper::_LoadClassMethodID=_loadClassMethod.methodID;
return true;
}
//设置 JniMethodInfo
bool MyJniHelper::setMethodInfo(JniMethodInfo &methodInfo,
const char *className,
const char *methodName,
const char *paramCode){
if (nullptr == className
||nullptr == methodName
||nullptr == paramCode) {
return false;
}
JNIEnv *env=MyJniHelper::getEnv();
if(!env){
return false;
}
/*
* FindClass 可以不使用加载器获取class
* 效果与之后使用一样 ClassLoader.loadClass 方法一样
*/
jclass classID = env->FindClass(className);
if(!classID){
env->ExceptionClear();
return false;
}
/*
* GetMethodID 获取对象方法
* GetStaticMethodID 获取静态方法
*/
jmethodID methodID=env->GetMethodID(classID,methodName,paramCode);
if(!methodID){
env->ExceptionClear();
return false;
}
methodInfo.classID=classID;
methodInfo.methodID=methodID;
methodInfo.env=env;
return true;
}
/*
* 四,获取 java的静态方法
*1、先获取jclass
*2、获取jmethodID
*3、设置JniMethodInfo
*/
//获取 jclass
jclass MyJniHelper::getClassID(const char *className){
if(nullptr==className){
return nullptr;
}
JNIEnv* env =MyJniHelper::getEnv();
jstring jClassName =env->NewStringUTF(className);
//使用ClassLoader.loadClass 获取class
jclass jclazz =(jclass)env->CallObjectMethod(MyJniHelper::_classLoader,
MyJniHelper::_LoadClassMethodID,
jClassName);
if(nullptr== jclazz){
env->ExceptionClear();
}
env->DeleteLocalRef(jClassName);
return jclazz;
}
//获取静态方法
bool MyJniHelper::getStaticMethodInfo(JniMethodInfo &methodinfo,
const char *className,
const char *methodName,
const char *paramCode){
if(nullptr==className
|| nullptr==methodName
|| nullptr==paramCode){
return false;
}
//获取 env
JNIEnv *env=MyJniHelper::getEnv();
if(env==nullptr){
return false;
}
jclass classID=MyJniHelper::getClassID(className);
if(! classID){
env->ExceptionClear();
return false;
}
jmethodID methodID=env->GetStaticMethodID(classID,methodName,paramCode);
if (! methodID) {
env->ExceptionClear();
return false;
}
methodinfo.classID = classID;
methodinfo.env = env;
methodinfo.methodID = methodID;
return true;
}</span>