Windows下android-ndk-r26b手动配置与CMake集成
2026/9/16 21:08:48 网站建设 项目流程

简介:Android NDK r26b Windows版是Google提供的Android原生开发工具集,适合需要编写C/C++代码、追求高性能或复用既有库的Android工程师,常用于图形渲染、音视频编解码、物理模拟与神经网络推理等模块。该压缩包共2000个文件,约1969个.h头文件构成主体,覆盖NDK API、JNI接口、OpenGL ES、神经网络、相机元数据等多类声明,便于开发者查阅底层接口;另有13个.py脚本、10个.md、7个.txt和1个.pdf文档,提供构建辅助、使用说明与版本信息,整体630.97MB,解压后可作为Android Studio的NDK环境。目前已有730人学习下载。借助这套资源,开发者可以系统理解NDK工具链的组织方式,掌握JNI桥接、交叉编译、动态库/静态库配置、多架构支持等关键内容,同时通过头文件直接定位原生符号,减少配置与调试时间。由于包内含大量本地头文件,无需联网即可查阅各类NDK接口定义,适合从零搭建原生开发环境或需要深入底层的中高级开发者。

1. 为什么在 Windows 上要手动处理 android-ndk-r26b 而不是依赖 IDE 自动下载

做 Android 原生开发时,NDK 版本失控比 Java 依赖冲突更难排查:链接阶段的undefined reference、JNI 函数签名对不上、C++ STL 重复加载,最后往往都指向同一个原因——编译用的 NDK 和运行时预期不是同一个版本。android-ndk-r26b-windows.zip这个包在 SDK 下载列表里一直存在,但很多项目从不主动锁定它。r26b 对应的版本标识是26.1.10909125,Clang 版本不过新,AGP 和独立 CMake 的兼容性都已验证过,对 Windows 这条线的开发和 CI 机器都相对友好。下面直接走一遍:下载校验、环境变量、ndk-build编译最小 so、接入 Gradle/CMake,最后给几个只有 Windows 会遇到的高频坑。

2. 下载校验与解压 android-ndk-r26b-windows.zip

2.1 文件命名与下载前确认

文件名里的r26b是“release 26 point b”,对应唯一的版本标识26.1.10909125。Google 的下载地址规则是android-ndk-r26b-windows.zip,这个包只给 64 位 Windows 用,Linux 和 macOS 是另一套命名。下载前先确认系统是 64 位,否则打开压缩包会看到toolchains/llvm/prebuilt/windows-x86_64目录无法被识别。

用 PowerShell 直接下载到这个文件时,加-UseBasicParsing可以避免 Windows PowerShell 5.1 依赖 IE 引擎导致交互卡住。

$url = "https://dl.google.com/android/repository/android-ndk-r26b-windows.zip" $out = "$env:USERPROFILE\Downloads\android-ndk-r26b-windows.zip" Invoke-WebRequest -Uri $url -OutFile $out -UseBasicParsing

这里$out指定了下载绝对路径,方便后面校验和解压引用同一个变量。如果没有走命令行下载,从浏览器拿到同名 zip 也完全可以,不需要重复下载。

2.2 校验与解压

压缩包是跨网络传输的,不能只看文件大小就解压。官方下载页会提供 SHA-256 校验值,下载完成后立刻比对,不一致就直接删除,避免后面排查半天发现是包本身坏了。

Get-FileHash -Path .\android-ndk-r26b-windows.zip -Algorithm SHA256 Expand-Archive -Path .\android-ndk-r26b-windows.zip -DestinationPath C:\Android\ndk -Force

-Algorithm SHA256指定哈希算法;Expand-Archive-Force表示目标目录已存在时覆盖文件。Expand-Archive在 PowerShell 5.1 里会先建索引,接近 1 GB 的包耗时较长,替换方案是用 Windows 10 自带的tar -xf,它对 zip 的支持更稳定,输出也更像 Linux 工具链习惯。

解压完成后,先确认这个关键目录结构:

