Android高级开发第一篇 - JNI(初级入门篇)

news2025/6/2 15:45:50

文章目录

  • Android高级开发JNI开发第一篇(初级入门篇)
    • 🧠 一、什么是 JNI?
      • ✅ 为什么要用 JNI?
    • ⚙️ 二、开发环境准备
      • 开发工具
    • 🚀 三、创建一个支持 JNI 的 Android 项目
      • 第一步:创建新项目
      • 项目结构示例
    • 🧪 四、第一个 JNI 示例:Hello from C++
      • 🧩 Java 代码(MainActivity.java)
    • 五、配置 CMake 构建脚本
    • 六、JNI 名称规则总结
    • 七、常见问题排查
    • 参考资源

Android高级开发JNI开发第一篇(初级入门篇)

👨‍💻 本文作者:一位正在攻克底层开发的 Android 工程师
🧭 目标读者:有 Java/Android 基础,希望入门 JNI 开发的新手
📌 本文特点:从零开始,手把手实战,代码详细注释,适合 CSDN 初学者收藏


🧠 一、什么是 JNI?

JNI(Java Native Interface) 是 Java 提供的一种机制,它允许 Java 代码与使用 C 或 C++ 编写的本地代码进行交互。

简单说,JNI 是 Java 和原生代码之间的“翻译官”。

✅ 为什么要用 JNI?

使用场景示例
调用高性能库OpenCV、FFmpeg
调用底层系统接口系统级音视频处理、传感器操作
提升性能密集计算场景用 C/C++
兼容老旧库有些厂商 SDK 只提供 .so 文件

⚙️ 二、开发环境准备

开发工具

  • ✅ Android Studio(建议 4.0+)
  • ✅ 已配置好 SDK 和 NDK(NDK 安装可通过 SDK Manager 添加)
  • ✅ 熟悉 Java 基础语法

🚀 三、创建一个支持 JNI 的 Android 项目

第一步:创建新项目

  1. 打开 Android Studio,点击 File > New Project
  2. 选择模板:Native C++
  3. 输入项目名,比如:JniHello
  4. 语言选 Java,C++ 标准选 C++11
  5. 完成后你会获得一个默认支持 JNI 的项目结构

项目结构示例

app/
├── src/main/java/com/example/jni/MainActivity.java
├── src/main/cpp/native-lib.cpp
├── CMakeLists.txt


🧪 四、第一个 JNI 示例:Hello from C++

系统自动生成了第一个 JNI 示例,我们来逐步分析它。

🧩 Java 代码(MainActivity.java)

public class MainActivity extends AppCompatActivity {

    // 加载本地库
    static {
        System.loadLibrary("native-lib");
    }

    // 声明 native 方法
    public native String stringFromJNI();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI()); // 调用 native 方法
    }
}

🧩 C++ 代码(native-lib.cpp)

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_jni_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

🔍 分析解释:
extern “C”:关闭 C++ 的名称重整(name mangling)

JNIEXPORT/JNICALL:JNI 的标准函数导出宏

Java_全限定类名_方法名:这个函数名必须完全匹配 Java 中声明的 native 方法

JNIEnv* env:提供访问 Java 方法、类、对象的能力

NewStringUTF:创建一个 Java 的 String 返回给 Java 层
默认生成的 CMakeLists.txt 一般如下:

五、配置 CMake 构建脚本

cmake_minimum_required(VERSION 3.4.1)

add_library(
        native-lib
        SHARED
        native-lib.cpp )

find_library(
        log-lib
        log )

target_link_libraries(
        native-lib
        ${log-lib} )

确保你的 app目录下的 build.gradle 中已启用 externalNativeBuild:

externalNativeBuild {
    cmake {
        path "src/main/cpp/CMakeLists.txt"
    }
}

最后会输出为
Hello from C++

✅ 说明你的 Java 成功调用了 C++ 函数,JNI 配置无误!

六、JNI 名称规则总结

Java 代码 native 函数名
com.example.jni.MainActivity.stringFromJNI() Java_com_example_jni_MainActivity_stringFromJNI

📌 小贴士:包名中的 . 替换为 _,类名与方法名直接拼接。

七、常见问题排查

