android jni 异常处理
说明:jni中没有try...catch... throw 等方法来处理异常,引发的异常的env对象不处理,会继续运行至下一个env对象之前。此时需要通过env来处理异常。分为三种,直接清除,抛给java,程序退出,代码如下:(结合动态注册的文章食用)
#include <jni.h> #include <string> #include <android/log.h> // // Created by 15155 on 2022/11/23. // #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "yuanrenxue->", __VA_ARGS__) extern "C" JNIEXPORT jstring JNICALL Java_com_yuanrenxue_course6_14_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } extern "C" JNIEXPORT void JNICALL Java_com_yuanrenxue_course6_14_MainActivity_demo(JNIEnv *env, jobject thiz) { // TODO: implement demo() __android_log_print((int) 6, "yuanrenxue->", "run here."); __android_log_print((int) 6, "yuanrenxue->", "current jni version %d", env->GetVersion()); // jint version = env->GetVersion(); 获取JNI 版本 // JNI_VERSION_1_6; //#define JNI_VERSION_1_1 0x00010001 //#define JNI_VERSION_1_2 0x00010002 //#define JNI_VERSION_1_4 0x00010004 //#define JNI_VERSION_1_6 0x00010006 //类操作 //1.获取对象Class jcalss com.yuanrenxue.course6_4 MysteryBox jclass mysteryBoxClass = env->FindClass("com/yuanrenxue/course6_4/MysteryBox"); jclass clsClazz = env->GetObjectClass(mysteryBoxClass); jmethodID jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;"); auto className = (jstring) env->CallObjectMethod(mysteryBoxClass, jmethodId); const char *str = env->GetStringUTFChars(className, nullptr); LOGD("获取对象 MysteryBox_Class_Name == %s", str); // 2.获取一个类的父类 jclass parentClass = env->GetSuperclass(mysteryBoxClass); clsClazz = env->GetObjectClass(parentClass); jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;"); className = (jstring) env->CallObjectMethod(parentClass, jmethodId); str = env->GetStringUTFChars(className, nullptr); LOGD("获取一个类的父类 MysteryBox_Parent_Class_Name == %s",str); //3.判断类型1是否可以安全的转换为类型2 jboolean IsAssignableFrom = env->IsAssignableFrom(mysteryBoxClass, parentClass); LOGD("判断类型1是否可以安全的转换为类型2 mysteryBoxClass IsAssignableFrom parentClass== %d", IsAssignableFrom); //对象操作 //1.不通过构造函数生成对象 jobject mysteryBoxCObject = env->AllocObject(mysteryBoxClass); jmethodID toString_methodID = env->GetMethodID(mysteryBoxClass, "toString", "()Ljava/lang/String;"); auto mysteryBoxCObject_toString_methodID = (jstring) env->CallObjectMethod(mysteryBoxCObject, toString_methodID); str = env->GetStringUTFChars(mysteryBoxCObject_toString_methodID, nullptr); LOGD("不通过构造函数生成对象 mysteryBoxCObject_toString_methodID== %s", str); //2.通过构造函数生成对象 jmethodID initMethod = env->GetMethodID(mysteryBoxClass, "<init>", "()V"); jobject MysteryObject2 = env->NewObject(mysteryBoxClass, initMethod); toString_methodID = env->GetMethodID(mysteryBoxClass, "toString", "()Ljava/lang/String;"); auto MysteryObject2_toString_methodID = (jstring) env->CallObjectMethod( MysteryObject2, toString_methodID); str = env->GetStringUTFChars(MysteryObject2_toString_methodID, nullptr); LOGD("通过构造函数生成对象 mysteryBoxClass, <init>, ()V== %s", str); //3.根据对象获取对应的类 mysteryBoxClass = env->GetObjectClass(mysteryBoxCObject); clsClazz = env->GetObjectClass(mysteryBoxClass); jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;"); className = (jstring) env->CallObjectMethod(mysteryBoxClass, jmethodId); str = env->GetStringUTFChars(className, nullptr); LOGD("根据对象获取对应的类 MysteryBox_Class_Name == %s", str); //4.判断某个对象是否为特定的实例 jboolean IsInstanceOf = env->IsInstanceOf(mysteryBoxCObject, mysteryBoxClass); LOGD("判断某个对象是否为特定的实例 IsInstanceOf == %hhu",IsInstanceOf); //属性操作 //1.获取非静态成员属性的ID mysteryBoxCObject price jfieldID price_filed_id = env->GetFieldID(mysteryBoxClass, "price", "I"); //2.获取非静态成员属性的值(方法的合集) jint price = env->GetIntField(MysteryObject2, price_filed_id); LOGD("获取非静态成员属性的值 price == %d",price); //3.设置非静态成员属性的值(方法的合集) env->SetIntField(MysteryObject2, price_filed_id, 20); price = env->GetIntField(MysteryObject2, price_filed_id); LOGD("设置非静态成员属性的值 price == %d",price); //4.获取静态成员属性的ID MysteryBox BASE_PRICE jfieldID BASE_PRICE_filed_id = env->GetStaticFieldID(mysteryBoxClass, "BASE_PRICE", "I"); //5.获取静态成员属性的值 jint static_price = env->GetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id); LOGD("获取静态成员属性的值 BASE_PRICE == %d",static_price); //6.设置静态成员属性的值 env->SetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id, 666); static_price = env->GetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id); LOGD("设置静态成员属性的值 BASE_PRICE == %d",static_price); //方法的操作 getContent //1.获取非静态方法id jmethodID getContentmethid = env->GetMethodID(mysteryBoxClass, "getContent", "()Ljava/lang/String;"); //2.调用非静态方法 auto getContent = (jstring) env->CallObjectMethod(MysteryObject2, getContentmethid); str = env->GetStringUTFChars(getContent, nullptr); LOGD("调用非静态方法 getContent == %s",str); //3.获取静态方法id staticMethod jmethodID staticMethodID = env->GetStaticMethodID(mysteryBoxClass, "staticMethod", "(Ljava/lang/String;I)Ljava/lang/String;"); //4.调用静态方法 jstring jstring1 = env->NewStringUTF("hell word!"); auto callstatic = (jstring) env->CallStaticObjectMethod(mysteryBoxClass, staticMethodID, jstring1, 30); str = env->GetStringUTFChars(callstatic, nullptr); LOGD("调用静态方法 callstatic == %s", str); /* * 2022-12-06 01:34:45.102 6536-6536/com.yuanrenxue.course6 D/yuanrenxue->: onCreate: run sucess!! 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: run here. 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: current jni version 65542 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取对象 MysteryBox_Class_Name == MysteryBox 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取一个类的父类 MysteryBox_Parent_Class_Name == MysteryParentBox 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 判断类型1是否可以安全的转换为类型2 mysteryBoxClass IsAssignableFrom parentClass== 1 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 不通过构造函数生成对象 mysteryBoxCObject_toString_methodID== MysteryBox{content='null', isOpened=false, price=0, brand='null'} 2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 通过构造函数生成对象 mysteryBoxClass, <init>, ()V== MysteryBox{content='普通款', isOpened=false, price=10, brand='手办盲盒'} 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 根据对象获取对应的类 MysteryBox_Class_Name == MysteryBox 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 判断某个对象是否为特定的实例 IsInstanceOf == 1 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取非静态成员属性的值 price == 10 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 设置非静态成员属性的值 price == 20 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取静态成员属性的值 BASE_PRICE == 10 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 设置静态成员属性的值 BASE_PRICE == 666 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 调用非静态方法 getContent == 这个盲盒没有打开哦 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 D/yuanrenxue->: staticMethod: name=hell word!, price=30 2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 调用静态方法 callstatic == 我是静态方法变量 */ } void OnCreate(JNIEnv *env, jobject thiz, jobject savedInstanceState) { //super.onCreate(savedInstanceState); jclass MainActivity_cls1 = env->GetObjectClass(thiz); jclass AppCompatActivity = env->GetSuperclass(MainActivity_cls1); jmethodID onCreate = env->GetMethodID(AppCompatActivity, "onCreate", "(Landroid/os/Bundle;)V"); env->CallNonvirtualVoidMethod(thiz, AppCompatActivity, onCreate, savedInstanceState); LOGD("super.onCreate(savedInstanceState);被调用"); //setContentView(R.layout.activity_main); jmethodID setContentView_mid = env->GetMethodID(MainActivity_cls1, "setContentView", "(I)V"); char *R_layout = "com/yuanrenxue/course6_4/R$layout"; jclass layout = env->FindClass(R_layout); jfieldID activity_main_fid = env->GetStaticFieldID(layout, "activity_main", "I"); jint activity_main = env->GetStaticIntField(layout, activity_main_fid); env->CallVoidMethod(thiz, setContentView_mid, activity_main); LOGD("setContentView(R.layout.activity_main); 被调用"); // //第一行:super.onCreate(savedInstanceState);因此首先需要获取superclass // jclass AppCompatActivity_cls1 = env->FindClass( // "androidx/appcompat/app/AppCompatActivity");//已经知道类名 // jclass MainActivity_cls1 = env->FindClass("com/yuanrenxue/course6_4/MainActivity"); ////调用这个函数protected void onCreate(@Nullable Bundle savedInstanceState) // jmethodID superclassOnCreate_mid = env->GetMethodID(AppCompatActivity_cls1, "onCreate", // "(Landroid/os/Bundle;)V"); // env->CallNonvirtualVoidMethod(thiz, AppCompatActivity_cls1, superclassOnCreate_mid, // savedInstanceState); // ////第二行:setContentView(R.layout.activity_main); // jmethodID setContentView_mid = env->GetMethodID(MainActivity_cls1, "setContentView", "(I)V"); // char *R_layout = "com/yuanrenxue/course6_4/R$layout"; // jclass R_layout_cls = env->FindClass(R_layout); // jfieldID activity_main_fid = env->GetStaticFieldID(R_layout_cls, "activity_main", // "I");//这里对应R$layout那个图看出来的 jint activity_main_value = env->GetStaticIntField(MainActivity_cls1, activity_main_fid); env->CallVoidMethod(thiz, setContentView_mid, activity_main_value); // private native String demoUTFString(); jmethodID demoUTFString = env->GetMethodID(MainActivity_cls1, "demoUTFString", "()Ljava/lang/String;"); auto str = (jstring) env->CallObjectMethod(thiz, demoUTFString); LOGD("private native String demoUTFString(); 被调用"); // Log.d(TAG, "onCreate: demoUTFString = " + this.demoUTFString()); jclass Log = env->FindClass("android/util/Log"); jmethodID d = env->GetStaticMethodID(Log, "d", "(Ljava/lang/String;Ljava/lang/String;)I"); jfieldID TAG_ID = env->GetStaticFieldID(MainActivity_cls1, "TAG", "Ljava/lang/String;"); jstring tag = static_cast<jstring>(env->GetStaticObjectField(MainActivity_cls1, TAG_ID)); env->CallStaticIntMethod(Log, d, tag, str); LOGD("Log.d(TAG, \"onCreate: demoUTFString = \" + this.demoUTFString()); 被调用"); jmethodID exceptionMId = env->GetMethodID(MainActivity_cls1,"exception", "()V"); env->CallVoidMethod(thiz,exceptionMId); LOGD("private native void exception(); 被调用"); } jint JNI_OnLoad(JavaVM *vm, void *reserved) { __android_log_print(6, "yuanrenxue->", "JNI_OnLoad函数被调用"); JNIEnv *env = nullptr; if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } //动态注册 // com.yuanrenxue.course6_4 jclass classzz = env->FindClass("com/yuanrenxue/course6_4/MainActivity"); /* * jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods) */ /* * typedef struct { const char* name; const char* signature; void* fnPtr; } JNINativeMethod; */ JNINativeMethod methods[] = { {"onCreate", "(Landroid/os/Bundle;)V", (void *) OnCreate} }; env->RegisterNatives(classzz, methods, 1); return JNI_VERSION_1_6; } ////同时静态注册 和 同时动态注册 会使用动态注册的 extern "C" JNIEXPORT void JNICALL Java_com_yuanrenxue_course6_14_MainActivity_exception(JNIEnv *env, jobject thiz) { // TODO: implement exception() jclass clazz = env->GetObjectClass(thiz); env->GetStaticFieldID(clazz, "test1", "Ljava/lang/String;"); //1.在nativate处理异常 不抛给java jthrowable jthrowable1 = env->ExceptionOccurred(); if (jthrowable1) { //进入这里表示出现了异常 小根据需求进行异常的处理 LOGD("在nativate处理异常 不抛给java"); env->ExceptionClear();//清除掉当前的异常,防止程序崩溃 env->GetStaticFieldID(clazz, "test", "Ljava/lang/String;"); } LOGD("在nativate处理异常 不抛给java"); //2.把异常抛给java env->GetStaticFieldID(clazz, "test1", "Ljava/lang/String;"); if (jthrowable1) { //进入这里表示出现了异常 小根据需求进行异常的处理 LOGD("把异常抛给java"); env->ExceptionDescribe(); env->ExceptionClear();//清除掉当前的异常,防止程序崩溃 env->GetStaticFieldID(clazz, "test", "Ljava/lang/String;"); // env->ThrowNew(env->FindClass("java/lang/Exception"),"nativate 把异常抛给java"); env->DeleteLocalRef(clazz); //释放资源 } //3.抛出致命异常 程序退 env->FatalError("抛出致命异常 程序退出"); }