ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows下Android NDK r28c从下载到配置的完整指南

Windows下Android NDK r28c从下载到配置的完整指南 简介Android NDK r28c 是面向 Android 原生开发者的官方工具集专为 Windows 64 位平台构建适用于需通过 C/C 编写高性能模块如图像处理、音视频编解码、AI 推理引擎的中高级开发者。本资源完整封装了 NDK 核心头文件、类型定义与平台扩展接口涵盖 Camera 元数据标签、Neural Networks API、OpenGL ES 扩展、Unicode 字符处理及 Linux V4L2 控制等关键能力可直接集成至 Android Studio 或自定义构建流程。压缩包含 2000 个文件主体为 1977 个 .h 头文件提供跨平台原生接口声明辅以 11 个 Python 脚本用于构建自动化与工具链管理、10 个 Markdown 文档含 API 说明与迁移指南、1 个 PDF 官方参考手册及基础文本配置文件总大小 713.46MB目录结构规范便于按功能模块快速定位。已有 176 人下载学习是搭建 Android 原生开发环境、理解底层系统交互机制及开展跨架构移植工作的可靠基础组件。 最近要给一个老项目适配新机器我从头下载了android-ndk-r28c-windows.zip这个 Windows 版 NDK 压缩包。说实话很多人拿到这个 zip 后的第一反应是解压完往那一放结果 Android Studio 要么报“NDK not configured”要么就是ndkVersion对不上然后开始莫名其妙地联网重下。这篇就把我从下载、解压、配置、跑通命令行编译再到踩了一堆 Windows 特有坑的完整过程写出来。适合第一次接触 NDK 的移动端开发者也适合正在从 r26、r27 往上升级的同学做参考。1. 版本号里的门道r28c 到底是哪个版本、和 r27、r26 差在哪1.1 从文件名拆出来的有效信息大部分 Android 开发者看到android-ndk-r28c-windows.zip只把它当成一个“下载链接里的尾巴”其实这个文件名已经把最关键的信息写清楚了。拆开看就是四段android-ndk这是 Android Native Development Kit 的标准前缀。r28c主版本号是 28c 是 r28 的第三次修订包。windows运行平台对应 Windows x86_64。zip免安装压缩包解压即用。这个命名规则和 Linux、macOS 上的 NDK 包是一致的比如 Linux 版本会叫android-ndk-r28c-linux.zipmacOS 会叫android-ndk-r28c-darwin.dmg或者darwin.zip。所以你在不同平台的 CI 机器上拉取同一套工具链时只要把文件名里的平台字段换掉就行版本号里面的r28c完全不用动。r28c这里的c是“revision c”的意思。Google 对 NDK 的版本管理基本是大版本号加小写字母修订号。比如r27a、r27b、r28c。字母越往后表示在这个大版本里修复了越多重要问题。换句话说同一大版本下能选c就不要选a因为后面带的都是实打实的 bugfix特别是 Windows 平台上的路径、长文件名、符号链接问题往往都是在小版本修订里才被磨平的。1.2 r28 的工具链变化直接影响老项目迁移r28 这个版本对老项目的直接冲击主要集中在工具链和最低 API 级别上。从工具链角度看NDK 早就全面转到 Clang/LLVM 了GCC 相关的交叉工具在 r18 之后就逐渐退出r28 里面你根本找不到arm-linux-androideabi-gcc这类文件。如果你的项目还在用ndk-build并且依赖一些老旧的 GCC 参数那升级之后大概率会直接报“unknown argument”或者“unable to execute command”之类的错误。从 API 级别看新版 NDK 对minSdkVersion的要求也在往上抬。老项目里常见的APP_PLATFORM : android-16或-DANDROID_PLATFORMandroid-16这种配置在较新的 NDK 上可能已经直接不被支持编译时会被工具链拒绝。所以 r28 里你需要重新检查Application.mk和 CMake 里的ANDROID_PLATFORM把它提升到一个合理的水平。具体每个大版本支持的最低 API 是多少以source.properties或官方发布说明为准千万别想当然用老版本的老参数。1.3 为什么我坚持用 zip 而不是安装器Windows 上 NDK 官方给过两种发布形态zip 压缩包和安装器 exe。安装器会把 NDK 塞进你指定的 SDK 目录或者默认放到C:\Android\android-sdk\ndk\...下好处是省事坏处是它帮你做了一些目录管理和版本绑定的决定一旦你后面想换版本或者迁移到其他机器反而没那么透明。zip 包的优势在于不写注册表不污染系统。解压后可以放在任意干净路径想留几个版本就留几个版本。CI 环境里只要把 zip 下载、解压、设置环境变量三步完成。打包到本地缓存方便拷贝不用每次都跑联网下载。所以我个人更推荐直接把 zip 当作一个绿色工具链来管理。接下来要讲的就是这种“绿色部署”的完整流程。2. Windows 部署的完整姿势解压位置、环境变量与验证命令2.1 解压前先想清楚三件事我吃过不少亏现在每次解压 NDK 之前都会先确认三件事第一路径里不要有空格。很多人喜欢解压到C:\Program Files\Android\...这个位置在 Android Studio 里一般没问题但当你打开命令行手动敲 CMake 命令或者 ndk-build 时空格和引号问题会非常折磨人。我的建议是直接放在C:\Android\NDK\android-ndk-r28c这种纯英文、无空格的路径下。第二路径里不要有中文和特殊符号。这不是玄学而是 Windows 下不同的终端编码环境对中文路径的处理方式不一致。如果你用 PowerShell 配置环境变量用 CMD 跑编译脚本很可能同一个中文路径在一种环境里正常在另一种环境里就出现字节错乱。为了省事从源头避开。第三整个路径长度不要拉太长。Windows 的经典路径长度限制是 260 个字符NDK 工具链内部嵌套很深比如toolchains\llvm\prebuilt\windows-x86_64\bin\clang.exe如果你把 NDK 解压到一层套一层很深的目录里文件路径很容易逼近限制到时候编译报莫名其妙的 “File name too long” 你就知道后悔药不够用了。2.2 环境变量配置ANDROID_NDK_HOME 和 PATH 到底怎么设解压完成之后环境变量是让命令行工具能快速找到 NDK 的关键。虽然 Android Studio 有自己的一套 SDK 位置管理逻辑但命令行场景下没有正确设置环境变量会经常出问题。我一般会设置一个用户级别的环境变量ANDROID_NDK_HOME指向 NDK 解压后的根目录[Environment]::SetEnvironmentVariable(ANDROID_NDK_HOME, C:\Android\NDK\android-ndk-r28c, User)这个变量的作用是给ndk-build.cmd、CMake 工具链脚本以及一些第三方构建工具提供统一的 NDK 入口。另外一个常见变量是ANDROID_NDK_ROOT。在 CMake 的安卓工具链里有些脚本仍会尝试读取ANDROID_NDK_ROOT。如果你的构建工具比较新基本都认ANDROID_NDK_HOME但为了兼容起见我建议两个变量都设成同一个目录[Environment]::SetEnvironmentVariable(ANDROID_NDK_ROOT, C:\Android\NDK\android-ndk-r28c, User)至于PATH我不建议把 NDK 根目录加进去因为 NDK 根目录下的可执行文件其实不多而且可能会和你系统里其他同名工具冲突。真正有用的目录是编译工具链所在的C:\Android\NDK\android-ndk-r28c\toolchains\llvm\prebuilt\windows-x86_64\bin把这个路径加到PATH里你就能直接在终端里敲clang、clang、llvm-ar这些命令来验证工具链是否可用。用 PowerShell 加 PATH 的话要稍微绕一下因为 PATH 本身是一个分号分隔的字符串$oldPath [Environment]::GetEnvironmentVariable(Path, User) $newPath C:\Android\NDK\android-ndk-r28c\toolchains\llvm\prebuilt\windows-x86_64\bin; $oldPath [Environment]::SetEnvironmentVariable(Path, $newPath, User)注意修改完环境变量后最好新开一个终端窗口再验证因为已经打开的窗口不会自动刷新环境变量。2.3 验证部署是否成功配置完成后第一时间做验证。打开一个新的 PowerShell 窗口执行 $env:ANDROID_NDK_HOME\toolchains\llvm\prebuilt\windows-x86_64\bin\clang.exe --version如果能看到类似clang version 18.x.x的输出说明工具链已经可以正常运行了。同时也检查一下source.properties这个文件在 NDK 根目录下记录了当前包的完整版本信息Get-Content $env:ANDROID_NDK_HOME\source.properties你应该能看到Pkg.Revision 28.x.x.x这样的一串数字这个数字非常关键后面 Android Studio 识别 NDK 版本时用的就是它。3. Android Studio 里的正确接法Gradle 的 ndkVersion 与 SDK 目录结构3.1 Android Studio 为什么总说“找不到 NDK”很多人的疼点在于明明我从官网下载了 zip解压了环境变量也设了可 Android Studio 的 Gradle 构建还是报错NDK not configured或者NDK did not have a source.properties file这种情况十有八九是因为你把 zip 解压到了任意的目录但 Android Studio 并不会去全局搜索你的ANDROID_NDK_HOME。它自己有固定的 SDK 扫描逻辑Android SDK 目录下的ndk文件夹里每一个子文件夹代表一个 NDK 版本文件夹的名称必须和该版本的版本号对应。也就是说Android Studio 期望目录长这样你的SDK目录\ndk\28.x.x.x\如果你直接解压得到android-ndk-r28c文件夹还把它放到了 SDK 的ndk目录下但不重命名成28.x.x.xAS 就会认为这个 NDK 没有正确的source.properties从而拒认。正确做法是打开 NDK 根目录的source.properties。记下Pkg.Revision字段比如它可能是28.0.12916984。把整个文件夹改名为28.0.12916984并放到SDK\ndk\下。完成之后重新打开项目Gradle 就能识别到这个 NDK 了。3.2 build.gradle 里的 ndkVersion 和 externalNativeBuild现在标准的做法是在模块的build.gradle里显式声明ndkVersion这样即使同一个 SDK 里装了多套 NDK构建系统也知道该用哪一套。android { compileSdk 34 ndkVersion 28.0.12916984 // 这里必须和 source.properties 里的 Pkg.Revision 一致 }我见过不少朋友在这个字段上踩坑网上复制了一个ndkVersion 25.0.xxxx但本地其实没有那个版本Gradle 就会去下载下载失败后就报错。正确思路永远是打开你本机SDK\ndk\目录看一眼里面实际有哪些版本再决定ndkVersion写什么。如果你的项目涉及 C/C 代码还会同时看到externalNativeBuild配置android { defaultConfig { externalNativeBuild { cmake { cppFlags -stdc17 arguments -DANDROID_STLc_shared } } } externalNativeBuild { cmake { path src/main/cpp/CMakeLists.txt } } }这里面的ANDROID_STLc_shared值得多提一句。老项目可能习惯了gnustl_shared或stlport但这些早就被移除了。r28 上你只能选择c_shared或c_static前者把 C 运行库打成独立的.so包会变大但多个 so 之间不会重复包含同一份运行时后者把运行库静态编进你的 so 里包小但多个 so 同时使用时容易撞符号。默认选c_shared在多数场景下比较稳妥。3.3 通过 SDK Manager 装过的 NDK 和这个 zip 有什么区别SDK Manager 安装 NDK 本质上做的事也是解压只是它帮你把目录放对了并且可以在项目构建时自动下载缺的版本。如果你已经下载了android-ndk-r28c-windows.zip就没必要再让 SDK Manager 下载一遍同样的东西。你可以用前文提到的重命名方法把这个 zip 放进 SDK 的ndk目录然后把项目里ndkVersion写成对应的版本号。这样 Android Studio 检测到本地已经有这个 NDK 时就不会再执行联网下载了。离线环境下这种“带包部署”的方式尤其好用。比如内网开发机上没法直接访问 Google 的 SDK 仓库那我就会提前在其他机器上下载好对应版本的android-ndk-r*.zip拷贝到内网开发机手动解压到 SDK 的ndk目录自动构建就能跑起来。4. 不打开 IDE 的命令行编译最小 JNI 示例跑通 NDK4.1 用 ndk-build.cmd 构建一个 libhello.so配置好环境变量后我们直接从命令行验证整个工具链。这里用一个最朴素的 JNI 示例连 Android Studio 都不用打开。先创建一个hello.c代码就做一件事返回一个字符串给 Java 层。#include jni.h JNIEXPORT jstring JNICALL Java_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) { return (*env)-NewStringUTF(env, Hello from NDK r28c); }接着创建Android.mkLOCAL_PATH : $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE : hello LOCAL_SRC_FILES : hello.c include $(BUILD_SHARED_LIBRARY)以及Application.mkAPP_ABI : arm64-v8a x86_64 APP_PLATFORM : android-21然后在项目根目录执行C:\Android\NDK\android-ndk-r28c\ndk-build.cmd NDK_PROJECT_PATH. APP_BUILD_SCRIPTjni/Android.mk NDK_APPLICATION_MKjni/Application.mk注意这里要把目录结构摆成标准 NDK 工程形态hello.c和Android.mk、Application.mk放在同级的jni子目录下否则ndk-build脚本的默认目录扫描会跟你捉迷藏。编译成功后你会在libs/arm64-v8a/libhello.so和libs/x86_64/libhello.so下看到产物。这个产物就是可以打包进 APK 的原生库。4.2 用 CMake 工具链文件构建除了ndk-build现在大多数新项目用的是 CMake。NDK 自带的 CMake 工具链文件位于C:\Android\NDK\android-ndk-r28c\build\cmake\android.toolchain.cmake写一个CMakeLists.txtcmake_minimum_required(VERSION 3.22.1) project(hello C) add_library(hello SHARED hello.c)然后执行cmake -S . -B build -G Ninja ^ -DCMAKE_TOOLCHAIN_FILEC:\Android\NDK\android-ndk-r28c\build\cmake\android.toolchain.cmake ^ -DANDROID_ABIarm64-v8a ^ -DANDROID_PLATFORMandroid-21 ^ -DANDROID_STLc_shared这里有几个参数值得解释ANDROID_ABI指定目标 ABI默认是arm64-v8a。你可以用armeabi-v7a、x86、x86_64但要确认当前 NDK 版本对这些 ABI 的支持情况。ANDROID_PLATFORM指定android-XX的 API 级别这决定了最低支持的 Android 版本。ANDROID_STL指定 C 标准库的链接方式。CMake 构建完成后产物在build\arm64-v8a\libhello.so目录下。4.3 验证产物的 ABI 和链接情况生成的.so是否真的可以放进 APK有一个快速检查方法用 NDK 自带的llvm-readelf或者llvm-objdump查看 ELF 头。比如C:\Android\NDK\android-ndk-r28c\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-readelf.exe -h libs\arm64-v8a\libhello.so输出里会明确显示Machine: AArch64说明这个 so 是给 arm64 用的。如果发现 Machine 是x86_64那说明你构建参数里的 ABI 选错了这个包打进 APK 后会在某些设备上出现Library not found的运行时崩溃。这里的核心思路是不要只看文件名和后缀要去看 ELF 的真实架构尤其是当你同时用命令行和 Android Studio 混合构建时很容易构建出和预期 ABI 不一致的产物。5. Windows 上几个高频坑的完整排查链路5.1 路径含空格或中文导致 clang 在编译中段诡异退出我有一台工作机用户目录是中文名项目也放在D:\My Projects\...路径下。第一次跑 NDK 编译时报错信息五花八门最开始是clang.exe: error: unable to execute command: Program not executable这个报错说得不清不楚。我第一个反应是 clang 没有执行权限但 Windows 哪来的执行权限问题后来我单独在命令行里运行C:\Android\NDK\android-ndk-r28c\toolchains\llvm\prebuilt\windows-x86_64\bin\clang.exe --version这个能正常运行说明工具链本身没问题。问题一定出在项目路径或 NDK 路径的解析上。接着我把构建命令中的路径用引号包住还是失败。最后把整个项目复制到C:\tmp\ndktest并且保证 NDK 也放在无空格无中文的路径下再跑一次编译通过。排查结论NDK 的 Make 系统和 CMake 脚本在 Windows 下对路径中的空格处理仍然不完美。C:\Program Files这种短路径往往没问题但一旦嵌套很深再加上中文用户名极容易触发编码或路径截断问题。所以在这类问题上别想着修代码直接挪位置最省事。5.2 ndkVersion 和本地实际版本对不上Gradle 反复联网下载另一个高频坑是Android Studio 项目里写的ndkVersion是别人的版本号比如网上教程里是25.1.8937393但你本地只有 r28cGradle 就会在构建时自动去找25.1.8937393并且尝试下载。如果网络环境不理想下载失败两次后构建就失败了。排查链路是这样的先看构建输出里NDK相关日志是不是在下载ndkVersion。打开项目根目录的local.properties看sdk.dir指向哪个目录。在这个 SDK 目录下的ndk文件夹里列出所有已安装的 NDK 版本。把build.gradle里的ndkVersion改成你在该目录里看到的那一长串数字。我当时写完这个版本号后再同步检查source.properties里的Pkg.Revision发现两者一致构建立刻就不下载了。注意ndkVersion必须写类似于28.0.12916984这样的长数字不能写r28c也不要写28。这个版本号的格式是 Gradle 用来区分小版本的少一段或多一段都会导致匹配失败。5.3 老项目 API level 太低r28 直接拒绝编译从 r26 往上升级的项目最容易碰到这个问题。我在验证一个旧模块时Application.mk里写的是APP_PLATFORM : android-19编译时直接报error: Invalid platform android-19 in NDK这个报错不是随口说说的而是新 NDK 工具链里的默认平台检查机制变严格了。解决方案是把android-19改成支持范围内的值比如android-21或android-24。具体支持到几以ndk-build或 CMake 的提示为准。升级 API level 后要连带检查代码里的旧 API 调用。比如__android_log_print这些老接口没动但要留意一些已经废弃的 C 库函数在新 NDK 里可能不再导出。这种问题一般会有编译链接时的 undefined reference 提示排查起来比运行时崩溃要友好得多。5.4 编译日志乱码和终端编码问题Windows 下 NDK 输出乱码是一个很顽固的问题尤其是在中文 Windows 系统上。CMD 默认的代码页可能是 936而 NDK 工具链输出的 UTF-8 日志会被错误解码出现一堆问号或方块字。排查起来不复杂但很烦。解决方案是在执行编译前先把终端切换成 UTF-8chcp 65001PowerShell 用户可以在当前会话设置输出编码[Console]::OutputEncoding [System.Text.Encoding]::UTF8这一步主要解决“日志乱码”的显示问题不会影响编译产物本身。但如果你发现编译和文件路径中涉及中文文件名那就不是切换代码页能救回来的只能回到最初的建议所有路径全部用英文。6. 配置完之后的检查清单以及我的一些习惯6.1 一分钟快速判断 NDK 状态是否正常我每次在新机器上配置完 NDK不会急着打开 Android Studio而是先执行下面这组命令# 查看 NDK 环境变量 echo $env:ANDROID_NDK_HOME # 查看核心版本信息 Get-Content $env:ANDROID_NDK_HOME\source.properties | Select-String Pkg.Revision # 查看编译器版本 $env:ANDROID_NDK_HOME\toolchains\llvm\prebuilt\windows-x86_64\bin\clang.exe --version三条命令都正常基本可以放心交给 Android Studio。如果哪条没输出就顺着对应章节排查。6.2 多版本 NDK 共存管理心得实际项目里不同的历史分支可能锁定不同 NDK 版本比如老分支用 r23新分支用 r28。我现在的习惯是在 SDK 的ndk目录下保留多个版本目录C:\Android\sdk\ndk\23.2.8568313 C:\Android\sdk\ndk\28.0.12916984然后在每个项目里用ndkVersion锁定自己需要的版本。这样切分支时不会因为只有单一 NDK 版本而被迫改代码。手动下载的 zip 包解压后我会先把android-ndk-r28c这类目录重命名成版本号再放进ndk目录。这个习惯帮我避免了很多“AS 不认目录”的尴尬。6.3 给新项目的一点建议如果你是从零开始搭建不要直接把“最新 NDK”当成默认配置。先确认项目要支持的最低 Android 系统版本再对照 NDK 发行说明选一个合适的版本。稳定优先没必要追求永远追新。另外C/C 源码在 Windows 上使用 NDK 编译时换行符和编码也会引发一些奇怪问题。建议 Git 仓库统一使用 LF 换行.gitattributes里把*.c、*.h、*.cpp都声明成text eollf。这能避免代码在 Windows 和 Linux CI 之间来回切换时出现大量无意义的警告。最后再分享一个我在多次踩坑后养成的习惯下载完android-ndk-r28c-windows.zip后立刻校验压缩包哈希比如用 PowerShell 里的Get-FileHash确认和官方页面给出的 SHA-256 一致再解压。Windows 环境里第三方下载源多文件损坏、被篡改、下载不完整的情况远比想象中常见。等你编译到一半发现 clang 崩溃那时候再去排查是 zip 的问题成本就高多了。本文还有配套的精品资源点击获取
返回列表