一、native方法命名的规则:
JNIEXPORT jobject JNICALL
Java_com_clam314_hellojni_HelloJniActivity_getParameterTestList(JNIEnv *env, jobject instance, jint size) ;
//JNIEXPORT和JNICALL分别用于在Windows下标明该函数导出在外部可以调用和用于约束函数入栈顺序和堆栈清理的规则,在编译到Linux环境的动态库时可用省略
//jobect 是方法的返回类型
//函数名的规则是Java_包名_类名_方法名
//方法的形参列表,第一个是JNIEnv *env, 代表的是JNI 函数表指针
//第二个对应的Java方法是实例方法,第二个形参为 jobject instance,代表的是拥有该Java实例方法的实例。若对应的是Java方法是静态方法,第二个形参为jclass cls,代表的是该方法所属的类
二、Java数据类型在native的映射
1.基本类型
#ifdef HAVE_INTTYPES_H
# include /* C99 */
typedef uint8_t jboolean; /* unsigned 8 bits */
typedef int8_t jbyte; /* signed 8 bits */
typedef uint16_t jchar; /* unsigned 16 bits */
typedef int16_t jshort; /* signed 16 bits */
typedef int32_t jint; /* signed 32 bits */
typedef int64_t jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
#else
typedef unsigned char jboolean; /* unsigned 8 bits */
typedef signed char jbyte; /* signed 8 bits */
typedef unsigned short jchar; /* unsigned 16 bits */
typedef short jshort; /* signed 16 bits */
typedef int jint; /* signed 32 bits */
typedef long long jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
#endif
2.引用类型
typedef _jobject* jobject;
typedef _jclass* jclass;
typedef _jstring* jstring;
typedef _jarray* jarray;
typedef _jobjectArray* jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray* jbyteArray;
typedef _jcharArray* jcharArray;
typedef _jshortArray* jshortArray;
typedef _jintArray* jintArray;
typedef _jlongArray* jlongArray;
typedef _jfloatArray* jfloatArray;
typedef _jdoubleArray* jdoubleArray;
typedef _jthrowable* jthrowable;
typedef _jobject* jweak;
三、字符串问题
字符串在Java里面是属于引用类型的,由JVM进行管理,native不能直接使用Java的字符串需要使用JNIEnv指针
JNIEXPORT void JNICALL
Java_com_clam314_hellojni_HelloJniActivity_parameterStringInput(JNIEnv *env,jobject instance, jstring s_){
const char *c_str = nullptr;
c_str = env->GetStringUTFChars(s_, nullptr);//第二个参数用于指定是复制字符串还在直接引用字符串,为了保证Java String是final的,一般都选择复制一份
if(c_str == nullptr){//当分配空间失败时候。JNI并不会抛异常,只会返回NULL,这时候需要判断,否则后续的操作都是非常危险
LOGE("字符串为空");
return;
}
LOGES(c_str);
env->ReleaseStringUTFChars(s_,c_str);//释放字符串,Get方法一般都有配套的Release用于释放之前分配的内存
}
另外注意 Java 默认使用 Unicode 编码,而 C/C++ 默认使用 UTF 编码
四、使用数组
JNIEXPORT void JNICALL
Java_com_clam314_hellojni_HelloJniActivity_parameterArrayInput(JNIEnv *env, jobject instance, jintArray array_){
jint i,sum = 0;
jint *c_array;
jint arr_len;
//1. 获取数组长度
arr_len = env->GetArrayLength(array_);
//2. 根据数组长度和数组元素的数据类型申请存放java数组元素的缓冲区
c_array = (jint*)malloc(sizeof(jint) * arr_len);
//3. 初始化缓冲区
memset(c_array,0, sizeof(jint)*arr_len);
LOGE("arr_len = %d",arr_len);
//4. 拷贝Java数组中的所有元素到缓冲区中
env->GetIntArrayRegion(array_,0,arr_len,c_array);
for(i = 0; i
五、访问Java实例的实例变量,Java类的静态变量
JNIEXPORT void JNICALL
Java_com_clam314_hellojni_HelloJniActivity_parameterObjectInput(JNIEnv *env, jobject instance, jobject parameter){
jfieldID fim_instance;
jfieldID fim_static;
jstring str;
jint num;
const char *c_str;
//使用env->env->GetObjectClass(parameter)获取实例的类实例jclass
//第一个参数是jclass第二个参数是变量名,第三个参数是变量的类型描述符
//获取实例变量的id
fim_instance = env->GetFieldID(env->GetObjectClass(parameter),"str","Ljava/lang/String;");
//获取静态变量的id
fim_static = env->GetStaticFieldID(env->GetObjectClass(parameter),"num","I");
if(fim_instance == nullptr){
LOGES("没有找到str这个实例变量");
return;
}
if(fim_static == nullptr){
LOGES("没有找到num这个静态变量");
return;
}
//根据获取到的静态变量id,获取静态变量
num = env->GetStaticIntField(env->GetObjectClass(parameter),fim_static);
//根据获取到的实例变量id,获取实例变量
str = (jstring)env->GetObjectField(parameter,fim_instance);
c_str = env->GetStringUTFChars(str, nullptr);
LOGE("parameter str = %s num = %d",c_str,num);
}
类型描述符
1.基本类型
boolean Z
byte B
char C
short S
int I
long L
float F
double D
2.类类型
L +包名路径/类名+; (包名之间用/分隔)
eg:
String Ljava/lang/String;
Object Ljava/lang/Object;
六、调用Java中的实例方法
JNIEXPORT void JNICALL
Java_com_clam314_hellojni_HelloJniActivity_callInstanceMethod(JNIEnv *env, jobject instance, jobject parameter){
jmethodID mid_instance_method;//方法的id
//第一个参数是实例的类实例jclass,第二个参数是方法名,第三个参数方法签名描述符
mid_instance_method = env->GetMethodID(env->GetObjectClass(parameter),"toString","()Ljava/lang/String;");
if(mid_instance_method == nullptr){
LOGES("找不到toString这个方法。");
return;
}
//根据方法id调用实例的方法
env->CallObjectMethod(parameter,mid_instance_method);
}
方法签名描述符:
(形参参数列表)返回值类型。注意:形参参数列表之间不需要用空格或其它字符分隔,形参列表空的话直接为(),返回Void的话用V
java方法 描述符
public String toString(){} ()Ljava/lang/String;
public void call(String str,int i){} (Ljava/lang/String;I)V
七、调用Java的静态方法
JNIEXPORT void JNICALL
Java_com_clam314_hellojni_HelloJniActivity_callStaticMethod(JNIEnv *env, jobject instance){
jclass clazz = nullptr;
jstring str_arg = nullptr;
jmethodID mid_static_method;
//查找类的实例jclass,类所在的路径. 类的全路径名,中间用/代替. 若是SDK提供类似 "java/util/ArrayList"
clazz = env->FindClass("com/clam314/hellojni/ParameterTest");
if(clazz == nullptr){
LOGES("找不到类");
return;
}
mid_static_method = env->GetStaticMethodID(clazz,"callStaticMethod","(Ljava/lang/String;I)V");
if(mid_static_method == nullptr){
LOGES("找不到callStaticMethod这个静态方法。");
return;
}
str_arg = env->NewStringUTF("我是静态方法");
env->CallStaticVoidMethod(clazz,mid_static_method,str_arg,666);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(str_arg);
}
八、返回Java实例
JNIEXPORT jobject JNICALL
Java_com_clam314_hellojni_HelloJniActivity_getInstance(JNIEnv *env, jobject instance, jstring str_, jint num){
jclass clazz = env->FindClass("com/clam314/hellojni/ParameterTest");
jmethodID constructor = env->GetMethodID(clazz,"","(Ljava/lang/String;I)V");
jobject stub_object = env->NewObject(clazz,constructor,str_,num);
return stub_object;
}
JNIEXPORT jobject JNICALL
Java_com_clam314_hellojni_HelloJniActivity_getParameterTestList(JNIEnv *env, jobject instance, jint size) {
jclass clazz = env->FindClass("com/clam314/hellojni/ParameterTest");
jmethodID constructor = env->GetMethodID(clazz,"","(Ljava/lang/String;I)V");
jclass clazz_list = env->FindClass("java/util/ArrayList");
jmethodID constructor_list = env->GetMethodID(clazz_list,"","()V");
jmethodID add_list = env->GetMethodID(clazz_list,"add","(Ljava/lang/Object;)Z");
jobject list = env->NewObject(clazz_list,constructor_list);
for(jint i = 0; iNewObject(clazz,constructor,env->NewStringUTF("add list"),i);
env->CallBooleanMethod(list,add_list,parameter_test);
}
return list;
}
更加详细的资料:
http://wiki.jikexueyuan.com/project/jni-ndk-developer-guide/function.html