JIN方法签名
在C中调用Java中方法时需要使用到方法签名。就是将方法的返回类型和参数类型转换为特定的符号。规则如下:
java类型 | 符号 |
---|---|
Boolean | Z |
Byte | B |
Char | C |
Short | S |
Int | I |
Long | J |
Float | F |
Double | D |
Void | V |
数组 | [ , 如:int[]-> [I, int[][]-> [[I, Thread[]-> [Ljava/lang/Thread; |
objects | 以”L”开头,以”;”结尾,中间是用”/” 隔开的包及类名。比如:Ljava/lang/String;如果是嵌套类,则用 来 表 示 嵌 套 。 例 如 “ ( L j a v a / l a n g / S t r i n g ; L a n d r o i d / o s / F i l e U t i l s 来表示嵌套。例如 “(Ljava/lang/String;Landroid/os/FileUtils 来表示嵌套。例如“(Ljava/lang/String;Landroid/os/FileUtilsFileStatus;)Z” |
java调用C中方法
需要先在java中定义native方法:
public native int add(int x,int y);
public native String sayHello(String s);
public native int[] increaseArrayEles(int[] intArray);
public native int checkPwd(String pwd);
需要在C代码中实现这些方法,可以在Android studio中执行javah命令:
进入到java目录下,执行 javah com.xx.xx(包名).xx(类名) 可以生成.h文件,然后可以在.c文件中执行对应的方法。
c中实现方法:
/**
* 将jstring转换为C中的char数组。
* @param env
* @param jstr 字符串
* @return
*/
char* _JString2CStr(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if(alen > 0) {
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba,0);
return rtn;
}
JNIEXPORT jstring JNICALL Java_wangjin_com_cmakendkdemo_JNI_sayHello
(JNIEnv *env, jobject jobj, jstring jstr){
char* fromJava = _JString2CStr(env,jstr);
char* formC = "add I am from C";
strcat(fromJava,formC);
return (*env)->NewStringUTF(env,fromJava); //返回字符串
}
JNIEXPORT jintArray JNICALL Java_wangjin_com_cmakendkdemo_JNI_increaseArrayEles
(JNIEnv *env, jobject jobj, jintArray array){
int size = (*env)->GetArrayLength(env,array);
jint* intArray = (*env)->GetIntArrayElements(env,array,JNI_FALSE);
for(int i=0;i < size;i++){
*(intArray+i) = *(intArray+i) +10;
LOGE("from c: %d",*(intArray+i));
}
return array; //返回int类型数组
};
JNIEXPORT jint JNICALL Java_wangjin_com_cmakendkdemo_JNI_checkPwd
(JNIEnv *env, jobject jobj, jstring pwd){
char* formJava = _JString2CStr(env,pwd);
char* passworld="12345";
int code = strcmp(passworld,formJava);
if(code == 1){
return 200;
} else {
return 400;
}
};
C中回调java方法
即Java中调用的C方法需要使用java中的方法。要注意调用的Java方法是不是static类型。
调用非static类型的步骤如下:
1、得到字节码 jclass
2、得到 method IDs jmethodID
3、实例化该类
4、调用方法
1)调用返回类型为int类型
/**
* 当执行这个方法的时候,让C代码调用
* public int add(int x, int y)
*/
public native void callbackAdd();
Java中的add方法:
public int add(int x, int y) {
Log.e("TAG", "add() x=" + x + " y=" + y);
return x + y;
}
C代码中实现方法:
//1、得到字节码
//jclass (*FindClass)(JNIEnv*, const char*);
jclass jclazz = (*env)->FindClass(env,"wangjin/com/cmakendkdemo/CCallJava");
//2、得到方法
//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
//第3个参数是要调用的方法名,第4个参数是方法签名,由于int add(int ,int),所已参数为"(II)I"
jmethodID jmethodID1=(*env)->GetMethodID(env,jclazz,"add","(II)I");
//3、实例化该类
//jobject (*AllocObject)(JNIEnv*, jclass);
jobject jobject1 = (*env)->AllocObject(env,jclazz);
//4、调用方法 有返回值,类型为int,后两个参数时add方法的参数:99,1
//jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallIntMethod(env,jobject1,jmethodID1,99,1);
//成功调用add方法。
2)调用返回类型和参数都为void的方法
/**
* 当执行这个方法的时候,让C代码调用
* public void helloFromJava()
*/
public native void callbackHelloFromJava();
public void helloFromJava() {
Log.e("TAG", "helloFromJava()");
}
实现方法:
//1、得到字节码
//jclass (*FindClass)(JNIEnv*, const char*);
jclass jclazz = (*env)->FindClass(env,"wangjin/com/cmakendkdemo/CCallJava");
//2、得到方法
//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
//第3个参数是要调用的方法名,第4个参数是方法签名,参数为null,则签名为()V,不要写成(V)V
jmethodID jmethodID1=(*env)->GetMethodID(env,jclazz,"helloFromJava","()V");
//3、实例化该类
//jobject (*AllocObject)(JNIEnv*, jclass);
jobject jobject1 = (*env)->AllocObject(env,jclazz);
//4、调用方法 无返回值
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,jobject1,jmethodID1);
//成功调用helloFromJava方法。
3) 调用参数为String 返回类型为void的方法
/**
* 当执行这个方法的时候,让C代码调用void printString(String s)
*/
public native void callbackPrintString();
public void printString(String s) {
Log.e("TAG","C中输入的:" + s);
}
实现方法:
//1、得到字节码
//jclass (*FindClass)(JNIEnv*, const char*);
jclass jclazz = (*env)->FindClass(env,"wangjin/com/cmakendkdemo/CCallJava");
//2、得到方法
//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
//第3个参数是要调用的方法名,第4个参数是方法签名,注意参数的签名
jmethodID jmethodID1=(*env)->GetMethodID(env,jclazz,"printString","(Ljava/lang/String;)V");
//3、实例化该类
//jobject (*AllocObject)(JNIEnv*, jclass);
jobject jobject1 = (*env)->AllocObject(env,jclazz);
//4、调用方法 有返回值
//jstring (*NewStringUTF)(JNIEnv*, const char*);
jstring jstring1 = (**env).NewStringUTF(env,"I am from C");
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,jobject1,jmethodID1,jstring1);
//成功调用printString方法。
4)调用static方法
调用static方法和非static方法不同,不在需要实例化类。
1、得到字节码 jclass
2、得到 method IDs jmethodID
3、调用方法
/**
* 当执行这个方法的时候,让C代码静态方法 static void sayHello(String s)
*/
public native void callbackSayHello();
public static void sayHello(String s){
Log.e("TAG", "我是java代码中的JNI."
+ "java中的sayHello(String s)静态方法,我被C调用了:"+ s);
}
C中实现方法:
//1、得到字节码
//jclass (*FindClass)(JNIEnv*, const char*);
jclass jclazz = (*env)->FindClass(env,"wangjin/com/cmakendkdemo/CCallJava");
//2、得到方法
//jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
//第3个参数是要调用的方法名,第4个参数是方法签名
jmethodID jmethodStaticID1=(*env)->GetStaticMethodID(env,jclazz,"sayHello","(Ljava/lang/String;)V");
//3、实例化该类
//jobject (*AllocObject)(JNIEnv*, jclass);
jobject jobject1 = (*env)->AllocObject(env,jclazz);
//4、调用方法 有返回值
//jstring (*NewStringUTF)(JNIEnv*, const char*);
jstring jstring1 = (**env).NewStringUTF(env,"I am from C");
//void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
//注意,第二个参数是jclass类型
(*env)->CallStaticVoidMethod(env,jclazz,jmethodStaticID1,jstring1);
//成功调用sayHello方法。
5)C中修改更新UI
//native 只能写在更新UI的类中。
public native void callBackShowToast();
public void showToast(){
Toast.makeText(this,"C中调用更改UI的方法",Toast.LENGTH_SHORT).show();
}
C中实现:
/**
* instance:谁调用了当前Java_wangjin_com_cmakendkdemo_MainActivity_callBackShowToast对应的Java接口
* 谁就是实例instance,当改变UI时,只能是在UI线程中,此处的实例是activity
* @param env
* @param instance
*/
JNIEXPORT void JNICALL
Java_wangjin_com_cmakendkdemo_MainActivity_callBackShowToast(JNIEnv *env, jobject instance) {
//1、得到字节码
//jclass (*FindClass)(JNIEnv*, const char*);
jclass jclazz = (*env)->FindClass(env,"wangjin/com/cmakendkdemo/MainActivity");
//2、得到方法
//jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
//第3个参数是要调用的方法名,第4个参数是方法签名
jmethodID jmethodStaticID1=(*env)->GetMethodID(env,jclazz,"showToast","()V");
//3、调用方法 无返回值,注意,这里的jobject是instance
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,instance,jmethodStaticID1);
//成功调用showToast方法。
}