【Android JNI 开发入门指南】

Android JNI 入门(含完整Demo) //自动检测 MainActivity 生成宏 #define com_example_jni_MainActivity_A 234L //函数的声明 extern “C” JNIEXPORT jstring JNICALL Java_com_example_jni_MainActivity_getString (JNIEnv *, jobject); #ifdef __cplusplus//如果是 C++ 什么事情都不干 } #endif #endif 这里注释添加的非常清楚,就不在啰嗦了,如若不懂,评论 阅读详情
AI摘要

本文详细介绍Java Native Interface (JNI) 的概念、用途及开发流程,包括如何使用NDK进行交叉编译,实现Java与C/C++代码的交互,以及常见错误解决方法。

Android JNI 开发入门指南

1. 【JNI介绍】

  • What (是什么): JNI (JAVA Native Interface)java本地接口。

    • 通过JNI可以实现Java和本地代码(C/C++)之间相互调用。

    • JNI可以看做是翻译官,实际上就是一套协议。

    • 因此类似于AIDL(安卓接口定义语言),aidl是用于进程间通信的一套协议(接口)。

  • Why (为什么要用):

    • 由于java的跨平台能力,导致了一些弊端,运行在虚拟机上,无法真正直接的操作系统硬件。

    • JNI则可以扩展JAVA的能力,让java也能通过它来操作硬件驱动。(智能家居,物联网…)

    • java是解释型语言,运行效率相对较低,而C/C++的效率要高很多,通过JNI可以把耗时操作放在C/C++中实现可以提高Java程序的运行效率。

    • java代码编译的字节码文件安全性较差, 可以通过jni 把重要的敏感的业务逻辑放到c/c++去实现,由于c/c++反编译比较困难,因此安全性较高。

    • 代码移植,复用已经存在的c代码(opencv,ffmpeg…)

    • C历史悠久,通过JNI可以调用优秀的C开源类库。

  • How (怎么用):

    • 熟练Java
    • C/C++ 能看懂 会调用。
    • JNI开发流程 NDK native develop kit

