NDK 构建配置
Android NDK (Native Development Kit) 允许在 Android应用中使用 C/C++ 代码,适合性能敏感的场景。
NDK 基础
什么时候使用 NDK
适合场景:
- CPU 密集型计算(图像处理、加密)
- 游戏引擎
- 复用现有 C/C++ 库
- 物理引擎、音频处理
不适合场景:
- 普通应用逻辑
- UI 代码
- 网络请求
构建系统选择
CMake(推荐):
- 跨平台构建系统
- Android Studio 集成完善
- 社区生态丰富
ndk-build:
- NDK 原生构建系统
- 适合已有 Android.mk 的项目
使用 CMake
基础配置
安装 NDK 和 CMake:
Android Studio:SDK Manager → SDK Tools → 选中 NDK 和 CMake
配置 build.gradle.kts:
kotlin
android {
defaultConfig {
ndk {
// 指定要编译的 ABI
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
}
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
buildFeatures {
prefab = true // 使用预构建库
}
}CMakeLists.txt 示例
基础 CMakeLists.txt:
cmake
cmake_minimum_required(VERSION 3.22.1)
project("myapp")
# 添加源文件
add_library(
native-lib
SHARED
native-lib.cpp
utils.cpp
)
# 查找并链接日志库
find_library(
log-lib
log
)
target_link_libraries(
native-lib
${log-lib}
)JNI 函数定义
native-lib.cpp:
cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}Kotlin 调用:
kotlin
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("native-lib")
}
}
external fun stringFromJNI(): String
}ABI 配置
支持的 ABI
| ABI | CPU 架构 | 说明 |
|---|---|---|
| armeabi-v7a | 32位 ARM | 大多数旧设备 |
| arm64-v8a | 64位 ARM | 现代设备(推荐) |
| x86 | 32位 x86 | 模拟器 |
| x86_64 | 64位 x86 | 模拟器 |
过滤 ABI
仅构建特定 ABI:
kotlin
android {
defaultConfig {
ndk {
abiFilters += listOf("arm64-v8a", "x86_64")
}
}
}按构建类型过滤:
kotlin
android {
buildTypes {
getByName("debug") {
ndk {
abiFilters += listOf("arm64-v8a") // Debug 仅构建 arm64
}
}
getByName("release") {
ndk {
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
}
}
}
}CMake 参数配置
Gradle 中配置
kotlin
android {
defaultConfig {
externalNativeBuild {
cmake {
// 传递给 CMake 的参数
arguments += listOf(
"-DANDROID_ARM_NEON=TRUE",
"-DANDROID_STL=c++_shared"
)
// C++ 编译标志
cppFlags += listOf("-std=c++17", "-frtti", "-fexceptions")
// C 编译标志
cFlags += listOf("-DDEBUG")
// 构建目标
targets += listOf("native-lib", "utils")
}
}
}
}CMake 工具链参数
ANDROID_ABI:
cmake
# 在CMakeLists.txt中检查ABI
if(ANDROID_ABI STREQUAL "arm64-v8a")
# ARM64特定配置
endif()ANDROID_PLATFORM:
kotlin
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments += "-DANDROID_PLATFORM=android-24"
}
}
}
}ANDROID_STL(C++ 标准库):
kotlin
arguments += "-DANDROID_STL=c++_shared"选项:
c++_shared- 共享 libc++(推荐)c++_static- 静态 libc++none- 无标准库
使用预构建库
导入预构建 .so 文件
CMakeLists.txt:
cmake
# 添加预构建库
add_library(
prebuilt-lib
SHARED
IMPORTED
)
set_target_properties(
prebuilt-lib
PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI}/libprebuilt.so
)
# 链接到你的库
target_link_libraries(
native-lib
prebuilt-lib
)目录结构:
src/main/cpp/
├── CMakeLists.txt
├── native-lib.cpp
└── libs/
├── arm64-v8a/
│ └── libprebuilt.so
└── armeabi-v7a/
└── libprebuilt.so使用 Prefab AGP 4.1+
Prefab 允许使用 AAR 中的原生库。
启用 Prefab:
kotlin
android {
buildFeatures {
prefab = true
}
}
dependencies {
implementation("com.example:native-library:1.0.0")
}CMakeLists.txt:
cmake
find_package(native-library REQUIRED CONFIG)
target_link_libraries(
myapp
native-library::native-library
)构建类型配置
按构建类型使用不同代码
CMakeLists.txt:
cmake
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUG_MODE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG")
endif()Gradle 配置
kotlin
android {
buildTypes {
getByName("debug") {
isJniDebuggable = true // 启用 JNI 调试
}
getByName("release") {
isJniDebuggable = false
externalNativeBuild {
cmake {
arguments += "-DCMAKE_BUILD_TYPE=Release"
}
}
}
}
}第三方库集成
集成 OpenCV
cmake
cmake_minimum_required(VERSION 3.22.1)
# 设置 OpenCV 路径
set(OpenCV_DIR ${CMAKE_CURRENT_SOURCE_DIR}/opencv/sdk/native/jni)
# 查找 OpenCV
find_package(OpenCV REQUIRED)
add_library(
opencv-app
SHARED
opencv-app.cpp
)
target_link_libraries(
opencv-app
${OpenCV_LIBS}
)集成 FFmpeg
cmake
# 添加 FFmpeg 预构建库
add_library(avcodec SHARED IMPORTED)
set_target_properties(avcodec PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/lib/${ANDROID_ABI}/libavcodec.so
)
add_library(avformat SHARED IMPORTED)
set_target_properties(avformat PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/lib/${ANDROID_ABI}/libavformat.so
)
target_link_libraries(
myapp
avcodec
avformat
)调试 NDK 代码
使用 Android Studio 调试
- 设置断点在 C++ 代码
- 以 Debug 模式运行
- 选择 Run → Attach Debugger to Android Process
- 选择 Native Only 或 Dual (Java + Native)
日志输出
cpp
#include <android/log.h>
#define TAG "NativeLib"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
LOGD("Debug message: %s", message);CMakeLists.txt 链接日志库:
cmake
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})构建优化
编译器优化
cmake
# Release 优化
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
# 启用 LTO(链接时优化)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)并行编译
properties
# gradle.properties
android.ndk.maxJobs=8减少 APK 体积
仅包含必要的 ABI:
kotlin
android {
defaultConfig {
ndk {
abiFilters += listOf("arm64-v8a") // 仅64位ARM
}
}
}拆分 APK:
最佳实践
选择合适的 ABI:
- 生产环境:
arm64-v8a+armeabi-v7a - 开发/测试:仅
arm64-v8a
使用 C++17 或更高版本:
cmake
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)管理原生库依赖:
- 使用 Prefab 管理 AAR 中的原生库
- 避免手动复制 .so 文件
版本控制:
- 将 CMakeLists.txt 纳入版本控制
- 不要提交生成的 .so 文件
测试原生代码:
- 编写单元测试(Google Test)
- 集成测试覆盖 JNI 调用
性能分析:
- 使用 Android Profiler
- 监控 JNI 调用开销
- 避免频繁的 JNI 调用