最近在用Android Studio写JNI程序,发现在写Native层C++代码时貌似没有特别好的打印Log的方法,所以就有了这一篇,这一篇主要是通过查找、记录Android层面的Log方法,然后在Native层进行调用,达到打印Log的效果。下面直接将源码贴上,源码也比较简单,供大家参考
ThrowException.h
这个类是一个辅助类,当找不到对应类、方法或者字段的时候可以直接调用这个这个方法的类来抛出异常。后续如果可以扩充这个类来完善异常抛出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// // Created by Jimmy on 10/25/18. // 当JNI找不到对应类、方法或者字段的时候抛出异常 // #ifndef TESTAPP_THROWEXCEPTION_H #define TESTAPP_THROWEXCEPTION_H #include <jni.h> class ThrowException { public: static jint ClassNotFound(JNIEnv *env, char *className); static jint NoSuchMethod(JNIEnv *env, char *methodName); static jint NoSuchField(JNIEnv *env, char *fieldName); }; #endif //TESTAPP_THROWEXCEPTION_H |
ThrowException.cpp
异常抛出类的具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// // Created by Jimmy on 10/25/18. // #include "ThrowException.h" #include <string.h> jint ThrowException::ClassNotFound(JNIEnv *env, char *className) { env->ExceptionDescribe(); env->ExceptionClear(); jclass jclassClassNotFound = env->FindClass("java/lang/ClassNotFoundException"); return env->ThrowNew(jclassClassNotFound, className); } jint ThrowException::NoSuchMethod(JNIEnv *env, char *methodName) { env->ExceptionDescribe(); env->ExceptionClear(); jclass jclassNotSuchMethod = env->FindClass("java/lang/NoSuchMethodException"); return env->ThrowNew(jclassNotSuchMethod, methodName); } jint ThrowException::NoSuchField(JNIEnv *env, char *fieldName) { env->ExceptionDescribe(); env->ExceptionClear(); jclass jclassNoSuchField = env->FindClass("java/lang/NoSuchFieldException"); return env->ThrowNew(jclassNoSuchField, fieldName); } |
NativeLog.h
NativeLog类的头文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// // Created by Jimmy on 10/25/18. // 再Native层调用Logcat打印log信息 // #ifndef TESTAPP_LOG_H #define TESTAPP_LOG_H #include <jni.h> #include <stdio.h> class NativeLog { private: // 记录对应的方法ID jmethodID jmethodIDLogV; jmethodID jmethodIDLogD; jmethodID jmethodIDLogI; jmethodID jmethodIDLogW; jmethodID jmethodIDLogE; // 记录android.util.Log类的ID jclass jclassLog; public: NativeLog(JNIEnv *env); NativeLog() {} // Log方法定义,名字和上次Log系统相同 int v(JNIEnv *env, const char *LOG_TAG, const char *Msg); int d(JNIEnv *env, const char *LOG_TAG, const char *Msg); int i(JNIEnv *env, const char *LOG_TAG, const char *Msg); int w(JNIEnv *env, const char *LOG_TAG, const char *Msg); int e(JNIEnv *env, const char *LOG_TAG, const char *Msg); }; #endif //TESTAPP_LOG_H |
NativeLog.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
// // Created by Jimmy on 10/25/18. // #include "NativeLog.h" #include "ThrowException.h" // NativeLog类初始化的时候通过查找android.util.log类以及其中的方法进行初始化 NativeLog::NativeLog(JNIEnv *env) { // 查找android.util.log类 jclass jclass1 = env->FindClass("android/util/Log"); if (jclass1 == nullptr && env->ExceptionCheck()) { ThrowException::ClassNotFound(env, "android/util/Log"); } jclassLog = (jclass)env->NewGlobalRef(jclass1); // 查找v、i、d、w、e等方法的方法ID jmethodIDLogV = env->GetStaticMethodID(jclassLog, "v", "(Ljava/lang/String;Ljava/lang/String;)I"); if (jmethodIDLogV == nullptr && env->ExceptionCheck()) { ThrowException::NoSuchMethod(env, "v"); } jmethodIDLogI = env->GetStaticMethodID(jclassLog, "i", "(Ljava/lang/String;Ljava/lang/String;)I"); if (jmethodIDLogI == nullptr && env->ExceptionCheck()) { ThrowException::NoSuchMethod(env, "i"); } jmethodIDLogD = env->GetStaticMethodID(jclassLog, "d", "(Ljava/lang/String;Ljava/lang/String;)I"); if (jmethodIDLogD == nullptr && env->ExceptionCheck()) { ThrowException::NoSuchMethod(env, "d"); } jmethodIDLogE = env->GetStaticMethodID(jclassLog, "e", "(Ljava/lang/String;Ljava/lang/String;)I"); if (jmethodIDLogE == nullptr && env->ExceptionCheck()) { ThrowException::NoSuchMethod(env, "e"); } jmethodIDLogW = env->GetStaticMethodID(jclassLog, "w", "(Ljava/lang/String;Ljava/lang/String;)I"); if (jmethodIDLogW == nullptr && env->ExceptionCheck()) { ThrowException::NoSuchMethod(env, "w"); } } // 下面的就是具体的Log打印实现 int NativeLog::d(JNIEnv *env, const char *LOG_TAG, const char *Msg) { jstring jstringLogTag = env->NewStringUTF(LOG_TAG); jstring jstringMsg = env->NewStringUTF(Msg); int ret = env->CallStaticIntMethod(jclassLog, jmethodIDLogD, jstringLogTag, jstringMsg); env->DeleteLocalRef(jstringLogTag); env->DeleteLocalRef(jstringMsg); return ret; } int NativeLog::v(JNIEnv *env, const char *LOG_TAG, const char *Msg) { jstring jstringLogTag = env->NewStringUTF(LOG_TAG); jstring jstringMsg = env->NewStringUTF(Msg); int ret = env->CallStaticIntMethod(jclassLog, jmethodIDLogV, jstringLogTag, jstringMsg); env->DeleteLocalRef(jstringLogTag); env->DeleteLocalRef(jstringMsg); return ret; } int NativeLog::i(JNIEnv *env, const char *LOG_TAG, const char *Msg) { jstring jstringLogTag = env->NewStringUTF(LOG_TAG); jstring jstringMsg = env->NewStringUTF(Msg); int ret = env->CallStaticIntMethod(jclassLog, jmethodIDLogI, jstringLogTag, jstringMsg); env->DeleteLocalRef(jstringLogTag); env->DeleteLocalRef(jstringMsg); return ret; } int NativeLog::w(JNIEnv *env, const char *LOG_TAG, const char *Msg) { jstring jstringLogTag = env->NewStringUTF(LOG_TAG); jstring jstringMsg = env->NewStringUTF(Msg); int ret = env->CallStaticIntMethod(jclassLog, jmethodIDLogW, jstringLogTag, jstringMsg); env->DeleteLocalRef(jstringLogTag); env->DeleteLocalRef(jstringMsg); return ret; } int NativeLog::e(JNIEnv *env, const char *LOG_TAG, const char *Msg) { jstring jstringLogTag = env->NewStringUTF(LOG_TAG); jstring jstringMsg = env->NewStringUTF(Msg); int ret = env->CallStaticIntMethod(jclassLog, jmethodIDLogE, jstringLogTag, jstringMsg); env->DeleteLocalRef(jstringLogTag); env->DeleteLocalRef(jstringMsg); return ret; } |
How to use
1. 在使用前将上面四个文件包含到自己的源码中
2. 定义一个全局变量Log,定义如下:std::shared_ptr<NativeLog> native_log;
3. 然后再使用前调用类构造函数进行初始化:Log = std::shared_ptr<NativeLog>(new NativeLog(env));
4. 最后通过Log->d()
、Log->e()
等方法进行Log调用即可
下面是一个小的调用示范
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include <jni.h> #include <string> #include <iostream> #include <memory> #include <unistd.h> #include <cstdlib> #include <wait.h> #include <sstream> #include "NativeLog.h" // 定义全局的Log变量 std::shared_ptr<NativeLog> Log; extern "C" JNIEXPORT jstring JNICALL Java_com_blog4jimmy_logandexception_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } // 上层定义了一个native_init方法,进行一些基本的初始化 extern "C" JNIEXPORT void JNICALL Java_com_blog4jimmy_logandexception_MainActivity_native_1init(JNIEnv *env, jobject instance) { std::stringstream stringstream; // 调用NativeLog的构造函数创建Native层的Log系统 Log = std::shared_ptr<NativeLog>(new NativeLog(env)); Log->d(env, "JIMMY", "Init native log success"); Log->e(env, "Jimmy", "Test Log.e()"); } |