基本步骤
- 通过env找到Java类:使用
FindClass
方法找到所需的 Java 类。 - 通过env获取Java类中的方法ID:使用
GetMethodID
或GetStaticMethodID
方法获取 Java 方法的 ID。 - 通过env创建Java对象:使用
AllocObject
或者NewObject
来创建Java对象 - 通过env调用方法:使用
Call<type>Method
或CallStatic<type>Method
调用 Java 方法。
详细解析
假设使用以下Java类:
public class MyClass {
public void instanceMethod(String message) {
System.out.println("Instance Method: " + message);
}
public static int staticMethod(int number) {
return number * 2;
}
}
在MainActivity中创建JNI函数接口:
public native int getNumber();
在native-lib.cpp中实现对应的c++代码来调用Java方法
1.通过env来找到类:
jclass clazz = env->FindClass("com/marxist/firstjni/MyClass");
if (!clazz) {
std::cerr << "Failed to find class" << std::endl;
return -1;
}
2.获取方法ID
方法ID又分为实例方法和静态方法,获取方式有差别
使用 env->GetMethodID 或者 env->GetStaticMethodID
传入的参数都是 步骤1获取到的类,方法名字,和方法签名 ps:Android studio识别到方法名之后,会自动补全方法签名,非常方便
//实例方法
jmethodID instanceMethodID = env->GetMethodID(clazz,"instanceMethod","(Ljava/lang/String;)V");
if (!instanceMethodID) {
std::cerr << "Failed to get method ID for instanceMethod" << std::endl;
return -1;
}
//静态方法
jmethodID staticMethodID = env->GetStaticMethodID(clazz,"staticMethod", "(I)I");
if (!staticMethodID) {
std::cerr << "Failed to get method ID for staticMethodID" << std::endl;
return -1;
}
3.创建对象
创建对象的方式有两种:
- 立即申请对象并初始化 使用NewObject 必须要传入构造方法
- AllocObject 分配内存,但先不初始化,不用传入构造方法
// Using AllocObject
jobject obj1 = env->AllocObject(myClass);
// Using NewObject
jmethodID constructor = env->GetMethodID(myClass, "<init>", "()V");
if (constructor) {
jobject obj2 = env->NewObject(myClass, constructor);
}
使用NewObject 的方式创建的话,在创建之前多了一步 获取构造方法
jmethodID constructor = env->GetMethodID(myClass, "<init>", "()V");
这里是获取默认的无参的构造函数
4.执行方法
使用 Call<type>Method
或 CallStatic<type>Method
来调用Java方法
需要注意的一点是:如果调用的是静态方法,不需要new 对象,与Java语法一致,直接使用类调用方法即可,调用普通的方法,传入对象和前面获取到的方法ID。传入的参数是Java类型的参数,而不是C++类型的参数,比如传入的参数是字符串message,则变量类型是jstring 而不是 c++的string类型
env->CallVoidMethod(myObj, instanceMethodID, message);
//处理异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
//调用静态方法传入的是类 而不是对象
number = env->CallStaticIntMethod(clazz, staticMethodID, 42);
// 处理异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
// 返回结果
return number;
完整代码
jint getNumber(JNIEnv *env, jobject /* this */) {
int number = 0;
//第一步 通过env找到Java类
jclass clazz = env->FindClass("com/marxist/firstjni/MyClass");
if (!clazz) {
std::cerr << "Failed to find class" << std::endl;
return -1;
}
//第二步 获取实例方法ID 获取静态方法ID
jmethodID instanceMethodID = env->GetMethodID(clazz, "instanceMethod", "(Ljava/lang/String;)V");
if (!instanceMethodID) {
std::cerr << "Failed to get method ID for instanceMethod" << std::endl;
return -1;
}
jmethodID staticMethodID = env->GetStaticMethodID(clazz, "staticMethod", "(I)I");
if (!staticMethodID) {
std::cerr << "Failed to get method ID for staticMethodID" << std::endl;
return -1;
}
//第三步 创建对象 有两种方式,1,立即申请对象并初始化 使用NewObject 必须要传入构造参数 2、alloc 分配内存,但先不初始化
jstring message = env->NewStringUTF("Hello from myClass message");
jobject myObj = env->AllocObject(clazz);
//第四步 调用方法
env->CallVoidMethod(myObj, instanceMethodID, message);
//处理异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
//调用静态方法传入的是类 而不是对象
number = env->CallStaticIntMethod(clazz, staticMethodID, 42);
// 处理异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
// 返回结果
return number;
}