问题 原因 解决方案
Java 找不到 native 方法 函数名写错或拼写不一致 检查方法命名和包名是否完全匹配
native 方法未加载 没有调用 System.loadLibrary() 加上正确的库名加载语句
编译报错:找不到头文件 NDK 未正确配置 检查 NDK 安装路径或重装

🧱 下一篇预告:第二篇 - JNI 参数传递与 Java → C → Java 双向调用
敬请期待!

参考资源

  • Android NDK 官方文档
  • JNI 规范
  • Android JNI 提示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2394317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【基础算法】高精度(加、减、乘、除)

文章目录 什么是高精度1. 高精度加法解题思路代码实现 2. 高精度减法解题思路代码实现 3. 高精度乘法解题思路代码实现 4. 高精度除法 (高精度 / 低精度)解题思路代码实现 什么是高精度 我们平时使用加减乘除的时候都是直接使用 - * / 这些符号&#xff0c;前提是进行运算的数…

Windows最快速打开各项系统设置大全

目录 一、应用背景 二、设置项打开方法 2.1 方法一界面查找&#xff08;最慢&#xff09; 2.2 方法二cmd命令&#xff08;慢&#xff09; 2.3 方法三快捷键&#xff08;快&#xff09; 2.4 方法四搜索栏&#xff08;快&#xff09; 2.5 方法五任务栏&#xff08;最快&am…

嵌入式编译工具链熟悉与游戏移植

在自己的虚拟机Ubuntu系统下&#xff0c;逐步编译 mininim源码(波斯王子重制开源版&#xff09; 指令流程 sudo apt-get remove liballegro5-dev liballegro-image5-dev \liballegro-audio5-dev liballegro-acodec5-dev liballegro-dialog5-dev sudo apt-get install automak…

DeepSeek-R1-0528,官方的端午节特别献礼

DeepSeek&#xff1a;端午安康&#xff01;刻在国人骨子里的浪漫 2025 年 05 月 28 日 | DeepSeek 端午特别献礼 当粽叶飘香时&#xff0c;DeepSeek 悄然带来一份节日惊喜 版本号 DeepSeek-R1-0528 正式上线 官方赋予它的灵魂是&#xff1a; 思考更深 推理更强 用户通过官网…

001 flutter学习的注意事项及前期准备

在学习flutter之前&#xff0c;还需要进行一些初始的配置&#xff0c;然后才可以学习flutter 1.安装flutter 国内官网&#xff1a;https://flutter.cn​​​​​​ 国际官网&#xff1a;https://flutter.dev 安装完成后&#xff0c;按照官网上面的操作步骤进行配置&#xf…

CS144 - Lecture 1 记录

CS144 - Lecture 1 由于没讲义&#xff0c;全看课了&#xff0c;系统性的总结有点难&#xff0c;记一些有趣的东西吧。 数据链路和网络层的传输 我们可以看见&#xff0c;对于发送方&#xff0c;我们的数据链路层为我们的网络层提供服务&#xff0c;在经过路由的时候&#xf…

【数据结构】——二叉树--链式结构

一、实现链式结构二叉树 二叉树的链式结构&#xff0c;那么从名字上我们就知道我们这个二叉树的底层是使用链表来实现的&#xff0c;前面我们的二叉树是通过数组来实现的&#xff0c;那么在其是完全二叉树的情况下&#xff0c;此时我们使用数组来实现就会使得其空间浪费较少&a…

充电便捷,新能源汽车移动充电服务如何预约充电

随着新能源汽车的普及&#xff0c;充电便捷性成为影响用户体验的关键因素之一。传统的固定充电桩受限于地理位置和数量&#xff0c;难以完全满足用户需求&#xff0c;而移动充电服务的出现&#xff0c;为车主提供了更加灵活的补能方式。通过手机APP、小程序或在线平台&#xff…

基于 Chrome 浏览器扩展的Chroma简易图形化界面

简介 ChromaDB Manager 是基于 Chrome 浏览器扩展的一款 ChromaDB&#xff08;一个流行的向量数据库&#xff09;的数据查询工具。提供了一个用户友好的界面&#xff0c;可以直接从浏览器连接到本地 ChromaDB 实例、查看集合信息和分片数据。本工具特别适合开发人员快速查看和…

IM系统的负载均衡