路径或文件作用
ndk-build.cmdWindows 下的构建入口,可供命令行或老式 Android.mk 工程调用
toolchains\llvm\prebuilt\windows-x86_64clang、llvm-readelf 等工具链本体,宿主平台是 x86_64 Windows
build\cmake\android.toolchain.cmake给 CMake 用的工具链文件,手工编译时必须显式指定
sysrootAndroid 平台头文件与系统库,编板级代码时依赖它
source.properties记录版本号,排查“装的是哪个 NDK”时最先看这里

2.3 目录规划与路径避坑

解压出来的顶层目录名是android-ndk-r26b,所以-DestinationPath C:\Android\ndk最终得到的是C:\Android\ndk\android-ndk-r26b。这个位置是我建议的安装路径:短、无空格、无中文。不要放进C:\Program Files,也不要把常用目录挂到 OneDrive 同步盘。CMake 和 Gradle 在 Windows 上处理带空格路径时,转义规则不一致,常常在does not match the generator这类诡异报错里消耗时间。

解压完立刻做一次路径自检:

Test-Path C:\Android\ndk\android-ndk-r26b\ndk-build.cmd

返回True说明目录层级正确,同时这个文件也是后续所有命令行编译的核心入口。

3. 在 Windows 上配置 android-ndk 环境变量并用 ndk-build 快速验证

3.1 设置 ANDROID_NDK_HOME 并加入 PATH

Gradle 本身不靠环境变量识别 NDK,但命令行ndk-build.cmd、部分开源构建脚本和 CMake 辅助脚本会去读取ANDROID_NDK_HOMEANDROID_NDK_ROOT。两个变量在不同工具里各有偏好,实践上宁可都设成同一个值,别赌某个工具默认不读它们。

[Environment]::SetEnvironmentVariable("ANDROID_NDK_HOME", "C:\Android\ndk\android-ndk-r26b", "User") [Environment]::SetEnvironmentVariable("ANDROID_NDK_ROOT", "C:\Android\ndk\android-ndk-r26b", "User") $userPath = [Environment]::GetEnvironmentVariable("Path", "User") [Environment]::SetEnvironmentVariable("Path", "$userPath;C:\Android\ndk\android-ndk-r26b", "User")

第三个参数"User"表示写入当前用户的环境变量注册表位置,不污染系统级变量。新开的终端才能看到变化,当前会话需要手动设置一次才能继续验证:

$env:ANDROID_NDK_HOME = "C:\Android\ndk\android-ndk-r26b" $env:Path += ";C:\Android\ndk\android-ndk-r26b" ndk-build.cmd --version

--version会输出 NDK 版本和构建号,看到类似r26b的标识才算环境变量生效。不要在这个环节用setxsetxPath有 1024 字符截断风险,而且写入前会覆盖掉带%VAR%引用形式的已有值。

环境变量的用途对比如下:

变量名主要消费者说明
ANDROID_NDK_HOME独立 CMake 脚本、部分老式构建系统指向 NDK 根目录即可
ANDROID_NDK_ROOTReact Native autolink、Gradle 插件里的自定义任务部分工具硬编码了这个名字,漏设会静默走回旧路径
PATH中的 NDK 目录ndk-build.cmdllvm-readelf.exe等命令行工具便于手工调试 ABI 产物

3.2 编写最小 Android.mk 编译第一个 so

不接 Gradle,先验证 NDK 能不能独立完成交叉编译,最可靠的做法是用ndk-build编一个 JNI 动态库。先在工程目录建好jni子目录:

New-Item -ItemType Directory -Force C:\dev\ndk-hello\jni

jni下新建三个文件。hello.c定义一个最简 JNI 函数:

#include <jni.h> JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_NativeLib_stringFromJNI(JNIEnv *env, jobject thiz) { return (*env)->NewStringUTF(env, "hello from ndk r26b"); }

Android.mk声明模块名和源文件:

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)

Application.mk控制要生成哪些 ABI 的产物:

APP_ABI := arm64-v8a x86_64 APP_STL := c++_shared

