JNI使用总结

1. 静态

1.1 访问Java类public成员变量

JNIEXPORT jint JNICALL
Java_com_my_1test_jnidemo_MainActivity_addNum(
        JNIEnv *env,
        jobject jobj) {
    jclass jclazz = env->GetObjectClass(jobj);
    jfieldID fid = env->GetFieldID(jclazz, "num", "I");
    jint num = env->GetIntField(jobj, fid);

    num++;

    return num;
}

1.2 访问Java类static成员变量

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_accessStaticField(
        JNIEnv *env,
        jobject jobj)
{
    jclass jclazz = env->GetObjectClass(jobj);
    jfieldID fid  = env->GetStaticFieldID(jclazz, "name", "Ljava/lang/String;");
    jstring  name = (jstring)env->GetStaticObjectField(jclazz, fid);
    const char* str = env->GetStringUTFChars(name, JNI_FALSE);
    std::string ret = "hello ";
    ret.append(str);
    jstring new_ret = env->NewStringUTF(ret.c_str());
    env->SetStaticObjectField(jclazz, fid, new_ret);
}

1.3 访问Java类private成员变量

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_accessPrivateField(
        JNIEnv *env,
        jobject jobj)
{
    jclass jclazz = env->GetObjectClass(jobj);
    jfieldID fid  = env->GetFieldID(jclazz, "age", "I");
    jint     age  = env->GetIntField(jobj, fid);
    if (age > 18)
    {
        age = 18;
    } else
    {
        age--;
    }
    env->SetIntField(jobj, fid, age);
}

1.4 访问Java类public方法

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_accessPublicMethod(
        JNIEnv *env,
        jobject jobj)
{
    jclass jclazz = env->GetObjectClass(jobj);
    jmethodID mid = env->GetMethodID(jclazz, "setSex", "(Ljava/lang/String;)V");
    char c[10] = "male";
    jstring jsex = env->NewStringUTF(c);
    env->CallVoidMethod(jobj, mid, jsex);
}

1.5 访问Java类父类方法

JNIEXPORT jstring JNICALL
Java_com_my_1test_jnidemo_MethodJni_accessSuperMethod(
        JNIEnv *env,
        jobject jobj)
{
    jclass jclazz = env->FindClass("com/my_test/jnidemo/SuperJni");
    if (jclazz == NULL)
    {
        char c[] = "error";
        return env->NewStringUTF(c);
    }
    jmethodID mid = env->GetMethodID(jclazz, "hello", "(Ljava/lang/String;)Ljava/lang/String;");
    char c[10] = "male11";
    jstring jname = env->NewStringUTF(c);
    return (jstring)env->CallNonvirtualObjectMethod(jobj, jclazz, mid, jname);
}

1.6 访问Java的int array

JNIEXPORT jint JNICALL
Java_com_my_1test_jnidemo_MainActivity_intArrayMethod(
        JNIEnv *env,
        jobject jobj, jintArray arr_)
{
    jint len = 0, sum = 0;
    jint *arr = env->GetIntArrayElements(arr_, 0);
    len = env->GetArrayLength(arr_);
    jint i = 0;
    for (; i<len;i++)
    {
        sum += arr[i];
    }
    env->ReleaseIntArrayElements(arr_, arr, 0);

    return sum;
}

1.7 访问Java传入对象的方法

JNIEXPORT jobject JNICALL
Java_com_my_1test_jnidemo_MainActivity_objectMethod(
        JNIEnv *env,
        jobject jobj, jobject person)
{
    jclass clazz = env->GetObjectClass(person);
    if (clazz == NULL){
        return env->NewStringUTF("cannot find class");
    }
    jmethodID mid = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");

    if (mid == NULL)
    {
        return env->NewStringUTF("not find constructor method");
    }
    jstring name = env->NewStringUTF("cfanr");

    return env->NewObject(clazz, mid, 21, name);
}

1.7 访问Java传入的类的ArrayList

JNIEXPORT jobject JNICALL
Java_com_my_1test_jnidemo_MainActivity_personArrayListMethod(
        JNIEnv *env,
        jobject jobj, jobject persons)
{
    jclass clazz = env->GetObjectClass(persons);
    if (clazz == NULL)
    {
        return env->NewStringUTF("not find class");
    }
    jmethodID constructMid = env->GetMethodID(clazz, "<init>", "()V");
    if (constructMid == NULL)
    {
        return env->NewStringUTF("not find constructormethod");
    }
    jmethodID addMid = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");
    jclass personCls = env->FindClass("com/my_test/jnidemo/Person");
    jmethodID personMid = env->GetMethodID(personCls, "<init>", "(ILjava/lang/String;)V");

    jobject arrayList = env->NewObject(clazz, constructMid);

    jint i = 0;
    for (;i<3;i++)
    {
        jstring name = env->NewStringUTF("Native");
        jobject person = env->NewObject(personCls, personMid, 18+i, name);
        env->CallBooleanMethod(arrayList, addMid, person);
    }

    return arrayList;
}

2. 动态注册

2.1 步骤

  • 动态注册
  • 先编写Java的native方法
  • 编写JNI函数的实现(函数名可以随便命名)
  • 利用结构体JNINativeMethod保存Java native方法和JNI函数对应关系
  • 利用registerNatives(JNIEnv* env)注册类的所有本地方法
  • 在JNI_OnLoad方法中调用注册方法
  • 在java中通过System.loadLibrary加载完JNI动态库之后,会自动调用JNI_OnLoad函数完成动态注册

2.2 实现代码:

static jstring sayHello(JNIEnv *env, jobject){
    LOGI("hello, this is native log.");
    const char *hello = "Hello from c++";
    return env->NewStringUTF(hello);
}
static JNINativeMethod jni_Methods_table[] = {
        {"getStringFromCpp", "()Ljava/lang/String;", (void*)sayHello},
};
static int registerNativeMethods(JNIEnv *env, const char *className, const JNINativeMethod *gMethods, int numMethods){
    jclass clazz;
    LOGI("Registering %s natives\n", className);
    clazz = env->FindClass(className);
    if (clazz == NULL){
        LOGE("Native registration unable to find class %s\n", className);
        return JNI_ERR;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0)
    {
        LOGE("Register natives failed for %s\n", className);
        return JNI_ERR;
    }
    env->DeleteLocalRef(clazz);
    return JNI_OK;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    LOGI("call JNI_OnLoad");
    JNIEnv *env = NULL;

    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
    {
        return JNI_EVERSION;
    }

    registerNativeMethods(env, className, jni_Methods_table, sizeof(jni_Methods_table)/sizeof(JNINativeMethod));
    return JNI_VERSION_1_4;
}

JNIEXPORT void JNICALL
Java_com_my_1test_jnidemo_MainActivity_registerNatives(
        JNIEnv *env, jclass clazz){
    env->RegisterNatives(clazz, jni_Methods_table, sizeof(jni_Methods_table)/sizeof(JNINativeMethod));
}
#ifdef __cplusplus
}
#endif

完整代码:
链接
其他可参考文章:
链接
链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值