JNI
定义 :
Java Native Interface
,即 Java
本地接口
作用:
使得Java 与 本地其他类型语言(如C、C++)交互
注意:
JNI
是Java
调用Native
语言的一种特性JNI
是属于Java
的,与Android
无直接关系
调用实现步骤:
- 在
Java
中声明Native
方法(即需要调用的本地方法) - 编译上述
Java
源文件javac
(得到.class
文件) - 通过
javah
命令导出JNI
的头文件(.h
文件) 使用
Java
需要交互的本地代码 实现在Java
中声明的Native
方法如
Java
需要与C++
交互,那么就用C++
实现Java
的Native
方法编译
.so
库文件- 通过
Java
命令执行Java
程序,最终实现Java
调用本地代码
NDK
定义 :
Native Development Kit
,是 Android
的一个工具开发包
NDK
是属于Android
的,与Java
并无直接关系
作用:
快速开发
C、 C++
的动态库,并自动将so
和应用一起打包成APK
(即可通过NDK
在Android
中 使用JNI
与本地代码(如C、C++
)交互。)NDK
集成了交叉编译器,并提供了相应的mk文件隔离平台、CPU
、API
等差异,开发人员只需要简单修改.mk
文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so
。NDK
提供了一份稳定、功能有限的API
头文件声明。
调用实现步骤:
配置
Android NDK
环境创建
Android
项目,并与NDK
进行关联在
Android
项目中声明所需要调用的Native
方法使用
Android
需要交互的本地代码 实现在Android
中声明的Native
方法 。
比如Android
需要与C++
交互,那么就用C++
实现Java
的Native
方法通过
ndk - bulid
命令编译产生.so
库文件编译
Android
工程,从而实现Android
调用本地代码
Android工程中C/C++代码解析
native-lib.cpp
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring JNICALL
Java_com_kevin_cpp_MainActivity_stringFromJNI(
JNIEnv *env,jobject obj ) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
JNIEXPORT
、NICALL
、JNIEnv
和jobject
都是JNI
标准中所定义的类型或者宏,它们的含义如下:JNIEXPORT
和JNICALL
:他们是JNI
中所定义的宏,可以在jni.h
这个头文件中查询到;JNIEnv*
:表示一个指向JNI环境的指针,可以通过它来访问JNI提供的接口方法。jobject
:表示Java
对象中的this
;
注意:JNI调用C或者C++存在区别:
JNI
是由C
语言定义接口的,JNI
通过函数名找函数入口,执行函数里的内容。这和函数用什么语言生成的并没有关系。只要保证函数名称符合JNI
的协议。而使用C++
要注意的是C++
默认生成的函数名称和你写在源文件中的名称并不相同,因为C++
要处理函数重载,会在函数名称中加上参数信息,这称为name mangling
。
解决方法是定义函数时在前面加上extern"C"
修饰,告诉编译器这函数按照C
语言方式编译和链接。extern"C"
这个声明的真实目的是为了实现C++
与C
及其它语言的混合编程。在
C
的定义中,env
是一个两级指针,而在C++
的定义中,env
是个一级指针
C
形式需要对env
指针进行双重deferencing
,而且须将env
作为第一个参数传给jni
函数。
在C
代码中:JNI
函数调用由“(*env)->”
作前缀,目的是为了取出函数指针所引用的值。
return (*env)->NewStringUTF(env,"HelloJNI!");
在C++
代码中:JNIEnv
类拥有处理函数指针查找的内联成员函数。
return env->NewStringUTF("HelloJNI!");
可以发现,C
或者C++
的实现很类似,但是它们对env
的操作方式不同,因此使用C
和C++
来实现同一个JNI
方法,它们的区别主要集中在对env
的操作上。