LOCAL_MODULE是编译产物名,最终会生成libhello.soLOCAL_LDLIBS := -llog链上 Android 的 log 库,方便之后在 JNI 层打印日志。APP_ABI只保留arm64-v8ax86_64,Windows 模拟器通常需要 x86_64,真机用 arm64-v8a;如果不做模拟器,留下arm64-v8a即可,能省一半编译时间。

接着执行构建:

cd C:\dev\ndk-hello ndk-build.cmd NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=jni/Android.mk NDK_APPLICATION_MK=jni/Application.mk

NDK_PROJECT_PATH=.告诉构建脚本当前目录是工程根;APP_BUILD_SCRIPT显式指定Android.mkNDK_APPLICATION_MK指定Application.mk。文件都放在默认jni目录时,直接输ndk-build.cmd也能工作,但显式参数能减少误用其他工程jni目录的歧义。

构建成功后查看 ELF 头,确认产物确实是目标 ABI:

C:\Android\ndk\android-ndk-r26b\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-readelf.exe -h libs\arm64-v8a\libhello.so

输出里Machine字段是AArch64就说明交叉编译链路是通的。

3.3 关联 Android SDK 管理

ndk-build命令行验证通过,不代表 Gradle 也能找到 NDK。新版 AGP 默认去 SDK 目录下的ndk\26.1.10909125查找,不读ANDROID_NDK_HOME。所以手动解压的包要么复制到 SDK 的ndk目录,要么用sdkmanager重新安装一份。

用 SDK 自带命令行安装最省事:

sdkmanager "ndk;26.1.10909125"

这会装到%LOCALAPPDATA%\Android\Sdk\ndk\26.1.10909125。如果坚持用手动解压的 zip,也可以把整个目录移过去,但目录名必须改成版本号:

New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\Android\Sdk\ndk" Move-Item C:\Android\ndk\android-ndk-r26b "$env:LOCALAPPDATA\Android\Sdk\ndk\26.1.10909125"

Move-Item会在目标路径不存在时直接改名,避免多包一层目录。移动前先确认目标盘剩余空间够用,NDK 完整包一般在 3 GB 左右。

4. 把 android-ndk-r26b 接进 Gradle 和 CMake:参数设置与 Windows 避坑

4.1 用 ndkVersion 锁定 r26b,避免版本漂移

项目里一旦写死ndkVersion "26.1.10909125",不管开发者本机默认装了什么 r26c、r27,都会被迫切到 r26b。这一点对 Windows 的多人协作特别重要,因为 IDE 自动下载的版本在不同 Android Studio 版本里差异很大。

