1.关于方法名
调用 native 方法之前,首先要调用 System.loadLibrary 接口加载一个实现了native 方法的动态库才能正常访问,否则就会抛出 java.lang.UnsatisfiedLinkError 异常,找不到 XX 方法的提示。现在我们想想,在 Java 中调用某个 native 方法时,JVM 是通过什么方式,能正确的找到动态库中 C/C++ 实现的那个 native 函数呢?
JVM 查找 native 方法
JVM 查找 native 方法有两种方式:
按照 JNI 规范的命名规则
调用 JNI 提供的 RegisterNatives 函数,将本地函数注册到 JVM 中。(后面会详细介绍)
比如Java层 HelloWorld 类中有一个sayHello方法 其命名规则为 Java_com_study_jnilearn_HelloWorld_sayHello
package com.example.testndkeclipse;
public class JniClient {
static public native String AddStr(String strA, String strB);
static public native int AddInt(int a, int b);
}
jni层对应的c文件
com_example_testndkeclipse_JniClient.c
方法为
JNIEXPORT jstring JNICALL Java_com_example_testndkeclipse_JniClient_AddStr
(JNIEnv *env, jclass arg, jstring instringA, jstring instringB)
使用的时候加载动态库
static {
// 加载so库
System.loadLibrary("TestNdk");// lib和.so为前缀后缀,不用加上
}
再在java层中调用即可
String strFromC = JniClient.AddStr("Java2C_参数1", "Java2C_参数2");
2.关于Android.mk文件
Android.mk文件用来告诉NDK编译系统,应该如何编译这些源码。更确切地说,该文件其实就是一个小型的Makefile。你可以在每一个android.mk file中定义一个或多个模块。每个模块属下列类型之一:
1)APK程序,一般的Android程序,编译打包生成apk文件
2)Java库,java类库,编译打包生成jar文件
- C\C++应用程序,可执行的C\C++应用程序
4)C\C++静态库,编译生成C\C++静态库,并打包成.a文件
5)C\C++共享库, 编译生成共享库(动态链接库),并打包成.so, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。
简单的理解为配置文件。
3.关于JNIEnv
在每一个native的C/C++实现的函数声明我们都能看到,除了函数本身的参数,在传入时还传递了一个JNIEnv函数和jclass或者jobject函数。
JNIEnv是一个结构,里面提供了许多进行Java和C/C++进行数据转换和处理的函数。在调用到native代码时实际上传入了由JVM创建的JNIEnv结构的指针,在这个结构内就是java执行栈中的一些数据等内容供native代码进行操作。由于传入的JNIEnv是一个指针,因此使用其中的函数需要以下语法:
(*env)->方法名(env,参数列表) //C的语法
env->方法名(参数列表) //C++的语法
这是由于C语言没有对象的概念,因此要将env指针作为形参传入到JNIEnv方法中。
代码已上传至Github