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


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

    一、前言

    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__)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在方法中使用即可:

     LOGI("test");
     int result = 100;
     LOGI("test result = %d", result);
    
    • 1
    • 2
    • 3

    其他级别打印也是同理使用。

    上面的方法把定义都写在打印的定义都写在一个类里面了,如果多个类使用打印就不方便了,

    如果要多个类都能见到调用到就可以定义在.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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面代码添加了是否Android平台的判断,如果觉得没必要可以直接去掉。

    DEBUG的值也可以设置成false,0就是false。

    在具体cpp文件中,可以重新定义TAG标签

    #include "myLog.h"
    #define LOG_TAG "TAG_NAME"
    
    • 1
    • 2

    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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    (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); //定义方法
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    (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());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    (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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到未定义 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);`
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    (2)浮点数类型:
     float: 使用"%f"格式打印,
     例如:`float num = 3.14; printf("%f", num);`
     double: 使用"%lf"格式打印,
     例如:`double num = 2.71828; printf("%lf", num);`
    
    • 1
    • 2
    • 3
    • 4
    (3)字符类型:
    char: 使用"%c"格式打印,
    例如:`char ch = 'A'; printf("%c", ch);`
    
    • 1
    • 2
    (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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    (5)布尔类型:
    bool: 使用"%d"或"%s"格式打印,分别将true打印为1,false打印为0或者"true"和"false",
    例如:`bool flag = true; printf("%d", flag);`
    
    
    • 1
    • 2
    • 3

    上面的打印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 中设置了正确的标签过滤条件,以及你期望的日志级别过滤条件。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

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

    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`是一个格式化字符串,后面可以是可变参数。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第一种方式比较接近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);`
    
    
    • 1
    • 2
    • 3
    • 4

    总的来说,__android_log_write函数更直接,适合简单的日志输出;

    __android_log_print函数更灵活,可以使用格式化字符串来输出带有变量值的日志信息。

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

  • 相关阅读:
    docker-network网络
    linux安装chrome及其驱动
    VUE-----生命周期
    买卖股票的最佳时机(系列)
    尚医通 (一) --------- 项目介绍
    卡片翻转效果的实现思路
    学点Selenium玩点新鲜~,让分布式测试有更多玩法
    《Real-Time Rendering 3rd》读书笔记
    FlinkSQL CDC实现同步oracle数据到mysql
    港联证券:从AI到华为产业链 主流基金为何屡屡错过新科技
  • 原文地址:https://blog.csdn.net/wenzhi20102321/article/details/136419367