1.IM场景的负载均衡 2.方案总览 SDK层想要连接一个TCP网关或者WebSocket网关的方案 SDK单地址:在SDK中写死某个网关的IP或者域名,缺点是更换地址需要重新打包SDK SDK多地址:防止某一个地址嗝屁了写上多个地址用足保持高可用 暴露接口给客户端:SDK层访问接口动态获得地址 注…

使用 Zabbix 监控 MySQL 存储空间和性能指标的完整实践指南

目录 引言 一、最终目标支持功能 二、监控方案设计 2.1 技术选型 2.2 设计思路 三、实现步骤 3.1 准备工作 3.11 创建 MySQL 监控账号 3.12 配置 .my.cnf 文件 3.2 编写统一脚本 3.3 配置 Zabbix Agent UserParameter 3.4 Zabbix 前端配置建议 四、总结 引言 MySQL …

【技能拾遗】——家庭宽带单线复用布线与配置(移动2025版)

&#x1f4d6; 前言&#xff1a;在家庭网络拓扑中&#xff0c;客厅到弱电箱只预埋了一根网线&#xff0c;由于已将广电的有线电视取消并改用IPTV。现在需要解决在客厅布置路由器和观看IPTV问题&#xff0c;这里就用到单线复用技术。 目录 &#x1f552; 1. 拓扑规划&#x1f55…

异步日志监控:FastAPI与MongoDB的高效整合之道

title: 异步日志监控:FastAPI与MongoDB的高效整合之道 date: 2025/05/27 17:49:39 updated: 2025/05/27 17:49:39 author: cmdragon excerpt: FastAPI与MongoDB整合实现日志监控系统的实战指南。首先配置MongoDB异步连接,定义日志数据模型。核心功能包括日志写入接口、聚合…

在 Android 上备份短信:保护您的对话

尽管我们的Android手机有足够的存储空间来存储无数的短信&#xff0c;但由于设备故障、意外删除或其他意外原因&#xff0c;您可能会丢失重要的对话。幸运的是&#xff0c;我们找到了 5 种有效的 Android SMS 备份解决方案&#xff0c;确保您的数字聊天和信息保持安全且可访问。…

标题:2025海外短剧爆发年:APP+H5双端系统开发,解锁全球流量与变现新大陆

描述&#xff1a; 2025年出海新风口&#xff01;深度解析海外短剧系统开发核心&#xff08;APPH5双端&#xff09;&#xff0c;揭秘高效开发策略与商业化路径&#xff0c;助您抢占万亿美元市场&#xff01; 全球娱乐消费模式正在剧变。2025年&#xff0c;海外短剧市场已从蓝海…

解决RAGFlow(v0.19.0)有部分PDF无法解析成功的问题。

ragflow版本为&#xff1a;v0.19.0 1.解析的时候报错&#xff1a;Internal server error while chunking: Coordinate lower is less than upper。 看报错怀疑是分片的问题&#xff0c;于是把文档的切片方法中的“建议文本块大小”数值&#xff08;默认512&#xff09;调小&…

c#基础08(数组)

文章目录 数组数组概念声明数组初始化数组赋值给数组访问数组元素 集合动态数组(ArrayList)使用foreach循环C#数组细节多维数组传递数组给函数参数数组 数组 数组概念 数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合&#xff0c;通常认为数组是一…

嵌入式学习--江协stm32day3

这是我目前为止认为最重要的模块--TIM定时器&#xff0c;这里我们主要学习通用定时器 最小的计数计时单元为时基单元&#xff0c;包括PSC&#xff0c;ARR&#xff0c;CNT CK_PSC&#xff08;Prescaler&#xff0c;预分频器&#xff09;&#xff1a;作用是对输入时钟信号进行分…

4.8.1 利用Spark SQL实现词频统计

在利用Spark SQL实现词频统计的实战中&#xff0c;首先需要准备单词文件并上传至HDFS。接着&#xff0c;可以通过交互式方法或创建Spark项目来实现词频统计。交互式方法包括读取文本文件生成数据集&#xff0c;扁平化映射得到新数据集&#xff0c;然后将数据集转成数据帧&#…

PyTorch中nn.Module详解

直接print(dir(nn.Module))&#xff0c;得到如下内容&#xff1a; 一、模型结构与参数 parameters() 用途&#xff1a;返回模块的所有可训练参数&#xff08;如权重、偏置&#xff09;。示例&#xff1a;for param in model.parameters():print(param.shape)named_parameters…