最简单的Android 调试 NDK编写 代码示例

发布时间:2026/5/19 13:31:34

最简单的Android 调试 NDK编写 代码示例 文章目录CMakeLists.txtnative-lib.cppactivity_main.xmlbuild.gradleCMakeLists.txtcmake_minimum_required(VERSION3.18.1)project(fontandroidmanager)# 设置基础路径set(PUBLIC_LIB_DIRD:/public_lib)# 设置 spdlogset(SPDLOG_INCLUDE_DIR${PUBLIC_LIB_DIR}/spdlog/include)set(SPDLOG_LIBRARY${PUBLIC_LIB_DIR}/spdlog/build/Android/x86_64_Static_Debug/Debug/libspdlogd.a)# 设置 freetypeset(FREETYPE_INCLUDE_DIR${PUBLIC_LIB_DIR}/freetype-master/install/Android/x86_64_Static_Debug/include)set(FREETYPE_LIBRARY${PUBLIC_LIB_DIR}/freetype-master/install/Android/x86_64_Static_Debug/lib/libfreetyped.a)# 设置 harfbuzzset(HARFBUZZ_INCLUDE_DIR${PUBLIC_LIB_DIR}/harfbuzz-13.1.1/install/Android/x86_64_Static_Debug/include)set(HARFBUZZ_LIBRARY${PUBLIC_LIB_DIR}/harfbuzz-13.1.1/install/Android/x86_64_Static_Debug/lib/libharfbuzz_d.a)set(HARFBUZZ_SUBSET_LIBRARY${PUBLIC_LIB_DIR}/harfbuzz-13.1.1/install/Android/x86_64_Static_Debug/lib/libharfbuzz-subset_d.a)# 可选的 harfbuzz 其他模块set(HARFBUZZ_RASTER_LIBRARY${PUBLIC_LIB_DIR}/harfbuzz-13.1.1/install/Android/x86_64_Static_Debug/lib/libharfbuzz-raster_d.a)set(HARFBUZZ_VECTOR_LIBRARY${PUBLIC_LIB_DIR}/harfbuzz-13.1.1/install/Android/x86_64_Static_Debug/lib/libharfbuzz-vector_d.a)# 打印路径信息以便调试message(STATUSUsing SPDLOG_INCLUDE_DIR: ${SPDLOG_INCLUDE_DIR})message(STATUSUsing SPDLOG_LIBRARY: ${SPDLOG_LIBRARY})message(STATUSUsing FREETYPE_INCLUDE_DIR: ${FREETYPE_INCLUDE_DIR})message(STATUSUsing FREETYPE_LIBRARY: ${FREETYPE_LIBRARY})message(STATUSUsing HARFBUZZ_INCLUDE_DIR: ${HARFBUZZ_INCLUDE_DIR})message(STATUSUsing HARFBUZZ_LIBRARY: ${HARFBUZZ_LIBRARY})message(STATUSUsing HARFBUZZ_SUBSET_LIBRARY: ${HARFBUZZ_SUBSET_LIBRARY})# 检查库和头文件是否存在foreach(VAR_NAME SPDLOG_INCLUDE_DIR SPDLOG_LIBRARY FREETYPE_INCLUDE_DIR FREETYPE_LIBRARY HARFBUZZ_INCLUDE_DIR HARFBUZZ_LIBRARY HARFBUZZ_SUBSET_LIBRARY)if(NOT EXISTS ${${VAR_NAME}})message(WARNINGPath not found for ${VAR_NAME}: ${${VAR_NAME}})else()message(STATUS${VAR_NAME} found: ${${VAR_NAME}})endif()endforeach()# 添加本地库add_library(${CMAKE_PROJECT_NAME}SHARED native-lib.cpp)# 指定头文件路径target_include_directories(${CMAKE_PROJECT_NAME}PRIVATE ${SPDLOG_INCLUDE_DIR}${FREETYPE_INCLUDE_DIR}${HARFBUZZ_INCLUDE_DIR})# 创建链接库列表set(LINK_LIBRARIES android log ${SPDLOG_LIBRARY}${FREETYPE_LIBRARY}${HARFBUZZ_LIBRARY}${HARFBUZZ_SUBSET_LIBRARY})# 如果您还需要其他 harfbuzz 模块可以添加#if(EXISTS ${HARFBUZZ_RASTER_LIBRARY})#list(APPEND LINK_LIBRARIES ${HARFBUZZ_RASTER_LIBRARY})#message(STATUSAdding harfbuzz-raster library)#endif()#if(EXISTS ${HARFBUZZ_VECTOR_LIBRARY})#list(APPEND LINK_LIBRARIES ${HARFBUZZ_VECTOR_LIBRARY})#message(STATUSAdding harfbuzz-vector library)#endif()# 指定库文件路径并链接target_link_libraries(${CMAKE_PROJECT_NAME}${LINK_LIBRARIES})# 如果需要额外的链接器标志target_compile_options(${CMAKE_PROJECT_NAME}PRIVATE-Wl,--allow-multiple-definition)# 添加编译定义如果需要调试版本target_compile_definitions(${CMAKE_PROJECT_NAME}PRIVATE SPDLOG_ACTIVE_LEVELSPDLOG_LEVEL_DEBUG)native-lib.cpp#include jni.h #include string #include spdlog/spdlog.h #include spdlog/sinks/basic_file_sink.h #include android/log.h #include chrono #include thread // 全局日志器 std::shared_ptrspdlog::logger g_logger nullptr; // 打印到Logcat的宏 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, FontManager-Native, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, FontManager-Native, __VA_ARGS__) // 初始化日志器 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_initLogger( JNIEnv* env, jobject /* this */, jstring path) { const char* pathChars env-GetStringUTFChars(path, nullptr); std::string logPath(pathChars); LOGD(Initializing logger with path: %s, logPath.c_str()); try { // 创建文件 sink auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(logPath, true); // 创建 logger g_logger std::make_sharedspdlog::logger(font_manager, file_sink); // 设置格式 g_logger-set_pattern([%Y-%m-%d %H:%M:%S.%e] [%l] %v); // 设置级别为trace以记录所有日志 g_logger-set_level(spdlog::level::trace); // 设置自动刷新 g_logger-flush_on(spdlog::level::info); // 写入初始化日志 SPDLOG_LOGGER_INFO(g_logger, ); SPDLOG_LOGGER_INFO(g_logger, Logger initialized successfully); SPDLOG_LOGGER_INFO(g_logger, Log file: {}, logPath); SPDLOG_LOGGER_INFO(g_logger, ); g_logger-flush(); LOGD(Logger initialized successfully); } catch (const spdlog::spdlog_ex ex) { LOGE(Logger init failed: %s, ex.what()); g_logger nullptr; } env-ReleaseStringUTFChars(path, pathChars); } // 写入INFO日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeInfoLog( JNIEnv* env, jobject /* this */) { LOGD(writeInfoLog called); if (g_logger) { SPDLOG_LOGGER_INFO(g_logger, This is an INFO log message); SPDLOG_LOGGER_INFO(g_logger, Current time: {}, std::chrono::system_clock::now().time_since_epoch().count()); g_logger-flush(); LOGD(INFO log written); } else { LOGE(Logger is null); } } // 写入DEBUG日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeDebugLog( JNIEnv* env, jobject /* this */) { LOGD(writeDebugLog called); if (g_logger) { SPDLOG_LOGGER_DEBUG(g_logger, This is a DEBUG log message); SPDLOG_LOGGER_DEBUG(g_logger, Debug value: {}, 42); g_logger-flush(); LOGD(DEBUG log written); } else { LOGE(Logger is null); } } // 写入WARNING日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeWarningLog( JNIEnv* env, jobject /* this */) { LOGD(writeWarningLog called); if (g_logger) { SPDLOG_LOGGER_WARN(g_logger, This is a WARNING log message); SPDLOG_LOGGER_WARN(g_logger, Warning: something might be wrong); g_logger-flush(); LOGD(WARNING log written); } else { LOGE(Logger is null); } } // 写入ERROR日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeErrorLog( JNIEnv* env, jobject /* this */) { LOGD(writeErrorLog called); if (g_logger) { SPDLOG_LOGGER_ERROR(g_logger, This is an ERROR log message); SPDLOG_LOGGER_ERROR(g_logger, Error code: {}, -1); g_logger-flush(); LOGD(ERROR log written); } else { LOGE(Logger is null); } } // 写入TRACE日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeTraceLog( JNIEnv* env, jobject /* this */) { LOGD(writeTraceLog called); if (g_logger) { SPDLOG_LOGGER_TRACE(g_logger, This is a TRACE log message); SPDLOG_LOGGER_TRACE(g_logger, Trace details: function entry point); g_logger-flush(); LOGD(TRACE log written); } else { LOGE(Logger is null); } } // 写入多条不同级别的日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeMultipleLogs( JNIEnv* env, jobject /* this */) { LOGD(writeMultipleLogs called); if (g_logger) { SPDLOG_LOGGER_TRACE(g_logger, Multiple logs - TRACE); SPDLOG_LOGGER_DEBUG(g_logger, Multiple logs - DEBUG); SPDLOG_LOGGER_INFO(g_logger, Multiple logs - INFO); SPDLOG_LOGGER_WARN(g_logger, Multiple logs - WARN); SPDLOG_LOGGER_ERROR(g_logger, Multiple logs - ERROR); g_logger-flush(); LOGD(Multiple logs written); } else { LOGE(Logger is null); } } // 循环写入指定数量的日志 extern C JNIEXPORT void JNICALL Java_com_example_fontandroidmanager_MainActivity_writeLoopLogs( JNIEnv* env, jobject /* this */, jint count) { LOGD(writeLoopLogs called with count: %d, count); if (g_logger) { for (int i 0; i count; i) { SPDLOG_LOGGER_INFO(g_logger, Loop log message #{}, i 1); // 每10条刷新一次 if ((i 1) % 10 0) { g_logger-flush(); } } g_logger-flush(); LOGD(Loop logs written, total: %d, count); } else { LOGE(Logger is null); } }activity_main.xml?xml version1.0 encodingutf-8?LinearLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticalandroid:padding16dp!-- 日志路径标签 --TextViewandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text日志文件路径可长按复制android:textSize14spandroid:textStyleboldandroid:layout_marginBottom4dp/!-- 可复制的日志路径 EditText --EditTextandroid:idid/et_log_pathandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text初始化中...android:textSize12spandroid:padding12dpandroid:backgroundandroid:drawable/editbox_backgroundandroid:enabledfalseandroid:focusabletrueandroid:focusableInTouchModetrueandroid:textIsSelectabletrueandroid:longClickabletrueandroid:layout_marginBottom24dp/!-- 多个按钮触发不同的C函数 --Buttonandroid:idid/btn_log_infoandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text写入INFO日志android:layout_marginBottom8dp/Buttonandroid:idid/btn_log_debugandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text写入DEBUG日志android:layout_marginBottom8dp/Buttonandroid:idid/btn_log_warningandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text写入WARNING日志android:layout_marginBottom8dp/Buttonandroid:idid/btn_log_errorandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text写入ERROR日志android:layout_marginBottom8dp/Buttonandroid:idid/btn_log_traceandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text写入TRACE日志android:layout_marginBottom16dp/Buttonandroid:idid/btn_write_multipleandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text写入多条日志android:layout_marginBottom16dp/Buttonandroid:idid/btn_write_loopandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text循环写入100条日志android:layout_marginBottom8dp//LinearLayoutbuild.gradleplugins{alias(libs.plugins.android.application)}android{namespacecom.example.fontandroidmanagercompileSdk{versionrelease(36){minorApiLevel1}}// 设置 NDK 版本ndkVersion23.2.8568313// 对应 android-ndk-r23cdefaultConfig{applicationIdcom.example.fontandroidmanagerminSdk29targetSdk36versionCode1versionName1.0testInstrumentationRunnerandroidx.test.runner.AndroidJUnitRunnerexternalNativeBuild{cmake{cppFlags-stdc17}}}buildTypes{release{isMinifyEnabledfalseproguardFiles(getDefaultProguardFile(proguard-android-optimize.txt),proguard-rules.pro)}}compileOptions{sourceCompatibilityJavaVersion.VERSION_11 targetCompatibilityJavaVersion.VERSION_11}externalNativeBuild{cmake{pathfile(src/main/cpp/CMakeLists.txt)version3.22.1}}buildFeatures{viewBindingtrue}}dependencies{// 添加这个以支持 DocumentFileimplementation(libs.appcompat)implementation(libs.material)implementation(libs.constraintlayout)testImplementation(libs.junit)androidTestImplementation(libs.ext.junit)androidTestImplementation(libs.espresso.core)}

相关新闻