我们知道都c/c++的方法运行的效率,大部分情况下都比java的方法运行的效率都要高,而且在Android直播项目中就需要使用很多开源的库,比如rtmp,x264, ffmpeg等,这些都是c/c++进行编写的,所以要借助Java Native Interface 来调用这些开源库 。
于是我就一口气将JNI的官方文档都看了一遍,更有了以下的疑问
-
Java如何调用c/c++方法
-
c++线程如何调用java的静态和非静态方法
-
c++如何更改java的静态和非静态的变量
-
c++如何使用java的反射机制
-
c++如何生成java变量并且返回
-
jni方法使用的时候会出现异常,怎么捕获呢?
以下是上述的问题的解答
- Java如何调用c/c++方法?
1.2在Java的方法前添加修饰符native,则表示该方法作为java作为c/c++接口的方法。
1.2 通过控制台进入到工程源码的目录(一般到src的目录下),输入命令行 javah -jni classpath(com/example/jniexample/JNIMethodTest),在当前目录下生产对应的头文件com_example_jniexample_JNIMethodTest.h也可以通过自己编写对应的头文件
#ifndef COM_EXAMPLE_JNIEXAMPLE_JNIMETHODTEST_H
#define COM_EXAMPLE_JNIEXAMPLE_JNIMETHODTEST_H
extern "C"{
//假如在cpp中编译的话需要使用该关键字修饰
JNIEXPROT jstring JNICALL Java_com_example_jniexample_JNIMethodTest(JNIEnv *env, jobject jobz);//需要注意的是static方法第二个参数的是jclass,非static方法jobject
}
#endif
1.3 编写对应的c/cpp文件,引入这个头文件,并且实现头文件的里面的方法
#include "com_example_jniexample_JNIMethodTest.h"
extern "C"{
JNIEXPROT jstring JNICALL Java_com_example_jniexample_JNIMethodTest(JNIEnv *env, jobject jobz){
return env->NewStringUTF("hello i am from c++");
}
}
1.4 在Android Studio使用CMake编译工具,或者是在eclipse使用ndk-build编译工具(这个CMake和ndk-build后面详细介绍)
1.5 在对应的编译工具就会生产对应的动态库,java的方法中就通过System.loadLibrary(“jmethodtest-jni”)来加载动态库,假如生产的动态库出现链接有问题,报某个函数找不到,则通过NDK中的程序 arm-linux-androideabi-objdump来将动态库中的函数都打印出来
$:arm-linux-androideabi-objdump -tT /Users/cwl/Developer/workspace/plugin/JNIExample/libs/armeabi-v7a/libhello-jni.so
//生成类似_ZN7_JNIEnv9NewObjectEP7_jclassP10_jmethodIDz这样子的代码我们根本无法理解,那么通过c++filt 来转换对应的函数
$:++filt -n _ZN7_JNIEnv9NewObjectEP7_jclassP10_jmethodIDz
$:_JNIEnv::NewObject(_jclass*, _jmethodID*, ...)//转换后可读的函数
1.6 然后在代码中调用这个Java的方法,则第一个问题解决。
问题1 的扩展:c++的方法一定要定义成JNIExport JNICALL <Javacom_xxx_xxx_xxx_MethodName>();有没有其他方法来注册动态的注册这些方法。
答:是有的,通过JNIEnv::RegisterNatives(jclass, JNINativeMethods,jint)来动态注册这样的方法。
/*通过Jni_onLoad在每一个so库中只有一个,并且可以在这个Jni_onLoad方法中动态的注册jni的方法,通过*/
JNIEXPROT jint JNICALL Jni_onLoad (JavaVM* vm, void *reserved){
JNIEnv* env = NULL