2. 【NDK(JNI)开发介绍】

  1. [交叉编译]

    • 在一个平台上去编译另一个平台上可以执行的本地代码。

    • 交叉编译的实现原理: 模拟不同平台的特性去编译代码。

    • Android系统运行的 CPU 架构 :ARM,X86,mips

  2. [NDK (native Develop Kit),谷歌提供的: 用作JNI开发的交叉编译工具集。]

    △安装介绍;如果电脑与JDK都是32位的则选择 android-ndk-r9d-windows-x86 的开发工具包。

     					   64为的则选择 android-ndk-r9d-windows-x86_64 的开发工具包。
    

    △使用介绍:解压就能用

    △NDK解压后的:常用目录,文件介绍:

     * docs: 帮助文档
    
     * platforms : 平台版本文件夹,使用时选择项目支持的最小版本号所对应的文件夹,每一个版本号的文件夹中包含了不同cpu架构的资源文件
    
     		[例如]:我的安卓项目设置的最低支持SDK版本为 api-14,则应该选择使用: platforms/android-14下的头文件,与.so文件。
    
     * include : 存储jni开发中常用的 .h头文件
     * lib : 	 google打包好的 提供给开发者使用的:.so文件,.o文件。
     * samples : google官方提供的样例工程 可以参考进行开发
     * android-ndk-r9d\build\tools : linux系统下的批处理文件 在交叉编译时会自动调用
    
     * ndk-build.cmd :交叉编译的命令。(执行它就可以吧c代表编译成安卓应用可以支持的 .so文件)
     * cdt :      eclipse的插件 高亮C代码 C的代码提示。(一般在eclipse中会自带此插件)
    
  3. 【[JNI-Hello World】

    △需求:在Android程序中点击一个Button,实现调用C语言的一个函数,该函数返回一个字符串(Hello World)!

    △核心原理:在java中声明一个native方法,然后在C语言代码中实现这个native方法,然后在java代码中调用这个方法。

    ☆实现步骤: —可以参考:android-ndk-r9d-windows-x86.zip\android-ndk-r9d\samples\hello-jni 这个示例工程。

    • 简要步骤如下:

      1. 创建一个android工程
      2. java代码中写声明native方法
      3. 创建jni目录,编写c代码,方法名字要对应(有一定的命名格式)。
      4. 编写Android.mk文件,如果需要还需Application.mk
      5. NDK编译生成动态链接库
      6. java代码load动态库.调用native代码
    • [详细步骤如下]:

      • [1]:首先写java代码, 声明本地方法 用到native关键字 本地方法不用去实现。

          例:
          	/**
          	 *1. 声明一个java本地方法,利用native关键字,不需要方法体。
          	 */
          	public native String sayHelloFromC();	
        
      • 2:然后在安卓项目根目录下创建jni文件夹, 在jni文件夹下创建 hello.c文件。需要包含进两个头文件:include<stdio.h> 与 include<jni.h>

        △在hello.c中:创建本地函数,本地函数命名规则为: Java_包名_类名_本地方法名

        △按照JNI本地函数命名规则,定义我们自己需要的函数。函数的返回值类型可以参照JNI协议。


        在jni.h头文件中:
        typedef const struct JniNativeInterface* JNIENV ;//因此JNIENV 类型,实际上就是JniNativeInterface这个结构体的指针的别名。

        • 因此JNIEnv 是JniNativeInterface这个结构体的一级指针

        • 参数:JNIENV* env 就是结构体JniNativeInterface这个结构体的二级指针(因为它接收的就是一级指针的地址)

        • JniNativeInterface 这个结构体定义了大量的函数指针,因此就可以通过结构体指针来访问结构体中定义的函数指针所指向的函数了。

        • (env)-> 即可调用结构体中的函数指针。(因为env为二级指针,因此需要加,取出一级指针,然后对一级指针使用 -> )

        • 第二个参数jobject thiz: 调用本地函数的java对象就是这个jobject,在本例中也就是MainActivity.this

        △:注意:我们调用的所有的JNI本地代码函数,都需要带这两个参数。

          例:hello.c 如下:
        
          	#include<stdio.h>
          	#include<jni.h>
        
          	//由于程序的入口是MainActivity,因此无需再此处创建 main()函数
        
          	/**
          	 * 添加一个C语言本地函数:命名规则为: Java_包名_类名_本地方法名 。(本地方法名就是调用这个c函数的java native 方法名)
          	 */
          	jstring Java_com_hzy_jnihelloworld_MainActivity_sayHelloFromC(JNIEnv* env,jobject thiz){
          		//定义一个C语言的字符串
          		char* hello_str = "helloWorld!";
          		//通过:结构体(JniNativeInterface)的二级指针 env 调用结构体中声明的函数指针所对应的函数
          																		(jstring  NewStringUTF(JNIEnv*, const char*);)
          		return (*env)->NewStringUTF(env,hello_str);
          	}
        
      • [3]:在项目的 jni目录下 创建Android.mk (makefile) 告诉编译器.c的源文件在什么地方,要生成的编译对象的名字是什么

         例:Android.mk 如下:
        
         		LOCAL_PATH := $(call my-dir)
        
         	    include $(CLEAR_VARS)
        
         	   	LOCAL_MODULE    := hello   #指定了生成的动态链接库的名字
         	   	LOCAL_SRC_FILES := hello.c #指定了C的源文件叫什么名字
        
         	    include $(BUILD_SHARED_LIBRARY)
        
      • 4:用cmd进入项目的根目录,然后调用命令 ndk-build 编译c代码,编译成功生成的动态链接库.so文件,
        该文件的位置 lib->armeabi->libhello.so 。(右键项目–>refresh即可看到该文件出现。)

        注意:命令使用前需要将 ndk 解压后的目录,添加到系统的path环境变量中。

           如果运行的设备平台为x86,则需新建一个 Application.mk文件,在里面进行配置,实现让ndk编译出多个平台的so文件。--提高兼容性
        
      • [5]:在java代码中加载动态链接库 System.loadlibrary(“动态链接库的名字”); 也就是 jni/Android.mk 中 LOCAL_MODULE所指定的名字。

         //使用前需要加载编译成功后生成的,动态链接库文件
         	static{
         		System.loadLibrary("hello");
         	}
        
      •  例:
         	//调用本地方法
         	String result = sayHelloFromC(); //实际上会调用 .so文件中所定义的对应的本地代码函数。
         	Toast.makeText(getApplicationContext(), result, 0).show();		
        

3. 【jni开发中的常见错误 】

  • △ [java.lang.UnsatisfiedLinkError: Native method not found: 本地方法没有找到 ]

    • 本地函数名写错
    • 忘记加载.so文件 没有调用System.loadlibrary(); //一般在静态代码块中加载
  • △[findLibrary returned null ]

    • System.loadLibrary(“hello”); //注意:加载动态链接库时,name为 :jni/Android.mk 中 LOCAL_MODULE所指定的名字。

    • 平台类型错误:例如:把只支持arm平台的.so文件部署到了 x86cpu的设备上。 —因为默认情况下会生成arm平台的so文件。

      解决方案:

        * 在jni目录下创建 Application.mk 文件,并在里面指定: 
      
        	  APP_ABI := x86 			#则只支持x86平台
        	  APP_ABI := armeabi x86   #则只支持arm平台与x86平台
        	  APP_ABI := all 		  #全部支持
      
          	  APP_PLATFORM := android-14  #此处配置成自己项目所支持的最低的AndroidSDK版本,交叉编译时就不会 Warning!
      
          完成配置后,cmd进入项目根目录,然后ndk-build重新编译。即可!	  
      
  • △[用javah 命令:来生成头文件,解决自己写本地代码函数时,函数名格式写错的问题。]

    • 如果是jdk 1.7以上,则到项目 src目录下运行 javah命令

    • 如果是jdk 1.6,则到项目的bin目录下 classes文件夹下运行 javah命令

    • 写法:javah (native方法声明的java类的全类名)

      例:首先在mainActivity中编写一个native方法:public native String sayHelloFromC(); //native方法的方法体位于本地代码中

        然后到cmd中找到项目的...\src> javah com.hzy.jnihelloworld.MainActivity,
      
        	就会将该类中所有的 native方法,生成对应的本地代码函数到头文件中。
      
        刷新项目即可看到:src/com_hzy_jnihelloworld_MainActivity.h 
      
        	:方法名就生成成功了。
      
        		/*
        		 * Class:     com_hzy_jnihelloworld_MainActivity
        		 * Method:    sayHelloFromC
        		 * Signature: ()Ljava/lang/String;
        		 */
        		JNIEXPORT jstring JNICALL Java_com_hzy_jnihelloworld_MainActivity_sayHelloFromC(JNIEnv *, jobject);
      
  • △:解决CDT插件报错的问题(在.c文件中使用 JNIEnv, jstring这些关键字时,发现报错!)

    右键单击项目选择 properties :

    选中:c/c++ general->paths and symbols->include选项卡下->点击add…->file system
    选择ndk目录下 的platforms文件夹 对应平台下(项目支持的最小版本)usr 目录下 arch-arm -> include
    (apply)确定后 会解决代码提示和报错的问题。

4. 【JNI简便开发流程】

  • 前言:一个标准的JNI程序开发步骤就如上文所示,但是过于繁琐,因此安卓也提供了简便的开发流程。

  • [实现步骤]:

    • [1]:【首先编写java代码, 用native 声明本地方法。】

    • 2:【添加本地支持 右键单击项目->andorid tools->add native surport,然后指定生成的so文件的名字即可。】

        * 如果发现 finish不能点击,则需要给工作空间指定 ndk目录的位置(工具包解压后的存放位置)。
      
        * 进入:window->preferences->左侧选择android->ndk ,然后把ndk解压后的存放目录指定进来即可。
      
          △如果发现自己的eclipse中没有andorid tools->add native surport,这个选项则代表自己的ADT版本问题,
      
          		此时可以将一个ndk插件安装到eclipse中,重启eclipse就会发现有 andorid tools->add native surport这个选项了。
        	
        			例:com.android.ide.eclipse.ndk_23.0.2.1259578.jar,放置到eclipse的plugins目录中即可。
      

      △使用这种方式就无需手动创建 jni文

简述JNI开发 JNI全称为Java Native Interface,主要用于实现Java和C/C++的通信。 阅读详情

相关推荐

Android使用android studio配置并运行Jni详细流程

以手动不使用cmake方式,配置并运行jni项目的详细流程。结构清晰,按照步骤做,一定能够成功运行,一起来试试吧

yxw331291779的博客 7289

安卓NDK开发入门:从JNI原理到实战性能优化指南

在移动应用开发中,性能优化和硬件能力调用是核心技术挑战。通过原生开发技术,开发者可以突破高级语言虚拟机的限制,直接操作内存和CPU指令,实现极致性能。其核心原理在于建立Java/Kotlin与C/C++代码之间的高效通信桥梁,这通常通过JNI(Java Native Interface)实现。这项技术的核心价值在于处理计算密集型任务,如图像处理、音视频编解码和物理模拟,并能复用大量成熟的C/C++生态库。在安卓平台上,NDK(Native Development Kit)提供了完整的工具链来实现这一过程,涉

chubaisheng8627的博客 379

Android Studio JNI开发指南:从入门到精通!

JNI(Java Native Interface)是一种用于在Java和本地代码之间进行交互的技术。它为开发人员提供了使用C/C++编写高性能本地代码的能力,并将其与Java代码无缝集成。本文将介绍如何在Android Studio中进行JNI开发,帮助您快速入门并逐步精通这一技术。

CodeJolt的博客 448

Android Studio NDK 开发指南:JNI 入门教程

通过以上步骤,我们成功地创建了一个简单的 Android Studio NDK 项目,并实现了 JNI 的入门示例。在本篇文章中,我们将介绍如何使用 Android Studio 进行 NDK 开发,并通过一个简单的示例来演示 JNI 的基本用法。我们可以尝试编译和运行项目,查看我们的 JNI 函数是否能够正常工作并将字符串显示在 UI 上。文件,我们需要在该文件中调用刚刚编写的 JNI 函数,并将其返回值显示在 UI 上。文件,我们可以开始编写我们的 JNI 函数。加载了我们在 JNI 中定义的库。

PixelDude的博客 281

Android JNI开发入门实战指南

JNI(Java Native Interface)是Java平台提供的一种标准接口,允许Java代码与C/C++等本地语言进行高效交互。在Android开发中,JNI不仅为计算密集型任务(如音视频编解码、图像处理)提供了性能优化路径,还支持复用成熟的原生库(如FFmpeg、OpenCV),并可直接访问系统底层资源或硬件接口。其核心机制基于JNIEnv指针和jobject实例,实现跨语言函数调用与数据传递。通过。

weixin_35748962的博客 1035

Android Studio中NDK与JNI开发入门指南

Java Native Interface (JNI) 是一个编程框架,允许Java代码和其他语言写的代码(主要是C和C++)进行交互。其定义了一个标准的编程接口,使得Java虚拟机(JVM)中的Java代码能够调用本地应用程序接口(API)中的本地方法(用C、C++或其他语言实现的方法),以及反过来实现本地方法调用Java对象和其方法。JNI不仅提供了一种机制来调用本地方法,同时也需要一种方式来处理不同数据类型之间的转换。

weixin_32099703的博客 1310

半导体工厂自动化实战:用secs4net实现设备与MES系统通信(附完整代码)

本文详细介绍了如何利用secs4net框架实现半导体工厂设备与MES系统的高效通信。通过解析SECS/GEM协议的核心架构、关键业务场景实现及性能优化实践,帮助开发者快速掌握工业自动化通信技术,提升生产效率和系统稳定性。

transformer2023的博客 892

Halcon 3D点云处理实战:从PLY文件读取到曲面匹配的完整流程(附避坑指南)

本文详细介绍了Halcon在3D点云处理中的完整流程,从PLY文件读取到曲面匹配,特别强调了3D算子的应用技巧和避坑指南。通过实战案例和参数优化建议,帮助开发者高效处理工业视觉检测中的复杂点云数据,提升匹配精度和性能。

weixin_42535720的博客 278

Tessy单元测试软件安装与破解避坑指南(附个人使用路径设置详解)

本文详细介绍了Tessy单元测试软件的安装与配置全流程,包括系统需求、服务器连接设置、环境变量配置等关键步骤,帮助开发者避开常见陷阱。特别提供了个人使用路径设置详解,确保Tessy在嵌入式开发环境中高效运行,适用于汽车电子、工业控制等领域。

weixin_33709364的博客 344

大语言模型在建筑规范自动化合规审查中的微调策略与规模效应实践

大语言模型(LLM)通过在海量文本数据上预训练,具备了强大的语言理解和生成能力。其核心原理是基于Transformer架构,通过自注意力机制捕捉长距离依赖关系。在工程实践中,为了将这种通用能力适配到建筑、法律、金融等高度专业化的垂直领域,通常需要采用领域微调技术。微调通过使用特定领域的高质量指令数据对模型参数进行更新,使其掌握专业术语、逻辑规则和任务范式,从而解决通用模型在专业场景下知识匮乏和“幻觉”问题。结合检索增强生成(RAG)技术,将动态外部知识库作为模型的“参考手册”,能进一步提升事实准确性并降低幻

weixin_30667831的博客 362

多跳问答技术解析:从原理到金融领域实践

多跳问答(Multi-hop QA)是自然语言处理中的高级任务,要求系统通过多步推理整合分散信息来回答问题。其核心技术在于理解文档间的复杂关联,相比单跳问答需要更精细的数据集设计和模型架构。在金融、医疗等专业领域,多跳问答能有效处理如'腾讯大股东投资的港股上市公司'这类需要串联多个信息点的问题。典型实现方案包括MR-Search框架的三级检索器设计,分别处理实体召回、关系匹配和数值比较。当前最佳实践表明,结合稠密检索与稀疏检索的混合策略,配合动态路由机制,能在保持较高精度的同时控制计算成本。这类技术在金融风

weixin_42566072的博客 606

华为OD机试真题 新系统2026-04-08 Python&JS 实现【配置操作失败数量统计】

模拟一个系统的命令行配置,包含添加、修改、删除三项操作,详情如下: 添加操作命令:add_rulerule_id=1rule_index = 18 修改操作命令: mod_rule rule_id= 1rule_index = 100 删除操作命令:del_rulerule_id=1

MISAYAONE的博客 586

全栈拆解华为乾崑 ADS 5:WEWA2.0智能体架构与安全风险场技术、实现多传感器全融合感知与主动安全预判、助力城市NOA/高速领航/全场景无人通行极致落地

华为乾崑ADS 5的核心颠覆性,不在于单一功能的小幅升级,而在于实现了自动驾驶从“工具式辅助驾驶”到“拟人化智能体驾驶”的全栈范式革命。通过WEWA 2.0端云协同AI智能体架构,解决了传统智驾决策僵硬、博弈能力弱、学习效率低的行业痛点;通过行业首发安全风险场技术,将自动驾驶安全体系从被动避险升级为主动预判,直接减半行车风险;通过乾崑OS专属车规系统底座,保障高阶智驾的低时延、高稳定、高可靠运行;通过多传感器超融合感知体系,实现全场景、全天候、无盲区的精细化环境理解。

getusushu的博客 289

【FDTD】仿真目录(共计 16 篇)

对于完美吸收型边界条件,有时候我们需要设置将仿真结构穿过边界条件区域,具体原因可以阅读下文。在进行 S 参数扫描时,当考虑到材料的色散特性时,我们可以如下文一样选择计算群延迟。仿真,我们需要构建仿真结构与仿真区域,对于它们的尺寸,应该遵循下文进行设定。中存在多种不同的网格类型,具体可以参考下文,这部分内容仅作了解即可。尺寸的设置问题,对于 mesh 的最小尺寸,可以参考下文。的边界条件设置也十分重要,下文中我们对边界条件进行总结。仿真中我们可以设定参与仿真的模式数量,可以参考下文。尺寸的实例,详见下文。

u011699626的博客 504

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

上一篇: 【方法数超过64k限制时-如何配置多Dex打包?】
下一篇: 大Bitmap导致Android-java.lang.OutOfMemoryError
大雪冬至
博客等级 码龄7年 299粉丝 65原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值