android { ndkVersion "26.1.10909125" defaultConfig { externalNativeBuild { cmake { arguments "-DANDROID_STL=c++_shared", "-DANDROID_PLATFORM=android-21" cFlags "-O2" cppFlags "-std=c++17" } } ndk { abiFilters "arm64-v8a", "x86_64" } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" } } }

ndkVersion使用的是唯一标识而不是r26b这种简写,写错版本号 AGP 会直接去下载,而不是静默回退。arguments里以-D开头的值会传给 CMake;-DANDROID_STL=c++_shared决定 C++ 运行时动态链接方式;-DANDROID_PLATFORM=android-21指定工具链参考的平台级,不必紧跟minSdk设得过大。abiFilters在 Windows 上最有用,四个 ABI 全编会显著拖慢增量编译。

4.2 手工用 CMake 和 Ninja 验证工具链

Gradle 的externalNativeBuild内部会把 CMake 包一层,报错时很难直接定位。独立跑一次 CMake,可以把 NDK 工具链本身的问题和 Gradle 配置的问题分离。假设src/main/cpp/CMakeLists.txt是:

cmake_minimum_required(VERSION 3.22.1) project(ndk_r26b_demo C CXX) add_library(hello SHARED hello.c) target_link_libraries(hello log)

在 PowerShell 里执行:

cmake -S . -B build -G Ninja ` -DANDROID_ABI=arm64-v8a ` -DANDROID_NDK=C:/Android/ndk/android-ndk-r26b ` -DCMAKE_TOOLCHAIN_FILE=C:/Android/ndk/android-ndk-r26b/build/cmake/android.toolchain.cmake ` -DANDROID_PLATFORM=android-21 cmake --build build

反引号是 PowerShell 续行符,用 cmd 时改成^-DANDROID_NDK-DCMAKE_TOOLCHAIN_FILE两个参数缺一不可,前者给 CMake 提供 NDK 根路径,后者指定 Android 交叉编译工具链定义。-G Ninja要求ninja.exe在 PATH 里,找不到时就显式加一条:

-DCMAKE_MAKE_PROGRAM=C:/Android/ndk/android-ndk-r26b/toolchains/llvm/prebuilt/windows-x86_64/bin/ninja.exe

Windows 下写路径全部用正斜杠,可以避免 CMake 把反斜杠当转义字符导致路径被拆散。

4.3 三个 Windows 必调参数与踩坑

实际操作里,我一般只在下面四个位置做调整,其余交给 AGP 默认值:

参数或配置类型作用与 Windows 注意点
-DANDROID_STL=c++_sharedCMake argument避免多个 so 各带一份 STL;Windows 上若用c++_static,链接期容易看到符号冲突,难排查
-DANDROID_PLATFORM=android-21CMake argument控制平台库基准;设得比minSdk高会留下运行时风险,设低则编译期约束更松
ndkVersion "26.1.10909125"Gradle 属性固定 r26b,避免 IDE 自动安装的新版把 ABI 生成规则改掉
abiFilters "arm64-v8a", "x86_64"Gradle ndk 块压缩 ABI 集合,Windows 上交叉编译最吃 CPU,ABI 越少增量编译越快

还有一个容易忽略的点:Gradle 内部生成的 CMake 变量优先级比环境变量高,所以不要在gradle.properties里用ANDROID_NDK_HOME这种全局注入来临时顶替,否则换个项目会带着错误路径。手工 CMake 验证通过后,回 Gradle 执行:app:assembleDebug,如果仍报错,再单独看build目录下的ninja.log,报错点通常比 IDE 的 Output 面板更具体。

5. 验证 r26b 安装与高频异常处理

5.1 命令行确认 NDK 版本与工具链完整

不要相信一次编译成功就万事大吉,换机器或换终端后环境变量经常静默失效。我习惯先跑一组固定命令:

ndk-build.cmd --version Select-String -Path C:\Android\ndk\android-ndk-r26b\source.properties -Pattern "Pkg.Revision" where.exe ndk-build.cmd

ndk-build.cmd --version确认命令行入口可用;第二行读到的Pkg.Revision = 26.1.10909125才是包的真实版本,如果显示的不是这个值,说明下载到的 zip 根本不是 r26b;第三行确认 PATH 里的ndk-build.cmd来自哪个目录,避免旧版本 NDK 被排到前面。

5.2 三个高频异常与修复

先看运行到编译时报什么错,Windows 上最常见到的三类如下:

第一类:Unable to locate NDKNDK not configured。新版 AGP 不读ANDROID_NDK_HOME,只认 SDK 下的ndk/<version>目录。解决办法是确认ndkVersion%LOCALAPPDATA%\Android\Sdk\ndk\26.1.10909125目录名一致,不一致就按第 3.3 节移动或重装 SDK 包。

第二类:Ninja: error: loading 'build.ninja': No such file or directory。通常是手工 CMake 时生成的build目录里没有build.ninja,说明 CMake 配置阶段提前失败;先删掉build目录再执行一次配置,把输出里的ANDROID_NDK路径和CMAKE_TOOLCHAIN_FILE打印出来核对。

第三类:undefined reference to __android_log_print。这是链接 log 库失败,Android.mk 工程要在LOCAL_LDLIBS里加-llog,CMake 工程要在CMakeLists.txt里写target_link_libraries(hello log),加在cFlags里是无效的。

如果每次都要手工验证,可以在 PowerShell 里把这四条命令存成Check-Ndk.ps1,一键输出版本、路径和第一个 so 的 ELF 头部。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询