Android Jni中添加日志打印其实就是C/C++日志打印
Android环境的C/C++代码打印,可以添加相关头文件后,调用打印方法
跟Android打印类似,也是有打印级别,I,D,W,E
网上一般做法,在某一个cpp类的上面写如下代码:
#include //添加头文件
#define LOG_TAG "TstCPlus" //定义TAG
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
在方法中使用即可:
LOGI("test");
int result = 100;
LOGI("test result = %d", result);
其他级别打印也是同理使用。
上面的方法把定义都写在打印的定义都写在一个类里面了,如果多个类使用打印就不方便了,
如果要多个类都能见到调用到就可以定义在.h头文件里面,其他类加入定义一下头文件调用到了。
#include
#define LOG_TAG "TestCPlus"
#define ANDROID_PLATFORM
#ifdef ANDROID_PLATFORM
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#else
#define LOGD(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#define LOGI(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#define LOGW(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#define LOGE(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#endif
#endif
上面代码添加了是否Android平台的判断,如果觉得没必要可以直接去掉。
DEBUG的值也可以设置成false,0就是false。
在具体cpp文件中,可以重新定义TAG标签
#include "myLog.h"
#define LOG_TAG "TAG_NAME"
String TAG = "MainActivity Java";
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate");
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
public native String stringFromJNI();
//TestCPlus.cpp 代码
#include "TestCPlus.h"
#include "Androidlog.h"
int TestCPlus::add(int parameter1, int parameter2) {
int result = parameter1 + parameter2;
LOGI("MainActivity jni c++ result = %d", result);//添加打印,但是没有定义TAG
return result;
}
//TestCPlus.h头文件代码
class TestCPlus {
//定义变量和方法
private:
int number;
public:
int add(int parameter1,int parameter2); //定义方法
};
#include
#include
#include "Androidlog.h"
#include "TestCPlus.h"
#define LOG_TAG "native-lib.cpp" //重新定义TAG
extern "C" JNIEXPORT jstring JNICALL
Java_com_demo_jnilog_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C/C++";
LOGD("MainActivity jni c++ ");
int num= 100;
LOGI("MainActivity jni c++ ,num = %d", num);
TestCPlus *testCPlus;
int result = testCPlus->add(2, 50);
LOGI("MainActivity jni c++ ,result = %d", result);
return env->NewStringUTF(hello.c_str());
}
2024-02-29 15:07:40.706 I/MainActivity Java: onCreate
2024-02-29 15:07:40.706 D/native-lib.cpp: MainActivity jni c++
2024-02-29 15:07:40.706 I/native-lib.cpp: MainActivity jni c++ ,num = 100
2024-02-29 15:07:40.706 I/TestLog: MainActivity jni c++ result = 52
2024-02-29 15:07:40.706 I/native-lib.cpp: MainActivity jni c++ ,result = 52
可以看到未定义 LOG_TAG 的 TestCPlus.cpp文件打印的就是使用原本的TAG,定义了的,就是用新的TAG
在C++中,可以使用不同的格式化输出来打印各种数据类型。下面是一些常见的数据类型及其对应的打印格式:
int: 使用"%d"格式打印,
例如:`int num = 10; printf("%d", num);`
long: 使用"%ld"格式打印,
例如:`long num = 1000000; printf("%ld", num);`
short: 使用"%hd"格式打印,
例如:`short num = 5; printf("%hd", num);`
float: 使用"%f"格式打印,
例如:`float num = 3.14; printf("%f", num);`
double: 使用"%lf"格式打印,
例如:`double num = 2.71828; printf("%lf", num);`
char: 使用"%c"格式打印,
例如:`char ch = 'A'; printf("%c", ch);`
char数组或指针:使用"%s"格式打印,
例如:`char str[] = "Hello"; printf("%s", str);`
参数的里面的jstring打印示例:
Java_com_example_example_NativeClass_printString(JNIEnv* env, jobject obj, jstring str) {
const char* nativeString = env->GetStringUTFChars(str, NULL);
if (nativeString != NULL) {
LOGI("String from Java: %s\n", nativeString);
env->ReleaseStringUTFChars(str, nativeString);
//或者:
std::string hello = "Hello from C++";
LOGI("stringFromJNI hello = %s", hello.c_str());
}
}
bool: 使用"%d"或"%s"格式打印,分别将true打印为1,false打印为0或者"true"和"false",
例如:`bool flag = true; printf("%d", flag);`
上面的打印printf在Android平台打印都替换成 LOGI 即可。
以上是一些常见数据类型的打印方式,你可以根据具体需要选择合适的格式化输出来打印不同的数据类型。
如果在JNI的CPP文件中日志打印不出来,可能有以下几个原因:
1. 缺少日志打印库:在CPP文件中,需要包含头文件 ``,并且使用 Android NDK 提供的日志库函数来进行打印。
请确保你的CPP文件中正确包含了该头文件。
2. 编译配置问题:在编译时,需要将日志库链接到你的JNI库中。
在 Android.mk 或 CMakeLists.txt 文件中,确保添加了正确的链接库配置。
示例:`LOCAL_LDLIBS += -llog`。
3. 日志级别设置问题:检查你的日志打印语句中的日志级别参数,
例如 `__android_log_print(ANDROID_LOG_DEBUG, "TAG", "Log message");`。
确保日志级别设置正确,以便在运行时打印出来。
4. 运行时过滤问题:在 Android Logcat 中,可能需要设置正确的过滤条件,以确保你的日志能够显示出来。
请确保你在 Logcat 中设置了正确的标签过滤条件,以及你期望的日志级别过滤条件。
如果以上步骤都确认无误,但仍然无法打印日志,可以检查一下日志打印语句是否被执行到,或者尝试在其他位置打印日志,以确定是否是特定位置的问题。另外,确保你的应用具有适当的权限来写入日志。
如果问题仍然存在,建议提供更多的代码细节或错误信息,以便更好地理解问题并提供帮助。
两个方法都是log.h里面定义的方法,目前看,两种方式都是可以打印,但是区别有什么呢
在Android的JNI开发中,__android_log_write
和__android_log_print
都是用于在native代码中打印日志的函数。它们的区别如下:
`__android_log_write`函数的参数形式为:`__android_log_write(int prio, const char *tag, const char *msg)`。
其中,`prio`表示日志的优先级,`tag`表示日志的标签,`msg`表示日志的内容。
`__android_log_print`函数的参数形式为:`__android_log_print(int prio, const char *tag, const char *fmt, ...)`。
其中,`prio`和`tag`的含义与`__android_log_write`相同,而`fmt`是一个格式化字符串,后面可以是可变参数。
第一种方式比较接近Java代码的打印,msg字符串里面要包含所有打印的信息。
第二种就是c++的打印方式,可以输入多个参数。在cpp文件中一般都是使用第二种。
`__android_log_write`函数需要将日志内容作为字符串传入,可以直接调用该函数输出,例如:`__android_log_write(ANDROID_LOG_DEBUG, "TAG", "Log message");`
`__android_log_print`函数使用类似于`printf`函数的格式化字符串,可以传入多个参数,例如:`__android_log_print(ANDROID_LOG_DEBUG, "TAG", "Log message: %d", value);`
总的来说,__android_log_write
函数更直接,适合简单的日志输出;
而__android_log_print
函数更灵活,可以使用格式化字符串来输出带有变量值的日志信息。
实际使用中,可以根据需要选择合适的函数来打印日志。