首页/新闻资讯/正文详情

Hello JNI 深度解析:Android Studio 下 JNI 调用 C/C++ 代码的完整实战指南

发布时间:2026/9/24 13:56:16 来源:云帆数科 栏目:资讯中心
Hello JNI 深度解析:Android Studio 下 JNI 调用 C/C++ 代码的完整实战指南
示例工程移动开发【免费下载链接】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),仅供参考

相关推荐

一行依赖三步搞定:cjpm集成metaphone4cj语音算法完整指南
一行依赖三步搞定:cjpm集成metaphone4cj语音算法完整指南

一行依赖三步搞定:cjpm集成metaphone4cj语音算法完整指南 【免费下载链接】metaphone4cj 语音算法,支持将一个特定的字符串(通常是一个英文单词),将其转化为一个代码,然后可以将其与其他代码(或… · 2026/9/24 13:56:16

Perfetto TraceProcessor 性能分析排查:从首次运行到离线部署的完整指南
Perfetto TraceProcessor 性能分析排查:从首次运行到离线部署的完整指南

Perfetto TraceProcessor 性能分析排查:从首次运行到离线部署的完整指南 【免费下载链接】perfetto Production-grade client-side tracing, profiling, and analysis for complex software systems. 项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto … · 2026/9/24 13:56:16

Yii 2 应用结构全景解析:从入口脚本到 MVC 组件的完整架构指南
Yii 2 应用结构全景解析:从入口脚本到 MVC 组件的完整架构指南

后端Web框架 【免费下载链接】yii2 Yii 2: The Fast, Secure and Professional PHP Framework 项目地址: https://gitcode.com/gh_mirrors/yi/yii2 点击查看 免费下载 Yii 2 框架基于经典的模型-视图-控制器(MVC)架构模式组织应用&#xff0… · 2026/9/24 13:56:16

Flink CDC 安装指南:三步部署加一份最小 YAML,把实时数据同步真正跑起来
Flink CDC 安装指南:三步部署加一份最小 YAML,把实时数据同步真正跑起来

Flink CDC 安装指南:三步部署加一份最小 YAML,把实时数据同步真正跑起来 【免费下载链接】flink-cdc Flink CDC is a streaming data integration tool 项目地址: https://gitcode.com/GitHub_Trending/flin/flink-cdc 数据库一有变更&#xff0c… · 2026/9/24 16:31:10

opencodex 多智能体兼容修复:PR 93/94 Cherry-pick 实战 —— agent_message 边界保持与加密槽位 sanitize 归一化
opencodex 多智能体兼容修复:PR 93/94 Cherry-pick 实战 —— agent_message 边界保持与加密槽位 sanitize 归一化

【免费下载链接】opencodex Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code 项目地址: https://gitcode.com/gh_mirrors/ope/opencodex 点击… · 2026/9/24 16:31:10

Ai Agent 执行链路设计:基于规则树将 AutoAgentTest 落地为可编排节点
Ai Agent 执行链路设计:基于规则树将 AutoAgentTest 落地为可编排节点

Ai Agent 执行链路设计:基于规则树将 AutoAgentTest 落地为可编排节点 【免费下载链接】CodeGuide :books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Jav… · 2026/9/24 16:30:57

PiKVM EDID 标识修改实战:用 kvmd-edidconf 查看、改写与采纳显示器标识
PiKVM EDID 标识修改实战:用 kvmd-edidconf 查看、改写与采纳显示器标识

文档教程 【免费下载链接】pikvm Open and inexpensive DIY IP-KVM based on Raspberry Pi 项目地址: https://gitcode.com/gh_mirrors/pi/pikvm 点击查看 免费下载 本篇指南围绕 PiKVM 官方 EDID 配置工具 kvmd-edidconf 展开,讲解如何在 PiKVM&#x… · 2026/9/24 16:30:50

Feynman 文献综述工作流 `/lit` 全解析:从工具纪律到出版物语料模式与出处追踪
Feynman 文献综述工作流 `/lit` 全解析:从工具纪律到出版物语料模式与出处追踪

【免费下载链接】feynman The open source AI research agent. 项目地址: https://gitcode.com/gh_mirrors/feynman/feynman 点击查看 免费下载 Feynman 是开源的 AI 科研代理(open source AI research agent),其内置的 /lit 工作… · 2026/9/24 16:30:50

Orleans 生产故障排查指南:八类高发事故的 Runbook 实战与源码级信号解析
Orleans 生产故障排查指南:八类高发事故的 Runbook 实战与源码级信号解析

后端微服务 【免费下载链接】orleans Cloud Native application framework for .NET 项目地址: https://gitcode.com/gh_mirrors/or/orleans 点击查看 免费下载 本指南是 Orleans 集群运维的事故处置手册(Runbook),覆盖客户端无法… · 2026/9/24 16:30:50

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码