在Windows环境下编译Android原生库需要搭建完整的工具链。与常见的Android Studio集成开发环境不同,命令行方式可以更好地适应持续集成和自动化构建场景。
首先需要确保系统中已安装以下核心组件:
Android SDK:包含NDK和CMake工具
C:\Users\<用户名>\AppData\Local\Android\Sdkplatform-tools和ndk目录是否存在Git for Windows:
注意:建议将Android SDK路径添加到系统环境变量中,方便后续脚本调用。例如添加
ANDROID_SDK_ROOT=D:\AndroidSDK
不同版本的NDK和CMake存在兼容性要求:
| 组件 | 最低版本 | 推荐版本 | 备注 |
|---|---|---|---|
| NDK | r21 | r25+ | 旧版本可能缺少关键工具链 |
| CMake | 3.18 | 3.22+ | 需匹配NDK内置的CMake版本 |
验证版本命令:
bash复制# 检查NDK版本
$NDK_PATH/ndk-build --version
# 检查CMake版本
$CMAKE_BIN --version
典型的命令行编译项目需要以下基础结构:
code复制/ndkTest
├── CMakeLists.txt # CMake构建脚本
├── build.sh # 构建入口脚本
├── native-lib.c # 原生代码实现
└── ninja-win/ # Ninja构建工具
└── ninja.exe
CMake配置文件是构建过程的核心,需要特别注意以下关键指令:
cmake复制cmake_minimum_required(VERSION 3.18.1) # 必须≥3.18以保证NDK兼容
project("native-lib") # 项目名称会影响输出文件名
# 添加动态库目标
add_library(
native-lib # 库名称
SHARED # 生成.so动态库
native-lib.c # 源文件列表
)
# 链接系统库
find_library(
log-lib # 变量名
log # Android日志库
)
target_link_libraries(
native-lib # 目标库
${log-lib} # 依赖库
)
经验:对于复杂项目,可以使用
aux_source_directory()自动收集源文件,避免手动维护文件列表
构建脚本需要处理以下核心逻辑:
bash复制#!/bin/bash
# 工具路径配置(需根据实际环境修改)
NDK_PATH="/d/AndroidSDK/ndk/26.3.11579264"
CMAKE_BIN="/d/AndroidSDK/cmake/3.22.1/bin/cmake"
NINJA_BIN="/d/ndkTest/ninja-win/ninja.exe"
# 构建参数配置
ABI="arm64-v8a" # 可选值:armeabi-v7a, x86, x86_64
API_LEVEL=21 # 最低支持的Android API级别
BUILD_DIR="build" # 临时构建目录
OUTPUT_DIR="libs" # 输出目录
CMake生成命令包含关键参数:
bash复制"$CMAKE_BIN" \
-G "Ninja" \ # 指定生成器类型
-DCMAKE_MAKE_PROGRAM="$NINJA_BIN" \ # Ninja可执行路径
-DCMAKE_TOOLCHAIN_FILE="$NDK_PATH/build/cmake/android.toolchain.cmake" \ # NDK工具链
-DANDROID_ABI="$ABI" \ # 目标ABI
-DANDROID_PLATFORM="android-$API_LEVEL" \ # 平台版本
-DCMAKE_BUILD_TYPE=Release \ # 构建类型
-B "$BUILD_DIR" \ # 构建目录
-S . # 源码目录
构建完成后需要处理产物:
bash复制# 执行构建
cd "$BUILD_DIR"
"$CMAKE_BIN" --build . --parallel 8 # 使用8线程加速构建
cd ..
# 整理输出
mkdir -p "$OUTPUT_DIR/$ABI"
cp "$BUILD_DIR/libnative-lib.so" "$OUTPUT_DIR/$ABI/"
技巧:添加
--parallel $(nproc)可以自动检测CPU核心数进行并行编译
修改build.sh实现批量构建:
bash复制ABIS=("armeabi-v7a" "arm64-v8a" "x86" "x86_64")
for abi in "${ABIS[@]}"; do
echo "▶ 构建ABI: $abi"
"$CMAKE_BIN" \
-DANDROID_ABI="$abi" \
-B "$BUILD_DIR-$abi" \
-S .
cd "$BUILD_DIR-$abi"
"$CMAKE_BIN" --build .
cd ..
mkdir -p "$OUTPUT_DIR/$abi"
cp "$BUILD_DIR-$abi/libnative-lib.so" "$OUTPUT_DIR/$abi/"
done
CCache配置:
bash复制-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
编译选项调优:
cmake复制# 在CMakeLists.txt中添加
target_compile_options(native-lib PRIVATE
-O2 # 优化级别
-fPIC # 位置无关代码
-march=armv8-a # CPU架构指定
)
问题现象:CMake配置阶段报错"Could not find toolchain file"
解决方案:
android.toolchain.cmake文件存在问题现象:运行时出现UnsatisfiedLinkError
排查步骤:
bash复制adb shell getprop ro.product.cpu.abi
bash复制file libs/arm64-v8a/libnative-lib.so
问题现象:undefined reference to编译错误
解决方案:
target_link_libraries是否包含所有依赖nm工具检查符号表:bash复制$NDK_PATH/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android-nm -gD libnative-lib.so
Jenkins Pipeline示例:
groovy复制pipeline {
agent any
stages {
stage('Build') {
steps {
bat '''
set ANDROID_SDK_ROOT=D:\\AndroidSDK
bash build.sh
'''
}
}
}
}
推荐目录结构:
code复制/releases
├── v1.0.0
│ ├── armeabi-v7a
│ └── arm64-v8a
└── v1.1.0
├── x86
└── x86_64
构建脚本可扩展版本号参数:
bash复制VERSION=$(git describe --tags)
OUTPUT_DIR="releases/$VERSION"
在实际项目部署中,我发现通过将NDK路径参数化可以大幅提升脚本的复用性。例如通过环境变量ANDROID_NDK_HOME传递路径,使同一套构建脚本可以在不同开发者的机器上运行。另外,对于大型项目,将CMake模块拆分为多个子目录管理,可以显著提高构建系统的可维护性。