1.Jni的介绍
先简单介绍一下,Jni简称(Java Native Interface)Java原生接口,在Java里面用Native修饰的方法由另外一种语言实现的本地方法,意思就是说,这个用native修饰的方法在Java里面只能看到声明看不到定义。
下面这张图介绍了JNI的基本结构描述图:
2.在C++中调用Java方法
JVM:是java虚拟机,所有的交互工作都是从获取jvm开始的,获取JVM的时候需要注意下面,就是要告知系统使用哪一版本的JNI不规定的话默认使用1.1版本。最好是使用新版本JNI_VERSION_1_4,就是1.4版本。
JavaVM* JniHelper::_psJavaVM = nullptr; jmethodID JniHelper::loadclassMethod_methodID = nullptr; jobject JniHelper::classloader = nullptr; JavaVM* JniHelper::getJavaVM() { pthread_t thisthread = pthread_self(); LOGD("JniHelper::getJavaVM(),pthread_self() = %ld",thisthread); return _psJavaVM; } void JniHelper::setJavaVM(JavaVM *javaVM) { pthread_t thisthread = pthread_self(); LOGD("JniHelper::setJavaVM(%p),javaVM,thisthread); _psJavaVM = javaVM; pthread_key_create(&g_key,_detachCurrentThread); }这上面的代码是Cocos里面封装好的JniHelper里面的获取JVM的一些相关操作,
void _detachCurrentThread(void* a) { cocos2d::JniHelper::getJavaVM()->DetachCurrentThread(); }
这个方法要Detach以下当前线程。
#include "JniHelper.h" #include <android/log.h> #include <string.h> #include <pthread.h> #define LOG_TAG "JniHelper" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,__VA_ARGS__) static pthread_key_t g_key;//用于声明线程ID jclass _getClassID(const char *className) {//获取类ID if (nullptr == className) { return nullptr; } JNIEnv* env = cocos2d::JniHelper::getEnv();//环境变量 jstring _jstrClassName = env->NewStringUTF(className);//需要调用java的类名 jclass _clazz = (jclass) env->CallObjectMethod(cocos2d::JniHelper::classloader,cocos2d::JniHelper::loadclassMethod_methodID,_jstrClassName); if (nullptr == _clazz) { LOGE("Classloader Failed to find class of %s",className); env->ExceptionClear(); } env->DeleteLocalRef(_jstrClassName); return _clazz; } void _detachCurrentThread(void* a) { cocos2d::JniHelper::getJavaVM()->DetachCurrentThread();//撤销当前线程 } namespace cocos2d { JavaVM* JniHelper::_psJavaVM = nullptr; jmethodID JniHelper::loadclassMethod_methodID = nullptr; jobject JniHelper::classloader = nullptr; JavaVM* JniHelper::getJavaVM() { pthread_t thisthread = pthread_self(); LOGD("JniHelper::getJavaVM(),thisthread); return _psJavaVM; } void JniHelper::setJavaVM(JavaVM *javaVM) { pthread_t thisthread = pthread_self();//是获得线程自身的ID LOGD("JniHelper::setJavaVM(%p),_detachCurrentThread); } JNIEnv* JniHelper::cacheEnv(JavaVM* jvm) { JNIEnv* _env = nullptr; // get jni environment jint ret = jvm->GetEnv((void**)&_env,JNI_VERSION_1_4);//获取1.4的Jni环境 switch (ret) { case JNI_OK : // Success! pthread_setspecific(g_key,_env); return _env; case JNI_EDETACHED : // Thread not attached if (jvm->AttachCurrentThread(&_env,nullptr) < 0) { LOGE("Failed to get the environment using AttachCurrentThread()"); return nullptr; } else { // Success : Attached and obtained JNIEnv! pthread_setspecific(g_key,_env); return _env; } case JNI_EVERSION : // Cannot recover from this error LOGE("JNI interface version 1.4 not supported"); default : LOGE("Failed to get the environment using GetEnv()"); return nullptr; } } JNIEnv* JniHelper::getEnv() { JNIEnv *_env = (JNIEnv *)pthread_getspecific(g_key); if (_env == nullptr) _env = JniHelper::cacheEnv(_psJavaVM); return _env; } bool JniHelper::setClassLoaderFrom(jobject activityinstance) { JniMethodInfo _getclassloaderMethod; if (!JniHelper::getMethodInfo_DefaultClassLoader(_getclassloaderMethod,"android/content/Context","getClassLoader","()Ljava/lang/ClassLoader;")) { return false; } jobject _c = cocos2d::JniHelper::getEnv()->CallObjectMethod(activityinstance,_getclassloaderMethod.methodID); if (nullptr == _c) { return false; } JniMethodInfo _m; if (!JniHelper::getMethodInfo_DefaultClassLoader(_m,"java/lang/ClassLoader","loadClass","(Ljava/lang/String;)Ljava/lang/Class;")) { return false; } JniHelper::classloader = cocos2d::JniHelper::getEnv()->NewGlobalRef(_c); JniHelper::loadclassMethod_methodID = _m.methodID; return true; } bool JniHelper::getStaticMethodInfo(JniMethodInfo &methodinfo,//下面重点说一下这个函数 const char *className,const char *methodName,const char *paramCode) { if ((nullptr == className) || (nullptr == methodName) || (nullptr == paramCode)) { return false; } JNIEnv *env = JniHelper::getEnv(); if (!env) { LOGE("Failed to get JNIEnv"); return false; } jclass classID = _getClassID(className); if (! classID) { LOGE("Failed to find class %s",className); env->ExceptionClear(); return false; } jmethodID methodID = env->GetStaticMethodID(classID,methodName,paramCode); if (! methodID) { LOGE("Failed to find static method id of %s",methodName); env->ExceptionClear(); return false; } methodinfo.classID = classID; methodinfo.env = env; methodinfo.methodID = methodID; return true; } bool JniHelper::getMethodInfo_DefaultClassLoader(JniMethodInfo &methodinfo,const char *className,const char *paramCode) { if ((nullptr == className) || (nullptr == methodName) || (nullptr == paramCode)) { return false; } JNIEnv *env = JniHelper::getEnv(); if (!env) { return false; } jclass classID = env->FindClass(className); if (! classID) { LOGE("Failed to find class %s",className); env->ExceptionClear(); return false; } jmethodID methodID = env->GetMethodID(classID,paramCode); if (! methodID) { LOGE("Failed to find method id of %s",methodName); env->ExceptionClear(); return false; } methodinfo.classID = classID; methodinfo.env = env; methodinfo.methodID = methodID; return true; } bool JniHelper::getMethodInfo(JniMethodInfo &methodinfo,const char *paramCode) { if ((nullptr == className) || (nullptr == methodName) || (nullptr == paramCode)) { return false; } JNIEnv *env = JniHelper::getEnv(); if (!env) { return false; } jclass classID = _getClassID(className); if (! classID) { LOGE("Failed to find class %s",methodName); env->ExceptionClear(); return false; } methodinfo.classID = classID; methodinfo.env = env; methodinfo.methodID = methodID; return true; } std::string JniHelper::jstring2string(jstring jstr) { if (jstr == nullptr) { return ""; } JNIEnv *env = JniHelper::getEnv(); if (!env) { return nullptr; } const char* chars = env->GetStringUTFChars(jstr,nullptr); std::string ret(chars); env->ReleaseStringUTFChars(jstr,chars); return ret; } } //namespace cocos2d
这里面实现了在C++方面获取到Java的虚拟机,还有java运行环境,还有需要调用的类名等,上面的getStaticMethodInfo方法用来判断Java的类静态函数是否存在,并且初始化info。下面介绍一下参数
- JniMethodInfo &methodinfo
- const char *className
- const char *methodName
- const char *paramCode
这里重点说明一下这些参数的作用,
methodinfo:是一个结构体参数,JNIEnv*和java.lang.Class对象、函数ID。
这样就可以使用JNIEnv*调用 CallStaticXXXMethod(jclass clazz,jmethodID methodID,…)和 CallXXXMethod(jobject obj,…)等常用函数(XXX替换为函数返回值类型,如:Void,Int等)。
有关签名类型可以参考一下说明:
这里要贴这个结构体的有关信息
typedef struct JniMethodInfo_ { JNIEnv * env; jclass classID; jmethodID methodID; } JniMethodInfo;
Oracle上面有关jni的文档,走你
下面我把info的代码贴出来。
bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME,"LoginWX","(Ljava/lang/String;Ljava/lang/String;)V"); if (isHave) { jstring jAPP_ID = minfo.env->NewStringUTF(APP_ID); jstring jAppSecret = minfo.env->NewStringUTF(AppSecret); minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID,jAPP_ID,jAppSecret); minfo.env->DeleteLocalRef(jAPP_ID); minfo.env->DeleteLocalRef(jAppSecret); minfo.env->DeleteLocalRef(minfo.classID); cocos2d::log("JniFun call LoginWX over!"); } else { //NoticeMsg::Instance().Showlogon(false); cocos2d::log("JniFun call LoginWX error!"); }
这里就先这样吧,简简单单说了一下Jni的作用,后面更详细的内容深入了解之后再做记录,就这样。
QQ:763949771,有问题加我QQ深入交流一下,备注:csdn