Android JNI

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是c&c++)

参考http://xdprof.sourceforge.net/doxygen/jni_8h.html

jni.h头文件路径:

  • *\android studio\jre\include
  • *\android studio\sdk\ndk-bundle\sysroot\usr\include

  • Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++编写的函数。
  • Native程序中的函数可以调用Java层的函数,也就是说在C/C++程序中可以调用Java的函数


JAVA只能调用被编译成库的C\C++代码,怎么加载so库?

首先我们要在src/main目录下新建文件夹,把所有的c/c++代码文件放到此目录下

并在CMakeList.txt中配置:把所有的.cpp文件加入到add_library里面

Android提供了3个实用的函数用来加载JNI库,分别是System.loadLibrary(libname),Runtime.getRuntime().loadLibrary(libname),以及Runtime.getRuntime().load(libFilePath)。

用loadLibrary函数加载

用System.loadLibrary(libname)和Runtime.getRuntime().loadLibrary(libname)这两个函数加载so库,不需要指定so库的路径,Android会默认从系统的共享库目录里面去查找,Android的共享库目录就是vendor/lib和system/lib,如果在共享库路径里面找到指定名字的so库,就会立即加载这个so库,所以我们给so库起名的时候要尽量避免和Android共享库里面的so库同名。如果在共享库目录里面查找不到,就会在APP的安装目录里面查找APP的私有so库,如果查找到,会立即加载这个so库。

用load函数加载

Runtime.getRuntime().load(libFilePath)用这个函数加载so库,需要指定完整的so库路径,优点是加载速度快,并且不会加载错误的so库,缺点就是需要指定完整的so库路径,有时候并不方便,大家常用的加载so库的方式还是用loadLibrary函数来加载。

加载so库示例:

native方法,就是在JAVA方法的前面加上native,这种方法是专门给JAVA调用C\C++调用的

本地c/c++代码:

这里的extern “C”的作用是让C++支持调用C语言的方法,如果你不需要,可以去掉;

JNIEXPORT xxx JNICALL代表这是一个JNI方法,其中xxx是返回值类型,如果是空类型,这里就是void;

Java_代表这是一个Java方法;

com_godgou_dlibtoandroid_MainActivity_stringFromJNI这段是你方法所在的包名以及它的方法名,在Java中相当于:com.godgou.dlibtoandroid.MainActivity.stringFromJNI

C语言并没有String型,如果需要使用它,需要借助C++的string工具包,把它转换成字符指针(char*):*. c_str()

返回文本:return env->NewStringUTF(hello.c_str());

C/c++语言调用JAVA代码:

在日常开发中,我们经常会遇到需要把C语言的数据回传给JAVA的情况,分同步和异步调用两种

同步调用:
同一条线程里调用JAVA代码

JAVA:

c/c++:

FindClass的入参是包名+类名的路径;

GetMethodID的入参是JAVA类,方法名,方法签名;

方法签名包含两个部分:

·括号里的内容是回传的数据内容,(Ljava/lang/String;)代表需要回传一个String型数据;

·括号外面的V代表这是一个void方法;

最后通过env->CallVoidMethod/CallStaticVoidMethod等等与Java方法对应的JNI方法调用JAVA。

来看看GetMethodID第三个参数是怎么表示的:

异步调用:还没理解等待后补

qihong lu

发表评论