Android之jni调用java函数总结
2017-05-14 21:51
531 查看
1、先看之前jni的如何实现动态注册
先看我之间的例子 http://blog.csdn.net/u011068702/article/details/71375920Android之JNI动态注册native方法和JNI数据简单使用
因为这里演示的jni调用java函数是基于这个例子改的,然后还有如何在jni里面加上日志可以看这篇博客
http://blog.csdn.net/u011068702/article/details/71852904
Android之jni日志如何输出
2、贴出相关代码
1)、java文加如下、package com.example.chenyu.test; public class JniClient { public JniClient() { } public native String getStr(); public native int addInt(int a, int b); /** * C调用java空方法 */ public void nullMethod() { System.out.println("I am chenyu, from java"); } /** * C调用java中的带两个int参数的方法 * * @param x * @param y * @return */ public int add(int x, int y) { int result = x + y; System.out.println("result in java " + result); return result; } /** * C调用java中参数为String的方法 * * @param s */ public String printString(String s) { String result = "I am chenyu, from java " + s; System.out.println(result); return result; } // 本地方法 public native void callMethod1(); public native void callMethod2(); public native void callMethod3(); }
这里写了3个jni方法,然后我们实现这3个jni方法调用上面的3个java方法
jni里面的代码如下
// // Created by chenyu on 5/7/17. // #include <stdlib.h> #include <string.h> #include <stdio.h> #include <jni.h> #include <assert.h> #include <log_help.h> //定义的时候要记得加上双引号 不是#define TAG JniClient #define TAG "JniClient" #define JNIREG_CLASS "com/example/chenyu/test/JniClient"//指定要注册的类 jstring get_str(JNIEnv* env, jobject thiz) { LOGD(TAG, "hello chenyu"); char * str = "this is first LOGD"; LOGD(TAG, "hello chenyu %s", str); return (*env)->NewStringUTF(env, "I am chenyu, 动态注册JNI"); } jint add_int(JNIEnv* env, jobject jobj, jint num1, jint num2) { LOGD(TAG, "nums + num2 is %d", num1 + num2); return num1 + num2; } void callMethod1(JNIEnv* env, jobject obj) { LOGD(TAG, "this is jni call1"); //在C语言中调用Java的空方法 //1.找到java代码native方法所在的字节码文件 //jclass (*FindClass)(JNIEnv*, const char*); jclass clazz = (*env)->FindClass(env, "com/example/chenyu/test/JniClient"); if(clazz == 0) { LOGD(TAG, "find class error"); return; } LOGD(TAG, "find class success"); //2.找到class里面对应的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method1 = (*env)->GetMethodID(env, clazz, "nullMethod", "()V"); if(method1 == 0) { LOGD(TAG, "find callMethod1 error"); return; } LOGD(TAG, "find callMethod1 success"); //3.调用方法 //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); (*env)->CallVoidMethod(env, obj, method1); LOGD(TAG, "callMethod1 called success"); } void callMethod2(JNIEnv* env, jobject obj) { LOGD(TAG, "this is jni call2"); jclass clazz = (*env)->FindClass(env, "com/example/chenyu/test/JniClient"); if(clazz == 0) { LOGD(TAG, "find class error"); return; } LOGD(TAG, "find class success"); //2.找到class里面对应的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method2 = (*env)->GetMethodID(env, clazz, "add", "(II)I"); if(method2 == 0) { LOGD(TAG, "find callMethod2 error"); return; } LOGD(TAG, "find callMethod2 success"); //3.调用方法 //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); int result = (*env)->CallIntMethod(env, obj, method2, 3, 5); LOGD(TAG, "callMethod2 called success"); LOGD(TAG, "in java 3 + 5 is %d", result); } void callMethod3(JNIEnv* env, jobject obj) { LOGD(TAG, "this is jni call3"); jclass clazz = (*env)->FindClass(env, "com/example/chenyu/test/JniClient"); if (clazz == 0) { LOGD(TAG, "find class error"); return; } LOGD(TAG, "find class success"); //2.找到class里面对应的方法 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID method3 = (*env)->GetMethodID(env, clazz, "printString", "(Ljava/lang/String;)Ljava/lang/String;"); if(method3 == 0) { LOGD(TAG, "find callMethod3 error"); return; } LOGD(TAG, "find callMethod3 success"); //3.调用方法 //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); jstring result = (*env)->CallObjectMethod(env, obj, method3, (*env)->NewStringUTF(env, "hello jni insert data")); //(*env)->CallVoidMethod(env, obj, method3, "chenyu"); //如果用这个会出现 JNI ERROR (app bug): accessed stale global reference 0xb39533f2 (index 19708 in a table of size 248) const char* result1 = (*env)->GetStringUTFChars(env, result, NULL);//将返回的java字符串转换为c字符串 LOGD(TAG, "callMethod3 called success result is %s", result1); } /** * 方法对应表 */ static JNINativeMethod gMethods[] = { {"getStr", "()Ljava/lang/String;", (void*)get_str}, {"addInt", "(II)I", (void*)add_int}, {"callMethod1", "()V", (void*)callMethod1}, {"callMethod2", "()V", (void*)callMethod2}, {"callMethod3", "()V", (void*)callMethod3}, }; /* * 为某一个类注册本地方法 */ static int registerNativeMethods(JNIEnv* env , const char* className , JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } /* * 为所有类注册本地方法 */ static int registerNatives(JNIEnv* env) { return registerNativeMethods(env, JNIREG_CLASS, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } /* * System.loadLibrary("lib")时调用 * 如果成功返回JNI版本, 失败返回-1 */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { LOGD(TAG, "this is jni start and will exec JNI_OnLoad methos"); JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } assert(env != NULL); if (!registerNatives(env)) {//注册 return -1; } //成功 result = JNI_VERSION_1_4; return result; }
步骤为:
1)、获取jclass
2)、获取jmethodID
3)、调用本地的Call*****Method(); 如果不清楚函数,可以查看这里 http://www.ceeger.com/Script/AndroidJNI/AndroidJNI.CallStaticIntMethod.html
如果函数返回String类型的话我们要调用
jstring result = (*env)->CallObjectMethod(env, obj, method3, (*env)->NewStringUTF(env, "hello jni insert data"));如果是jstring类型转成char *类型,我们需要用这个函数
const char* result1 = (*env)->GetStringUTFChars(env, result, NULL)
还有就是char *转成jstring可以用看下面的函数
/** * 转换c中的字符串为java.lang.String,这个方法是从网上找到的,感谢原作者<a href="http://home.cnblogs.com/u/liangwind/">天末凉风</a> */ jstring stoJstring(JNIEnv* env, const char* pat) { jclass strClass = (*env)->FindClass(env,"Ljava/lang/String;"); jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V"); jbyteArray bytes = (*env)->NewByteArray(env,strlen(pat)); (*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat); jstring encoding = (*env)->NewStringUTF(env,"utf-8"); return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding); }
在C++里面,把jstring转化成string函数如下
static std::string jstring2str(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("UTF-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr,mid,strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr,JNI_FALSE);
if(alen > 0)
{
rtn = (char*)malloc(alen+1);
memcpy(rtn,ba,alen);
rtn[alen]=0;
}
env->ReleaseByteArrayElements(barr,ba,0);
std::string stemp(rtn);
free(rtn);
return stemp;
}
至于参数的详解,返回值,数据类型,我前面几篇博客已经讲解,这里就不详细说了
3、运行结果
4、总结
jni调用java函数简单步骤,在jni函数里面实现以下几个步骤1)、获取jclass
2)、获取jmethodID
3)、调用本地的Call*****Method(); 如果不清楚函数
如果函数返回String类型的话我们要调用
jstring result = (*env)->CallObjectMethod(env, obj, method3, (*env)->NewStringUTF(env, "hello jni insert data"));如果是jstring类型转成char *类型,我们需要用这个函数
const char* result1 = (*env)->GetStringUTFChars(env, result, NULL)
相关文章推荐
- Android使用JNI(从java调用本地函数)
- cocos2dx3.3 android工程 Jni调用java函数
- 【iOS-cocos2d-X 游戏开发之十三】详细讲解在Xcode中利用预编译并通过Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- VS2010 通过Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- JniHelper调用java静态和非静态方法总结(即cocos2dx中调用android平台下显示第三方广告)
- Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- android jni c/c++线程通过CallVoidMethod调用java函数出现奔溃问题
- 【iOS-cocos2d-X 游戏开发之十三】详细讲解在Xcode中利用预编译并通过Jni调用Android的Java层代码(cocos2dx里访问调用Android函数)!
- AndroidJNI 通过C++调用JAVA
- Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- 如何通过JNI在Java中调用C库函数
- AndroidJNI 通过C++调用JAVA
- java中如何使用JNI调用C++写的函数
- JNI学习--通过Java应用调用C语言的函数打印hello,world
- Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- Android JNI 使用的数据结构JNINativeMethod详解 ||建立Android SDK下的JNI、JAVA应用完整步骤---Android JAVA调用C++代码
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(上)
- 关于java调用window DLL里的函数的总结
- 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(下)