Skip to content

NDK 构建配置

源:Android 官方文档 - CMake

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 ManagerSDK Tools → 选中 NDKCMake

配置 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

ABICPU 架构说明
armeabi-v7a32位 ARM大多数旧设备
arm64-v8a64位 ARM现代设备(推荐)
x8632位 x86模拟器
x86_6464位 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 调试

  1. 设置断点在 C++ 代码
  2. 以 Debug 模式运行
  3. 选择 RunAttach Debugger to Android Process
  4. 选择 Native OnlyDual (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

参见 APK Splits 构建

最佳实践

选择合适的 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 调用