Android JNI总结
0x01 JNI介绍
JNI是Java Native Interface的缩写,JNI不是Android专有的东西,它是从Java继承而来,但是在Android中,JNI的作用和重要性大大增强。
JNI在Android中起着连接Java和C/C++层的作用,现在APP的许多重要的逻辑,算法以及和底层的交互功能都是通过JNI调用C/C++来实现。
简单来说,JNI提供了一种可以让Java代码调用C/C++代码的接口。
0x02 JNI中的类型/数据结构
JNI的类型/数据结构,以及函数的声明都放在jni.h的头文件中,这个头文件可以在NDK的platforms文件夹下android对应版本的对应架构文件夹下找到。比如
platforms\android-21\arch-arm64\usr\include\jni.h
一些比较重要的类型如下:
1. 基本类型(都是一些C类型的重命名)
2. 常见的对象类型
jobject 代表Java中的对象
jstring 代表Java中的String类型
jclass 代表Java中的类
jobjectArray/jbooleanArray 等都是数组类型
3. JNIEnv代表JNI环境的结构体
可以看到JNIEnv结构体中有大量函数指针,我们可以通过这个结构体来调用jni.h中声明的函数,之后会有代码来说明这结构体的作用
0x03 Native函数的静态注册与动态注册
前面的数据类型比较无聊,其实我们主要关注的还是Java native函数是怎么和C/C++关联起来的,关联起来后,C/C++函数的编写和正常的C/C++代码基本相同。
Native函数的注册有两种方式:静态注册和动态注册。
关于使用Android Studio编写Native代码的相关配置可以参考:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental
1. 静态注册
静态注册较为简单,所以先来用一个例子来说明一下静态注册。
使用AndroidStdio新建项目,我们把项目命名为HelloNative
在项目中新建一个文件夹jni
在MainActiviy中声明两个native属性函数,第一个函数为static, AS提供alt+enter快捷键可以新建mainactivity并快速生成这两个函数对应的Native层函数框架
1 2 |
|
在MainActivity开始处加载so库
1 2 3 |
|
mainactivity.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
mainactiviy.c中的函数就是我们要编写的native函数
Java_dlive_hellonative_MainActivity_Hello1对应Java中声明的Hello1函数
Java_dlive_hellonative_MainActivity_Hello2对应Java中声明的Hello2函数
这就是静态注册,即Native函数的函数名由Hello1的packagename和Hello1的函数名组成,Java层调用Hello1时,会调用mainactivity.so中对应的
Java_dlive_hellonative_MainActivity_Hello1函数。
这里还有几点要注意:
1. Java层函数对应的Native层函数的第一个参数为JNIEnv*
2. 被声明为static的函数Hello1对应的Native函数
Java_dlive_hellonative_MainActivity_Hello1 第二个参数为jclass,表示Hello1函数所在的类
3. 没有static声明的函数对应的Native函数的第二个参数为jobject,表示调用Hello2的对象
4. Native函数从第三个参数开始才对应Java层函数的参数
2. 动态注册
动态注册与静态注册的区别在于Native的函数名可以自定义,然后使用JNI提供的
RegisterNatives动态将Java层函数和Native层函数绑定起来即可。
动态注册主要依赖两个函数JNI_OnLoad和RegisterNatives
JNI_Onload会在so加载的时候自动被调用,在JNI_Onload中调用RegisterNatives将Java层函数和Native层函数关联起来。
MainActivity.java中native属性的函数:
1 |
|
在jni目录下新建hello.cpp和hello.h,在hello.cpp中实现native函数
1 2 3 4 |
|
可以看到实现的函数名称为helloNative,而不是静态注册时很长的函数名。
1 2 3 4 5 |
|
gClassName : Java层类名
gMethods:{java层函数名,java层函数签名【(参数)返回值】,native层函数指针}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
registerNativeMethods是找了一个网上的实现,就是封装了一下RegisterNatives
1 2 3 4 5 6 7 8 9 10 11 12 |
|
0x04 JNI中提供的函数
JNI中提供了哪些函数可以在jni.h中找到,这里只讲一下常用的几个函数。
讲解顺序是按照jni.h中声明的顺序排序的。
//根据packagename找到并返回java class //比如 jclass stringClass = env -> FindClass("java/lang/String"); //jobjectArray array = env -> NewObjectArray(count, stringClass, NULL); jclass FindClass(const char *name) |
//生成一个Java对象 //clazz为FindClass的返回结果 //methodID指Java类的构造函数ID //调用一个Java对象的方法或者存取一个Java对象的域变量前,要先知道这个方法或域变量的ID //取得方法ID和域ID的函数: //GetMethodID //GetFieldID //例子: //jclass clazz = env->FindClass("android/content/Intent") //jmethodID method = env->GetMethodID(clazz, "<init>", "Ljava/lang/String") //jstring action = env -> NewStringUTF("android.intent.action.MAIN") //jobject intent = env -> NewObject(clazz, method, action) jobject NewObject(jclass clazz, jmethodID methodID, ...) |
//clazz为FindClass返回值 //name为函数名字,如构造函数为 "<init>" //sig为函数签名, 如Content类<init>的签名为,"Ljava/lang/String" (参数) jmethodID GetMethodID(jclass clazz, const char *name, const char *sig) |
//获取字符串内容,对应ReleaseStringUTFChars,该函数返回的指针要使用ReleaseStringUTFChars释放 const char* GetStringUTFChars(jstring str, jboolean *isCopy) |
//创建clazz的对象数组,len为长度,init表示将数组元素初始化为什么一般为NULL //jobjectArray array = env -> NewObjectArray(count, stringClass, NULL);S jobjectArray NewObjectArray(jsize len, jclass clazz, jobject init) |
//获取对象数组里的元素,第二个参数为数组下标 //如果一次只取一个元素,可以使用下面的函数,也不用释放内存,更加方便,参考《深入解析Android5.0系统》 jobject GetObjectArrayElement(jobjectArray array, jsize index) |
//给对象数组元素赋值 // 例: // for(int i=0; i< count; i++) // { // jstring str = env -> NewStringUTF("HELLO"); // if(str == NULL) // { // return NULL; // } // env -> SetObjectArrayElement(array, i, str); // } // return array; void SetObjectArrayElement(jobjectArray array, jsize index,jobject val) |
//返回int数组指针,第二个参数值是否拷贝一份数组出来,数组用完后要使用ReleaseIntArrayElements释放数组内存 jint * GetIntArrayElements(jintArray array, jboolean *isCopy) |
注:本博客文章转载需带上原文链接
Android JNI总结相关推荐
- [转]Android JNI使用方法
本文转自:http://www.open-open.com/lib/view/open1324909652374.html 经过几天的努力终于搞定了android JNI部分,下面将我的这个小程序和大 ...
- Android JNI开发入门之一
JNI在Android系统中有着广泛的应用.Android系统底层都是C/C++实现的,上层提供的API都是Java的,Java通过JNI调用底 层的实现.比如:Android API多媒体接口Med ...
- java jni 数据类型_【Android JNI】Native层解析Java复杂数据类型HashMap
前提 Java HashMap 是基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.HashMap是存放引用类型数据的容器,只能存放引用数据类型,不能存 ...
- Android JNI原理分析
引言:分析Android源码6.0的过程,一定离不开Java与C/C++代码直接的来回跳转,那么就很有必要掌握JNI,这是链接Java层和Native层的桥梁,本文涉及相关源码: frameworks ...
- Android JNI 和 NDK
1.Android NDK 一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第 ...
- Android JNI简单实例(android 调用C/C++代码)
转载自 xiechengfa 最终编辑 xiechengfa Android JNI简单实例关键字: android.jni Android的jni实例 android 的应用程序(Dalvik VM ...
- android jni malloc和free的使用
今天,简单讲讲android在jni如何使用malloc和free进行内存的分配和释放. 这个其实也是C++相关的知识,不过jni需要用到,所以这里记录一下. 一.malloc()和free()的基本 ...
- android jni new/delete 和 new[]/delete[]
今天,简单讲讲android里再jni使用new时如何释放内存. 这个其实是和C++有关的知识,不过jni编程时还是需要注意的.所以这里记录一下. new 和 delete 到底是什么? 如果找工作的 ...
- android jni jstring 转 char*
今天,简单讲讲Android jni如何将java的Sring转成char*. 这个之前一直不理解,所以我都是android传入byte[]转成char*,有一篇博客专门讲了这个.后来发现用Strin ...
- android jni 释放资源
今天,简单讲讲android 如何释放在jni新建得 结构体等资源. 因为android里是自动释放资源的,所以之前没有注意这一点,后来查找资料才发现jni需要自己释放资源.这里记录一下. JNI 编 ...
最新文章
- DevExpress v17.2新版亮点—ASP.NET篇(二)
- 设置linearlayout最大高度_高位消防水箱设置要求及历年真题
- 5月19-20日的上海 来一次纯粹的WebRTC之旅
- Python数据库连接池DBUtils
- java.net.noroute,java.net.NoRouteToHostException: No route to host
- 回溯---含有相同元素求子集
- FFmpeg简介及常见用法
- opengl 光线追踪_Vulkan的视频编解码支持将于2020年上半年加入,光线追踪也在路上...
- [Windows] PPT插件集,部分支持WPS(提高你的制作效率和页面美观)
- 安装duetdisplay遇到的问题
- Logistic模型原理详解以及Python项目实现
- 当面试官问你期望的薪资是多少的时候,他是这样回答的...
- 在树莓派中解决浏览器自动更新失败弹框遮挡数据的方案
- InfoPath2007中添加图片按钮
- 开源网络情报(OSINT)定义:对您的企业意味着什么
- 互联网快讯:百度发布青春版“Wonder”App,;极米2021双十二圆满收官;华为笔记本新品将发布
- Google AppOps
- 阿里巴巴Java开发手册github地址
- Synchronized 同步锁详解
- Yahoo!创始人:杨致远的故事