Android Jni添加打印(C++打印)

小明 2025-05-06 02:41:34 2

Android Jni添加打印(C++打印)

文章目录

  • Android Jni添加打印(C++打印)
    • 一、前言
    • 二、添加日志实现
      • 1、在某个类上面定义类型和方法
      • 2、把日志方法定义在.h文件中
      • 定义 myLog.h
      • 3、引用打印头文件的示例代码
        • (1) MainActivity.java 代码
        • (2) 另外一个cpp代码类和头文件
        • (3)jni native-lib.cpp代码类
        • (4)打印内容
        • 三、其他
          • 1、打印各种类型和示例
            • (1)整数类型:
            • (2)浮点数类型:
            • (3)字符类型:
            • (4)字符串类型:
            • (5)布尔类型:
            • 2、日志打印不出情况
            • 3、__android_log_write 和 __android_log_print 区别?
              • (1)参数形式:
              • (2)使���方式:

                一、前言

                Android Jni中添加日志打印其实就是C/C++日志打印

                ()

                Android环境的C/C++代码打印,可以添加相关头文件后,调用打印方法

                跟Android打印类似,也是有打印级别,I,D,W,E

                ()

                二、添加日志实现

                1、在某个类上面定义类型和方法

                网上一般做法,在某一个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头文件里面,其他类加入定义一下头文件调用到了。

                2、把日志方法定义在.h文件中

                定义 myLog.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"
                

                3、引用打印头文件的示例代码

                (1) MainActivity.java 代码
                    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();
                
                (2) 另外一个cpp代码类和头文件
                //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); //定义方法
                };
                
                (3)jni native-lib.cpp代码类
                #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());
                }
                
                (4)打印内容
                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

                三、其他

                1、打印各种类型和示例

                在C++中,可以使用不同的格式化输出来打印各种数据类型。下面是一些常见的数据类型及其对应的打印格式:

                (1)整数类型:
                 int: 使用"%d"格式打印,
                 例如:`int num = 10; printf("%d", num);`
                 
                 long: 使用"%ld"格式打印,
                 例如:`long num = 1000000; printf("%ld", num);`
                 
                 short: 使用"%hd"格式打印,
                 例如:`short num = 5; printf("%hd", num);`
                
                (2)浮点数类型:
                 float: 使用"%f"格式打印,
                 例如:`float num = 3.14; printf("%f", num);`
                 double: 使用"%lf"格式打印,
                 例如:`double num = 2.71828; printf("%lf", num);`
                
                (3)字符类型:
                char: 使用"%c"格式打印,
                例如:`char ch = 'A'; printf("%c", ch);`
                
                (4)字符串类型:
                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());
                    }
                }
                
                (5)布尔类型:
                bool: 使用"%d"或"%s"格式打印,分别将true打印为1,false打印为0或者"true"和"false",
                例如:`bool flag = true; printf("%d", flag);`
                

                上面的打印printf在Android平台打印都替换成 LOGI 即可。

                以上是一些常见数据类型的打印方式,你可以根据具体需要选择合适的格式化输出来打印不同的数据类型。

                2、日志打印不出情况

                如果在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 中设置了正确的标签过滤条件,以及你期望的日志级别过滤条件。
                

                如果以上步骤都确认无误,但仍然无法打印日志,可以检查一下日志打印语句是否被执行到,或者尝试在其他位置打印日志,以确定是否是特定位置的问题。另外,确保你的应用具有适当的权限来写入日志。

                如果问题仍然存在,建议提供更多的代码细节或错误信息,以便更好地理解问题并提供帮助。

                3、__android_log_write 和 __android_log_print 区别?

                两个方法都是log.h里面定义的方法,目前看,两种方式都是可以打印,但是区别有什么呢

                在Android的JNI开发中,__android_log_write和__android_log_print都是用于在native代码中打印日志的函数。它们的区别如下:

                (1)参数形式:
                 `__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文件中一般都是使用第二种。

                (2)使用方式:
                 `__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函数更灵活,可以使用格式化字符串来输出带有变量值的日志信息。

                实际使用中,可以根据需要选择合适的函数来打印日志。

The End
微信