【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

华为2288H V5服务器断电后‘趴窝’?别慌,手把手教你用SmartKit+BMC修复工具搞定

本文详细介绍了华为2288H V5服务器在断电后无法启动的修复方法,通过SmartKit和BMC修复工具进行故障诊断与修复。文章提供了从工具获取、安装到具体修复流程的完整指南,帮助运维人员快速恢复服务器运行,并给出了后续加固与预防措施,确保服务器稳定运行。

weixin_30575517的博客 297

微信小程序PC端兼容性实战:如何绕过限制在电脑上运行手机端小程序

本文详细解析了微信小程序在PC端的兼容性问题及解决方案,重点介绍了如何利用`wx.getSystemInfo`API检测运行环境,并通过修改User-Agent、动态环境检测与适配等技术手段实现手机端小程序在PC端的顺畅运行。文章还提供了常见兼容性问题的解决方法和调试工具推荐,帮助开发者高效应对多端适配挑战。

weixin_28366053的博客 867

正直摄影方式的精度估算式_利用BDS数据反演大气可降水量及其精度分析

可降水量(PWV)对中小尺度灾害性天气预报具有指示意义,是降雨强度预报的重要参数之一。自20世纪80、90年代起,国外已经对GPS探测大气可降水量进行了大量研究。国内最早由毛节泰引进并详细介绍了地基GPS反演大气可降水量的方法,近年来发展迅速并取得了一定的成果。随着中国北斗卫星导航系统(BDS)提供服务并不断地建设完善,其已经能够应用到气象学领域,可以获得大气可降水量。文献[11]利用...

weixin_39796752的博客 1246

Python+OpenCV实现游戏自动刷怪脚本(附完整代码)

本文详细介绍了如何使用Python和OpenCV开发游戏自动刷怪脚本,涵盖环境搭建、图像识别、行为决策引擎及反检测优化等关键技术。通过完整的代码示例,帮助开发者实现从简单脚本到智能自动化系统的升级,提升游戏效率。

weixin_29032489的博客 520

fMRI数据处理:从DICOM到NIFTI(上)

哈喽,这里是系列fMRI数据处理文章专栏。包括从核磁拷贝完DICOM格式的文件,到整理数据,检查数据,数据预处理,后续分析等等内容。如果你是一个初学者,特别是心理学或者是刚踏入认知神经科学的小白,那么这个专栏可以帮助你从头到尾完成数据处理直到结果的可视化。如果你已经进入了认知神经科学领域,这里面的内容可能过于细致,并且找不到你想要的答案,不过可以在帖子下留言评论,欢迎大家提供宝贵的意见!如果是医学相关,可能这些内不太准确或专业,谨慎参考!

weixin_44933894的博客 2482

webpack性能优化-optimization.splitChunks.chunks中的“all“、“async“和“initial“

最初,chunks(以及内部导入的模块)是通过内部 webpack 图谱中的父子关系关联的。CommonsChunkPlugin 曾被用来避免他们之间的重复依赖,但是不可能再做进一步的优化。 ——摘自 webpack 从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks。 而关于 optimization.splitChunks 中的chunks,webpack 官方文档却没有很好的进行举例解释,只说明了 async.

程序员秋风的博客 3137

实验十一 ——————二层交换基础

实验内容实验网络拓扑图如上所示SW1以及SW2都创建VLAN10和VLAN20,按照上图所示,将接口添加到特定的VLAN;测试PC之间的连通性,要求相同VLAN内的PC能够相互通信要求设置两台交换机名称以及进行特权模式的密码,并允许通过Telnet方式管理交换机实验目的了解二层交换机工作原理掌握交换机基本配置命令理解VLAN的概念,掌握VLAN的配置理解trunk的概念,掌握trunk的配置实验步...

Fly_鹏程万里 1489

(数字图像处理MATLAB+Python)第五章图像增强-第一节:图像增强概述和基于灰度级变换的图像增强

图像增强(Image Enhancement):指不考虑图像降质原因,利用各种数学方法和变换手段,增强图像中人们感兴趣部分或提高有用的图像特征的清晰度。从图像质量来看,图像增强提高了图像的可懂度,改善了图像的视觉效果例如在现实场景中,针对那些对比度较差、视觉效果不好的图像,我们就可以利用图像增强改善视觉质量图像增强可分为如下几种基于灰度级变换的图像增强基于直方图修正的图像增强基于照度反射模型的图像增强基于模糊技术的图像增强基于伪彩色处理的图像增强其他图像增强方法分段线性灰度级变换。

快乐江湖的博客 3334

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

ssm框架搭建

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

上一篇: 【方法数超过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、付费专栏及课程。

余额充值