java和c之间互调
1、 java非静态native方法调c
在java中编写非静态方法:
public native String getString();
在c中
//java非静态方法jobject
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_getString
(JNIEnv * env, jobject jobj){//非静态方法时第二个参数为jobject,代指java调用native方法的对象
return (*env)->NewStringUTF(env,"I'am from c");
}
java中调用结果:
I'am from c
2、 java静态方法调用c
java中编写
public native static String getStringStatic();
在c中
//java 中静态方法jclass
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_getStringStatic
(JNIEnv * env, jclass jclzz){//静态方法和非静态方法的区别就在于第二个参数为class,及指的是java中的那个类
return (*env)->NewStringUTF(env,"this is a static method");
java中调用结果:
this is a static method
3、 c访问java的非静态域
java中
public String key = "key";
public native void accessField();//访问java中的非静态域
在c中
JNIEXPORT void JNICALL Java_com_cool_ndktest_Jni_accessField
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclzz = (*env)->GetObjectClass(env,jobj);
//获取jfieldID 第3个参数为java中腰访问的字段名,第4个参数为方法签名,不懂或者不清楚可以去查查
jfieldID fid = (*env)->GetFieldID(env,jclzz,"key","Ljava/lang/String;");
//获取java中的key对应的值 String key = "value";其中jstr就是jni类型的"value"
jstring jstr = (*env)->GetObjectField(env,jobj,fid);
//将jni中的String转换为c中的字符串char*
char* c_str = (*env)->GetStringUTFChars(env,jstr,NULL);
char text[30] = "key ";
//生成新字符串key value
strcat(text,c_str);
//c string -> jni jsting
jstring new_str = (*env)->NewStringUTF(env,text);
//重新设置字段
(*env)->SetObjectField(env,jobj,fid,new_str);
(*env)->ReleaseStringChars(env,new_str,c_str);
}
java中调用及运行结果
java中调用:
Log.e("399","key修改前:" + jni.key);
jni.accessField();
Log.e("399","key修改后:" + jni.key);
运行结果:
key修改前:value
key修改后key: value
4、 c访问java中的静态域
java中
public static int num = 10;
public native void accessStaticField();//访问java中的静态域
c中
JNIEXPORT void JNICALL Java_com_cool_ndktest_Jni_accessStaticField
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclazz = (*env)->GetObjectClass(env,jobj);
//获取jfieldId
jfieldID fid = (*env)->GetStaticFieldID(env,jclazz,"num","I");
//获取java中num字段的值
int num = (*env)->GetStaticIntField(env,jclazz,fid);
num ++;
(*env)->SetStaticIntField(env,jclazz,fid,num);
}
java中调用及运行结果
java中调用:
Log.e("399","num修改前:" + jni.num);
jni.accessStaticField();
Log.e("399","num修改后:" + jni.num);
运行结果:
num修改前:10
num修改后:11
5、 c调用java中的非静态方法
java中
public int getRandom(int max){
Random random = new Random();
return random.nextInt(max);
}
public native int accessMethod();//访问java中非静态方法
c中
JNIEXPORT jint JNICALL Java_com_cool_ndktest_Jni_accessMethod
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclazz = (*env)->GetObjectClass(env,jobj);
//获取jmethodId
jmethodID jmethId = (*env)->GetMethodID(env,jclazz,"getRandom","(I)I");
//调用
int result = (*env)->CallIntMethod(env,jobj,jmethId,200);
return result;
}
java中调用及运行结果
调用:Log.e("399","随机数:" + jni.accessMethod());
运行结果: 随机数:137
6、 c调用java静态方法
java中
public static String getUUID(){
return UUID.randomUUID().toString();
}
public native String accessStaticMethod();//访问java中的静态方法
c中
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_accessStaticMethod
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclazz = (*env)->GetObjectClass(env,jobj);
//获取jmethodId
jmethodID jmid = (*env)->GetStaticMethodID(env,jclazz,"getUUID","()Ljava/lang/String;");
//调用
jstring jstr = (*env)->CallStaticObjectMethod(env,jclazz,jmid);
return jstr;
}
java中调用及运行结果:
调用:Log.e("399","UUID:" + jni.accessStaticMethod());
运行结果:UUID:29c4ca2c-024d-4cf7-8f81-6bc254c2cf80
7、访问java中的构造函数
java中
public native Date acceessConstructor();//访问java中的构造函数
c中
JNIEXPORT jobject JNICALL Java_com_cool_ndktest_Jni_acceessConstructor
(JNIEnv * env, jobject jobj){
//获取jclass 通过类的路径来从JVM 里面找到对应的类
jclass jclazz = (*env)->FindClass(env,"java/util/Date");
//获取jmethodId 第3个参数:构造函数默认为<init> 第4个参数为构造函数签名,这里访问的是Date()无参构造函数
jmethodID jmid = (*env)->GetMethodID(env,jclazz,"<init>","()V");
//创建对象
jobject jdate_obj = (*env)->NewObject(env,jclazz,jmid);
//获取Date中getTime方法的jmethodID
jmethodID jget_time = (*env)->GetMethodID(env,jclazz,"getTime","()J");
//调用java中的getTime方法
jlong jtime = (*env)->CallLongMethod(env,jdate_obj,jget_time);
//在android中打印日志
LOGE("来自jni:%lld",jtime);
return jdate_obj;
}
这里使用在android中打印日志的方法,所以在前面加上
#include <android/log.h>
#define TAG "399"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
java中调用以及运行结果:
java中调用:
Date date = jni.acceessConstructor();
Log.e("399","调用java的构造函数: " + date.getTime());
运行结果:
来自jni:1502681960114
调用java的构造函数: 1502681960114
8、处理中文字符串乱码问题
java中
public native String handleChineseString(String msg);//处理中文字符串
c中
//处理中文字符串
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_handleChineseString
(JNIEnv *env, jobject jobj, jstring jstr){
jboolean jbool;
char * c_str = (*env)->GetStringUTFChars(env,jstr,&jbool);
if(jbool){
LOGE("is copy: JNI_TRUE");
} else{
LOGE("is copy: JNI_FALSE");
}
LOGE("c中获取的string:%s",c_str);
char * c_s = "带着心情去旅行";
char * new_str = strcat(c_str,c_s);
jclass str_clazz = (*env)->FindClass(env,"java/lang/String");
jmethodID jmid = (*env)->GetMethodID(env,str_clazz,"<init>","([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env,strlen(new_str));
// 将Char * 赋值到 bytes
(*env)->SetByteArrayRegion(env,bytes,0,strlen(new_str),new_str);
char * charset = "UTF-8";
jstring charsetName = (*env)->NewStringUTF(env,charset);
jstring j_result = (*env)->NewObject(env,str_clazz,jmid,bytes,charsetName);
return j_result;
}
调用和运行结果:
java调用:Log.e("399",jni.handleChineseString("你好"));
运行结果:
E/399: 你好带着心情去旅行
最后,来个测试的完整源码:
Jni.java
public class Jni {
static {
System.loadLibrary("native-lib");
}
public String key = "value";
public static int num = 10;
public int getRandom(int max){
Random random = new Random();
return random.nextInt(max);
}
public static String getUUID(){
return UUID.randomUUID().toString();
}
public native String getString();
public native static String getStringStatic();
public native void accessField();//访问java中的非静态域
public native void accessStaticField();//访问java中的静态域
public native int accessMethod();//访问java中非静态方法
public native String accessStaticMethod();//访问java中的静态方法
public native Date acceessConstructor();//访问java中的构造函数
public native String handleChineseString(String msg);//处理中文字符串
}
hello.c
//
// Created by cool on 2017/8/13.
//
#include "com_cool_ndktest_Jni.h"
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#define TAG "399"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_getString
(JNIEnv * env, jobject jobj){
return (*env)->NewStringUTF(env,"I'am from c");
}
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_getStringStatic
(JNIEnv * env, jclass jclzz){
return (*env)->NewStringUTF(env,"this is a static method");
}
//访问java中的非静态域
JNIEXPORT void JNICALL Java_com_cool_ndktest_Jni_accessField
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclzz = (*env)->GetObjectClass(env,jobj);
//获取jfieldID
jfieldID fid = (*env)->GetFieldID(env,jclzz,"key","Ljava/lang/String;");
//获取java中的key对应的值 String key = "value";其中jstr就是jni类型的"value"
jstring jstr = (*env)->GetObjectField(env,jobj,fid);
//将jni中的String转换为c中的字符串char*
char* c_str = (*env)->GetStringUTFChars(env,jstr,NULL);
char text[30] = "key ";
//生成新字符串key value
strcat(text,c_str);
//c string -> jni jsting
jstring new_str = (*env)->NewStringUTF(env,text);
//重新设置字段
(*env)->SetObjectField(env,jobj,fid,new_str);
(*env)->ReleaseStringChars(env,new_str,c_str);
}
//访问java中的静态域
JNIEXPORT void JNICALL Java_com_cool_ndktest_Jni_accessStaticField
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclazz = (*env)->GetObjectClass(env,jobj);
//获取jfieldId
jfieldID fid = (*env)->GetStaticFieldID(env,jclazz,"num","I");
//获取java中num字段的值
int num = (*env)->GetStaticIntField(env,jclazz,fid);
num ++;
(*env)->SetStaticIntField(env,jclazz,fid,num);
}
//访问java中的非静态方法
JNIEXPORT jint JNICALL Java_com_cool_ndktest_Jni_accessMethod
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclazz = (*env)->GetObjectClass(env,jobj);
//获取jmethodId
jmethodID jmethId = (*env)->GetMethodID(env,jclazz,"getRandom","(I)I");
int result = (*env)->CallIntMethod(env,jobj,jmethId,200);
return result;
}
//访问java中的静态方法
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_accessStaticMethod
(JNIEnv * env, jobject jobj){
//获取jclass
jclass jclazz = (*env)->GetObjectClass(env,jobj);
//获取jmethodId
jmethodID jmid = (*env)->GetStaticMethodID(env,jclazz,"getUUID","()Ljava/lang/String;");
//调用
jstring jstr = (*env)->CallStaticObjectMethod(env,jclazz,jmid);
return jstr;
}
//访问java中的构造函数
JNIEXPORT jobject JNICALL Java_com_cool_ndktest_Jni_acceessConstructor
(JNIEnv * env, jobject jobj){
//获取jclass 通过类的路径来从JVM 里面找到对应的类
jclass jclazz = (*env)->FindClass(env,"java/util/Date");
//获取jmethodId 第3个参数:构造函数默认为<init> 第4个参数为构造函数签名,这里访问的是Date()无参构造函数
jmethodID jmid = (*env)->GetMethodID(env,jclazz,"<init>","()V");
//创建对象
jobject jdate_obj = (*env)->NewObject(env,jclazz,jmid);
//获取Date中getTime方法的jmethodID
jmethodID jget_time = (*env)->GetMethodID(env,jclazz,"getTime","()J");
//调用java中的getTime方法
jlong jtime = (*env)->CallLongMethod(env,jdate_obj,jget_time);
//在android中打印日志
LOGE("来自jni:%lld",jtime);
return jdate_obj;
}
//处理中文字符串
JNIEXPORT jstring JNICALL Java_com_cool_ndktest_Jni_handleChineseString
(JNIEnv *env, jobject jobj, jstring jstr){
jboolean jbool;
char * c_str = (*env)->GetStringUTFChars(env,jstr,&jbool);
if(jbool){
LOGE("is copy: JNI_TRUE");
} else{
LOGE("is copy: JNI_FALSE");
}
LOGE("c中获取的string:%s",c_str);
char * c_s = "带着心情去旅行";
char * new_str = strcat(c_str,c_s);
jclass str_clazz = (*env)->FindClass(env,"java/lang/String");
jmethodID jmid = (*env)->GetMethodID(env,str_clazz,"<init>","([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env,strlen(new_str));
// 将Char * 赋值到 bytes
(*env)->SetByteArrayRegion(env,bytes,0,strlen(new_str),new_str);
char * charset = "UTF-8";
jstring charsetName = (*env)->NewStringUTF(env,charset);
jstring j_result = (*env)->NewObject(env,str_clazz,jmid,bytes,charsetName);
return j_result;
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
Jni jni = new Jni();
tv.setText(jni.getString());
Log.e("399",Jni.getStringStatic());
Log.e("399","key修改前" + jni.key);
jni.accessField();
Log.e("399","key修改后" + jni.key);
Log.e("399","num修改前:" + jni.num);
jni.accessStaticField();
Log.e("399","num修改后:" + jni.num);
Log.e("399","随机数:" + jni.accessMethod());
Log.e("399","UUID:" + jni.accessStaticMethod());
Date date = jni.acceessConstructor();
Log.e("399","调用java的构造函数: " + date.getTime());
Log.e("399",jni.handleChineseString("你好"));
}
}