Android Studio NDK 入门教程--优雅的在C++中输出Logcat

Posted Wastrel_xyz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Studio NDK 入门教程--优雅的在C++中输出Logcat相关的知识,希望对你有一定的参考价值。

概述

本文讲述如何通过android/log.h在native代码中输出logcat日志。

认识android/log.h

了解的最好方式就是直接看代码,下面贴出其代码,并对英文部分做中文注释。

#ifndef _ANDROID_LOG_H
#define _ANDROID_LOG_H


 /*****************这段警告是针对所以android native库的
 *  重要提示:
 *      这个文件是在Android NDK 1.5版本以上的一部分。
 *      如果在第三方源码或二进制代码中依赖此定义需要遵守:
 *      - 不要修改枚举(除了你想新增一个32位的值)
 *      - 不要修改常量或者函数式宏
 *      - 不要改变方法的签名
 *      - 不要改变结构体的前后顺序或大小
 */

/* 支持Android内核程序将消息发送到日志缓冲区,稍后将可以在logcat浏览日志。
 * 每一个日志必须包含
 *      - 一个优先级
 *      - 一个标签
 *      - 一些文字
 * 标签通常对应于发出日志消息的组件,应该小且合理。
 * 
 * 日志消息可能被特定实现截断(例如:最大1023个字符)
 *
 * 如果日志消息没有以"\\n"结尾那么将会自动追加。不可能出现多个日志在Logcat中被打印成一行。
 *
 * 请适度的使用LOGS
 *      - 发送日志消息吃CPU和减缓你的应用程序和系统。
 *      - 循环日志缓冲区很小(<64kb),发送很多消息可能推迟系统中剩下的其他重要的日志消息。
 *      - 在版本发布,只有发送日志消息来考虑异常情况。
 * 提示:这些方法必须实现/system/lib/liblog.so
 */


#include <stdarg.h>

#ifdef __cplusplus
extern "C" 
#endif

/*
 * Android日志优先级,升序排列 很容与Java中常见的日志等级V D I W E对应起来 
 */
typedef enum android_LogPriority 
    ANDROID_LOG_UNKNOWN = 0,
    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 android_LogPriority;

/*
 * Send a simple string to the log.
 *发送一个简单的消息
 */
int __android_log_write(int prio, const char *tag, const char *text);

/*
 * Send a formatted string to the log, used like printf(fmt,...)
 * 发送一个带格式化的log,像printf一样使用它
 */
int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
/* 
 *如果是GNUC编译器,这里将会检查format调用的正确性。下同。
 */
#if defined(__GNUC__)
    __attribute__ ((format(printf, 3, 4)))
#endif
    ;

/*
 * A variant of __android_log_print() that takes a va_list to list
 * additional parameters.
 * __android_log_print() 的一个变体,使用va_list代替可变参数
 */
int __android_log_vprint(int prio, const char *tag,
                         const char *fmt, va_list ap);

/*
 * Log an assertion failure and SIGTRAP the process to have a chance
 * to inspect it, if a debugger is attached. This uses the FATAL priority.
 * 日志断言失败和SIGTRAP过程有机会检查它,如果一个调试器连接。这使用的是FATAL优先级。
 */
void __android_log_assert(const char *cond, const char *tag,
              const char *fmt, ...)    
#if defined(__GNUC__)
    __attribute__ ((noreturn))
    __attribute__ ((format(printf, 3, 4)))
#endif
    ;

#ifdef __cplusplus

#endif

#endif 

以上代码由两个注意点:1、使用__android_log_print()时可以像C语言中的printf一样对输出的字符串进行格式化。在实际应用中使用print函数较多。2、使用这个头文件的时候必须包含log日志库。

使用使用__android_log_print()打印日志

在编译配置中添加log库

  • 如果你用的是正式版gradle,在ndk标签中加入

    ldLibs "log"
  • 如果你用的是实验版gradle,在ndk标签中加入:

    ldLibs.add("log")
  • 如果你使用CMakeLists,在target_link_libraries标签中加入log
  • 如果你使用的是MK文件,加入如下语句:

    LOCAL_LDLIBS := -llog

在代码中使用

  • 在代码中包含头文件include"android/log.h"
//打印一个简单Info级别的日志 对应Java的Log.i("JNI","This is log")

__android_log_print(ANDROID_LOG_INFO,"JNI","This is log"); 

//打印格式化字符串 这里使用的是C语言中printf中的格式。关于C中的printf格式化输出可自行百度,文档非常多。

int i=5;
__android_log_print(ANDROID_LOG_INFO,"JNI","i=%d",i); 

C语言printf格式化输出详解:http://blog.csdn.net/xuefu2008/article/details/4645026/

如何优雅的输出日志

下面将通过C语言中的宏定义功能简化日志输出工具类。

//filename LogUtils.h
//
// Created by wastrel on 2016/4/7.
//



#include "android/log.h"

#ifndef LOG_TAG
    #define LOG_TAG "JNI"
#endif
#ifndef IS_DEBUG
    #define IS_DEBUG true
#endif

#define LOG_NOOP (void) 0
//__FILE__ 输出文件名
//__LINE__ 输出行数
//__PRETTY_FUNCTION__  输出方法名
//可以按需选取 %s %u %s 分别与之对应
#define LOG_PRINT(level,fmt,...) __android_log_print(level,LOG_TAG,"(%s:%u) %s: " fmt,__FILE__,__LINE__,__PRETTY_FUNCTION__,##__VA_ARGS__)
//通过IS_DEBUG来控制是否输出日志
#if IS_DEBUG
    #define LOGI(fmt,...) LOG_PRINT(ANDROID_LOG_INFO,fmt,##__VA_ARGS__)
#else
    #define LOGI(...) LOG_NOOP
#endif

#if IS_DEBUG
    #define LOGW(fmt,...) LOG_PRINT(ANDROID_LOG_WARN,fmt ,##__VA_ARGS__)
#else
    #define LOGW(...) LOG_NOOP
#endif

#if IS_DEBUG
    #define LOGD(fmt,...) LOG_PRINT(ANDROID_LOG_DEBUG,fmt ,##__VA_ARGS__)
#else
    #define LOGD(...) LOG_NOOP
#endif

#if IS_DEBUG
    #define LOGE(fmt,...) LOG_PRINT(ANDROID_LOG_ERROR,fmt ,##__VA_ARGS__)
#else
    #define LOGE(...) LOG_NOOP
#endif

#if IS_DEBUG
    #define LOGF(fmt,...) LOG_PRINT(ANDROID_LOG_FATAL,fmt ,##__VA_ARGS__)
#else
    #define LOGF(...) LOG_NOOP
#endif

新建一个LogUtils.h文件,拷贝以上代码。然后在需要使用的cpp文件中include即可。

    #include"LogUtils.h"

    int func(int i)
    
        LOGW("this is a warning");
        LOGE("i = %d",i);
    

以上是关于Android Studio NDK 入门教程--优雅的在C++中输出Logcat的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio NDK 入门教程--优雅的在C++中输出Logcat

Android Studio NDK 入门教程--JNI动态注册本地方法

Android Studio NDK 入门教程--Java与C++之间的类型签名

Android Studio NDK 入门教程--Java对象的传递与修改

NDK开发 从入门到放弃(七:Android Studio 2.2 CMAKE 高效NDK开发)

Android Studio NDK 入门教程--JNI签名验证防止恶意调用