示例工程移动开发【免费下载链接】ndk-samplesAndroid NDK samples with Android Studio项目地址https://gitcode.com/gh_mirrors/nd/ndk-samples点击查看免费下载本篇技术指南以 Android NDK Samples 仓库中的 hello-jni 示例为核心系统讲解在 Android Studio 中通过 JNIJava Native Interface从 Java/Kotlin Activity 调用原生 C/C 代码的完整链路从 CMake 构建配置、JNI 函数命名与签名规则到System.loadLibrary加载时机与常见异常排查。读完本篇你将能够独立搭建一个最小可运行的 NDK 工程并理解 Java 与 Native 层之间的调用契约与运行时机制。一、示例概览Hello JNI 解决什么问题hello-jni 是 Android NDK 入门级示例核心目标只有一个让一个 Android Activity 调用一段 C/C 代码并把返回的字符串显示在界面上。它不涉及复杂的图形渲染、音视频处理或性能优化而是把 JNI 工程的最小可行骨架完整呈现出来是理解 NDK 开发后续所有高级示例如 hello-gl2、native-audio、gles3jni的基础。从仓库结构看这个示例由两部分组成详见 hello-jni/app/src/main应用层Kotlin 编写的HelloJniActivity位于 HelloJni.kt声明external原生方法原生层C 编写的 JNI 实现位于 hello-jni.cpp通过 CMake 编译成共享库libhello-jni.so。值得注意的是该示例已从早期的 Java 实现迁移为Kotlin ViewBinding的现代写法build.gradle 中开启了viewBinding true是阅读官方新代码风格的良好范本。二、环境准备Pre-requisites官方 README 明确给出了运行前提Android Studio 4.2并随 Android Studio 一起安装或单独配置NDKNative Development Kit与CMake工具链。当前仓库的构建环境更进一步体现了现代 NDK 工程的做法仓库通过版本目录Version Catalog统一管理依赖版本见 gradle/libs.versions.toml其中 Android Gradle Plugin 版本为 8.7.0、Kotlin 为 1.9.0hello-jni 模块自身使用 AGP 8.7.0 与 Kotlin 插件构建hello-jni/app/build.gradle 中的ndksamples.android.application与ndksamples.android.kotlin插件原生侧 CMake 最低版本要求为3.22.1见 CMakeLists.txt 首行cmake_minimum_required(VERSION 3.22.1)。建议在 Android Studio 的 SDK Manager 中勾选 NDK (Side by side) 与 CMake 组件确保本机工具链版本不低于上述要求。三、快速开始四个步骤跑起来README 中的 Getting Started 给出了极简的启动路径整理如下下载并安装 Android Studio4.2 及以上版本启动 Android Studio在欢迎页选择 Open 打开本示例所在目录即hello-jni目录等待 Gradle 同步完成首次同步会下载 AGP、依赖库等耗时取决于网络连接设备或启动模拟器后点击菜单Run / Run app即可在界面上看到 C 层返回的字符串。构建层面Gradle 会自动完成以下工作通过 hello-jni/app/build.gradle 中的externalNativeBuild { cmake { path src/main/cpp/CMakeLists.txt } }配置将 CMake 构建接入 Gradle 任务链编译libhello-jni.so并随 APK 打包安装时由包管理器将 so 解压到应用私有目录下文详述。四、Kotlin 侧声明 external 方法与加载动态库打开 HelloJni.kt可以看到 JNI 调用的两个关键步骤。1. 加载原生库companion object { init { System.loadLibrary(hello-jni) } }System.loadLibrary(hello-jni)会按平台命名规则查找名为libhello-jni.so的动态库。注释中还给出了一个关键细节该库在应用安装阶段即由包管理器Package Manager解压到/data/data/com.example.hellojni/lib/libhello-jni.so因此运行时无需关心 so 文件的确切位置。2. 声明 external 函数external fun stringFromJNI(): String?external关键字声明这是一个由原生代码实现的方法其实现会在首次调用时从当前已加载的原生库中按 JNI 命名规则查找。HelloJni 的onCreate通过 ViewBinding 拿到布局中的 TextView布局见 activity_hello_jni.xml其 id 为hello_textview并把原生函数返回值设置为文本val binding ActivityHelloJniBinding.inflate(layoutInflater) setContentView(binding.root) binding.helloTextview.text stringFromJNI()3. 一个故意留坑的反例类中还声明了一个故意不实现的原生方法external fun unimplementedStringFromJNI(): String?源码注释明确说明Kotlin/Java 中可以声明任意多个external方法它们的实现只在首次调用时才到当前已加载的原生库中查找。一旦调用unimplementedStringFromJNI()由于原生层不存在对应符号运行时将抛出java.lang.UnsatisfiedLinkError异常。这个反例的作用是帮助初学者理解 JNI 符号查找是懒加载、按需解析的——声明本身不会报错调用才会失败。五、C 侧JNI 函数命名规则与签名原生实现位于 hello-jni.cpp完整代码如下#include jni.h #include string extern C JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env, jobject /* this */) { std::string hello Hello from JNI.; return env-NewStringUTF(hello.c_str()); }这段代码体现了 JNI 原生函数的全部规范要素extern C防止 C 名称修饰name mangling确保导出符号名与 JVM 查找规则一致JNIEXPORT/JNICALL由jni.h定义的宏分别控制导出可见性与调用约定函数名 Java_ 包名点转下划线 _ 方法名com.example.hellojni.HelloJni.stringFromJNI对应Java_com_example_hellojni_HelloJni_stringFromJNI。这是 JVM 定位原生实现的默认规则Kotlin/Java 侧方法名、包名与 C 侧函数名必须严格一致否则首次调用会抛出UnsatisfiedLinkError前两个固定参数JNIEnv* envJNI 环境指针用于调用 JNI API与jobject调用该方法的对象引用此处未使用故注释为this返回值类型映射jstring对应 Kotlin 的String?。C 字符串不能直接返回必须通过env-NewStringUTF(...)构造 JVM 可识别的 UTF-16 字符串对象。从函数签名可以看出JNI 层与 Kotlin 层是一一对应的stringFromJNI()返回String?原生层返回jstring参数列表同样遵循JNI 类型 ↔ 平台类型的映射表如jint ↔ Int、jboolean ↔ Boolean、jobjectArray ↔ Array等。六、CMake 构建配置把 C 变成共享库hello-jni/app/src/main/cpp/CMakeLists.txt 是整个原生构建的指挥所cmake_minimum_required(VERSION 3.22.1) project(hello-jni) add_library(hello-jni SHARED hello-jni.cpp) # Include libraries needed for hello-jni lib target_link_libraries(hello-jni android log)逐行解读cmake_minimum_required(VERSION 3.22.1)声明 CMake 最低版本需与 Android Studio 内置 CMake 版本匹配add_library(hello-jni SHARED hello-jni.cpp)把hello-jni.cpp编译为共享库SHARED最终产物为.so库名hello-jni即对应 Kotlin 侧System.loadLibrary(hello-jni)所引用的名字target_link_libraries(hello-jni android log)链接 Android 系统库。android提供 NDK 平台 APIlog提供__android_log_print等日志输出能力——虽然本例未直接使用日志但这是 NDK 工程的标配链接项后续几乎所有示例如 audio-echo都会用到。该 CMakeLists 通过 hello-jni/app/build.gradle 的externalNativeBuild块接入 GradleexternalNativeBuild { cmake { path src/main/cpp/CMakeLists.txt } }构建时AGP 会为每种目标 ABI如arm64-v8a、armeabi-v7a、x86、x86_64分别编译一份 so 并打包进 APK运行时由系统按设备架构选择加载。七、运行时行为与常见问题排查完整调用链回顾一次 JNI 调用的完整生命周期如下APK 安装时包管理器将libhello-jni.so解压到/data/data/com.example.hellojni/lib/HelloJni类的companion object初始化时执行System.loadLibrary(hello-jni)把 so 加载进进程ActivityonCreate调用stringFromJNI()JVM 按Java_com_example_hellojni_HelloJni_stringFromJNI规则查找到 C 函数并执行C 函数构造jstring返回Kotlin 侧拿到Hello from JNI.字符串并设置到 TextView。常见报错速查现象原因排查方向应用启动即崩溃日志含UnsatisfiedLinkError: dlopen failed: library libhello-jni.so not foundSystem.loadLibrary的库名与add_library名称不一致或 so 未打包核对loadLibrary(hello-jni)与 CMake 中add_library(hello-jni ...)的名称是否一致调用stringFromJNI()时抛UnsatisfiedLinkError: No implementation foundC 函数名与 Kotlin 包名/类名/方法名不匹配或漏写extern C按Java_包名_类名_方法名逐段核对检查符号是否被 C name mangling返回的中文乱码C 侧字符串编码与 JVM 期望不符使用NewStringUTF构造返回字符串而非直接强转指针Kotlin/Java 侧方法未声明为external却调用原生实现缺少external修饰符在方法前补充external关键字需要特别强调第 2 种情况示例中故意保留的unimplementedStringFromJNI()正是这种错误的教学演示它印证了JNI 符号解析发生在首次调用时而非库加载时。八、延伸阅读全局项目结构与多示例协作方式见仓库根目录 README.md 与 ARCHITECTURE.md想要在原生侧输出调试日志可参考 base/src/main/cpp 中基于log库封装的日志工具若需深入 JNI 与 C 异常处理、回调等进阶用法可对比学习 exceptions 示例向官方仓库贡献代码前请阅读 CONTRIBUTING.md。九、许可协议hello-jni 示例版权归 Google, Inc.Copyright 2022所有遵循 Apache License, Version 2.0 许可协议发布。你可以自由使用、修改与分发本示例代码但需保留原始版权声明并在分发时附带许可证副本详见仓库根目录 LICENSE。总结hello-jni 用最少的代码量完整呈现了 NDK 工程的三大支柱——Kotlin 侧的external声明与System.loadLibrary加载、C 侧的 JNI 命名规范与类型映射、CMake 的共享库构建配置。掌握这三者你就掌握了 Android 上 Java/Kotlin 与 C/C 互操作的最小闭环为阅读仓库中其余 20 余个进阶示例图形、音频、编解码、神经网络等打下坚实基础。赞分享示例工程移动开发【免费下载链接】ndk-samplesAndroid NDK samples with Android Studio项目地址https://gitcode.com/gh_mirrors/nd/ndk-samples点击查看免费下载相关推荐Hello JNI如何在Java中调用C代码ndk-samples入门样本完整教程Hello JNI如何在Java中调用C代码ndk samples入门样本完整教程 ndk samples 是 Android 官方的 NDK 示例仓库其示例工程移动开发Android NDK Samples入门指南JNI基础与Hello-JNI详解Android NDK Samples入门指南JNI基础与Hello JNI详解 Android NDK Samples是Google官方维护的示例代码仓库示例工程移动开发LeetDown实战指南macOS平台A6/A7设备降级高效方案LeetDown实战指南macOS平台A6/A7设备降级高效方案 LeetDown是一款专为macOS设计的图形化iOS设备降级工具针对搭载A6/A7芯片的桌面应用逆向工程固件上一篇从入门到精通解决Chataigne 90%技术难题的实战指南下一篇ImGui-SFML 项目常见问题解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
