Android使用cmake+ndk輸出原生Log
我們可以在c/cpp程式碼中用 print 函式輸出log資訊,但是這樣在 logcat並 不會顯示,好在Android已經給我提供了相應的方法解決這個問題:使用 log.h 標頭檔案
開始
- 建立一個新的Android Studio的工程專案
- 勾選 Include C++ support 選項
- 然後就是一路next直到建立專案成功
專案結構
生成好的專案會在 main 目錄下建立好 cpp 目錄和相應的cpp檔案,以及 CmakeLists 檔案

CmakeLists
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # 限定cmake支援最低版本 cmake_minimum_required(VERSION 3.4.1) # 指定so生成到libs目錄 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI}) # 配置so庫的資訊 add_library( # Sets the name of the library. # 生成的so庫名稱,並不需要和c/cpp檔名相同 # 這裡生產的so庫名稱將為libnative-lib.so native-lib # Sets the library as a shared library. # STATIC:靜態庫,是目標檔案的歸檔檔案,在連結其它目標的時候使用 # SHARED:動態庫,會被動態連結,在執行時被載入 # MODULE:模組庫,是不會被連結到其它目標中的外掛,但是可能會在執行時使用dlopen-系列的函式動態連結 SHARED # Provides a relative path to your source file(s). # 資原始檔的路徑,可以是多個資原始檔 src/main/cpp/native-lib.cpp ) # 從系統庫中查詢依賴庫 find_library( # Sets the name of the path variable. # 設定依賴庫的名字,下面連結庫的時候會用到 log-lib # Specifies the name of the NDK library that # you want CMake to locate. # 查詢log依賴庫 # {sdk-path}/ndk-bundle/sysroot/usr/include/android/log.h log ) # 配置庫的依賴關係(連結關係) target_link_libraries( # Specifies the target library. # 目標庫 native-lib # Links the target library to the log library # included in the NDK. # 依賴庫,可以是多個 ${log-lib} ) 複製程式碼
native-lib.cpp
#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_simple_nativelogdemo_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++ hhahah"; return env->NewStringUTF(hello.c_str()); } 複製程式碼
app/build.gradle下的android節點塊
android { compileSdkVersion 27 defaultConfig { applicationId "com.simple.nativelogdemo" minSdkVersion 16 targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { path "CMakeLists.txt" } } } 複製程式碼
完善程式碼
很簡單,只需要在 cpp 檔案中引入 log.h 標頭檔案並呼叫相關方法即可
#include <jni.h> #include <string> //{sdk-path}/ndk-bundle/sysroot/usr/include/android #include <android/log.h> //定義輸出的TAG const char * LOG_TGA = "LOG_TGA"; extern "C" JNIEXPORT jstring JNICALL Java_com_simple_nativelogdemo_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++ hhahah"; //輸出debug級別的日誌資訊 __android_log_print(ANDROID_LOG_DEBUG, LOG_TGA, "hello native log"); return env->NewStringUTF(hello.c_str()); } 複製程式碼
輸出

log.h標頭檔案分析
常用輸出函式
/** * 輸出一個簡單的字串作為log資訊 */ int __android_log_write(int prio, const char* tag, const char* text); /** * 輸出一個格式化的字串作為log資訊 */ int __android_log_print(int prio, const char* tag, const char* fmt, ...) /** * 與`__android_log_print`方式相同,區別只是傳遞引數不同 */ int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) /** * 用於記錄斷點失敗,型別為`ANDROID_LOG_FATAL` */ void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...) 複製程式碼
引數 prio 代表日誌級別
日誌級別型別
typedef enum android_LogPriority { /** For internal use only.*/ ANDROID_LOG_UNKNOWN = 0, /** The default priority, for internal use only.*/ ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ /** Verbose logging. Should typically be disabled for a release apk. */ ANDROID_LOG_VERBOSE, /** Debug logging. Should typically be disabled for a release apk. */ ANDROID_LOG_DEBUG, /** Informational logging. Should typically be disabled for a release apk. */ ANDROID_LOG_INFO, /** Warning logging. For use with recoverable failures. */ ANDROID_LOG_WARN, /** Error logging. For use with unrecoverable failures. */ ANDROID_LOG_ERROR, /** Fatal logging. For use when aborting. */ ANDROID_LOG_FATAL, /** For internal use only.*/ ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */ } android_LogPriority; 複製程式碼
我們只需要關注其中的
- ANDROID_LOG_VERBOSE
- ANDROID_LOG_DEBUG
- ANDROID_LOG_INFO
- ANDROID_LOG_WARN
- ANDROID_LOG_ERROR
這5個就好了,因為這是我們常用的。