JNI开发基础系列--java和c之间互调

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("你好"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值