1. NDK 开发环境搭建与首个 JNI 程序
环境准备与版本对齐
NDK 开发链路涉及四个必须版本兼容的组件:Android Studio、Android Gradle Plugin(AGP)、NDK、CMake。版本错配是首次搭建最常见的失败原因,因此先确认工具链版本,再创建工程。
- Android Studio:建议使用当前稳定版(如 Ladybug 或更新),自带 SDK Manager 与 NDK 下载入口。
- NDK:通过 SDK Manager 的 SDK Tools 页勾选 NDK (Side by side),安装后位于
$ANDROID_SDK/ndk/<版本号>。推荐使用 LTS 版本(如 27.x),避免使用已弃用的ndk-bundle路径。 - CMake:同样在 SDK Tools 中勾选 CMake,Android Studio 会使用 SDK 内置的 CMake 而非系统 PATH 中的版本,避免宿主机 CMake 版本干扰。
- LLDB:勾选 Android SDK Platform-Tools 与 LLDB,用于 native 断点调试。
在
local.properties 中显式声明 ndk.dir 已不推荐;现代 AGP 通过 android.ndkVersion 指定版本,由 Gradle 自动解析 SDK 内的 NDK 路径,可避免团队协作时的路径差异。工程结构与构建链路
一个可运行的 JNI 工程由 Java 层、native 源码层和 CMake 构建脚本三部分组成。Java 层通过 System.loadLibrary 加载 .so,native 层用 extern "C" 导出符合 JNI 命名约定的符号,CMake 负责把 .cpp 编译成各 ABI 的共享库并打包进 APK。
创建工程与关键配置
在 Android Studio 中选择 Native C++ 模板新建工程,模板会自动生成 cpp/native-lib.cpp、CMakeLists.txt 与 externalNativeBuild 配置。若从空工程手动添加,需在 app/build.gradle.kts 中补齐以下内容:
android {
namespace = "com.example.ndkfirst"
compileSdk = 35
ndkVersion = "27.0.12077973" // 与 SDK Manager 中已安装版本一致
defaultConfig {
applicationId = "com.example.ndkfirst"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
externalNativeBuild {
cmake {
cppFlags += "-std=c++17"
abiFilters += listOf("arm64-v8a", "x86_64")
}
}
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1" // 与 SDK 内置 CMake 版本一致
}
}
}
abiFilters 只保留 arm64-v8a 与 x86_64 可显著缩短首次构建时间;若真机为 32 位设备,需补上 armeabi-v7a,否则运行时会抛出 UnsatisfiedLinkError。CMakeLists.txt 与 native 实现
cmake_minimum_required(VERSION 3.22.1)
project("native-lib")
add_library(native-lib SHARED native-lib.cpp)
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_ndkfirst_NativeBridge_hello(JNIEnv *env, jobject /* this */) {
std::string msg = "Hello from JNI";
return env->NewStringUTF(msg.c_str());
}
Java/Kotlin 侧声明与调用:
object NativeBridge {
init { System.loadLibrary("native-lib") }
external fun hello(): String
}
// Activity 中
binding.sampleText.text = NativeBridge.hello()
构建、运行与验证
- 点击 Sync Now,确认 Gradle 未报
NDK not configured或CMake version not found。 - 执行 Build > Make Project,在
app/build/intermediates/cxx/下可看到各 ABI 的.so产物。 - 连接设备或启动模拟器,点击 Run。界面应显示
Hello from JNI。 - 若显示异常,用
adb logcat | grep -i "UnsatisfiedLink\|JNI"定位是库未加载还是符号未找到。
验证要点:
① 符号名必须与包名、类名、方法名严格对应,
②
③ 首次构建会下载 CMake 与 NDK 组件,需保持网络可用。
① 符号名必须与包名、类名、方法名严格对应,
com.example.ndkfirst.NativeBridge.hello 对应 Java_com_example_ndkfirst_NativeBridge_hello;②
System.loadLibrary("native-lib") 中的名称不含 lib 前缀与 .so 后缀;③ 首次构建会下载 CMake 与 NDK 组件,需保持网络可用。
常见失败与排查
| 现象 | 可能原因 | 处理 |
|---|---|---|
| UnsatisfiedLinkError: dlopen failed | APK 中缺少当前设备 ABI 的 .so | 在 abiFilters 中补充对应 ABI 并重新构建 |
| UnsatisfiedLinkError: No implementation found | JNI 函数名拼写或包名不匹配 | 核对 Java_ 后的完整路径,注意下划线转义 |
| CMake Error: could not find CMake | SDK Tools 未安装 CMake 或版本号写错 | 在 SDK Manager 安装对应版本,或修正 version 字段 |
| NDK not configured | 未安装 NDK 或 ndkVersion 与已装版本不一致 | 安装匹配版本,或删除 ndkVersion 让 AGP 自动选择 |