转载 这位同学的这两篇文章挺好,讲清楚了c++调java 结合一个github一个开源ndk demo例子
https://blog.csdn.net/lyh1299259684/article/details/79430413
https://blog.csdn.net/lyh1299259684/article/details/79438802
https://blog.csdn.net/lyh1299259684/article/details/79476530
https://github.com/whcbx/AndroidJNIDemo
1.什么是JNI,什么是NDK。
jni的全称是java native interface (java本地接口),它是一个标准,是C/C++ 和 java 通信的一个桥梁,ndk它是一个配合jni的开发工具包。
2.JNI的优缺点
优点:运算效率高,安全性高(C/C++的代码不容易被反编译),可以运用大量优秀的C/C++语言库
缺点:对开发人员的要求高,在一定程度上限制了java的跨平台能力,JNI虽然依附于JVM但是有一部分是脱离JVM运行的。
3.JNI中方法格式
void Java_com_gavinandre_rtsplibrary_RtspClient_stop(JNIEnv *env, jobject)
4.不同情况下的native函数,对jobject的定义
1) 当native函数不是静态的时候,jobject对应的是java中调用该函数的对象(也就是this)
2) 当native函数是静态的时候, jobject对应的是调用此函数的class对象(类对象)
5.JNI的基本数据类型和引用类型
c数据类型 JNI数据类型 解释
uint8_t jboolean; /* unsigned 8 bits */
int8_t jbyte; /* signed 8 bits */
uint16_t jchar; /* unsigned 16 bits */
int16_t jshort; /* signed 16 bits */
int32_t jint; /* signed 32 bits */
int64_t jlong; /* signed 64 bits */
float jfloat; /* 32-bit IEEE 754 */
double jdouble; /* 64-bit IEEE 754 */
jobject 任何java对象,包括没有对应类的java对象
jclass java中的class对象
jstring 字符串类对象
jarray 对应任何类型的数组
_jobjectArray * jobjectArray;
_jbooleanArray * jbooleanArra
_jbyteArray * jbyteArray;
_jcharArray * jcharArray;
_jshortArray * jshortArray;
_jintArray * jintArray;
_jlongArray * jlongArray;
_jfloatArray * jfloatArray;
_jdoubleArray * jdoubleArray;
_jthrowable * jthrowable;
_jobject * jweak;
6.JNI中java类型的签名对照表
java类型 签名
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
object L完整的类名; 例如 Ljava/lang/String;
array [数组的数据类型 例如:int[] [I double[][] [[D
method (参数类型)返回值类型 例如:int getNumber(int a, int b) -> (II)I
public interface NativeCallback {
void onFrame(byte[] frame, int nChannel, int width, int height);
}
gCallbackMethodId = env->GetMethodID(clz, "onFrame", "([BIII)V");
------------------------------java----------------------------------------
package com.koimy;
public class Main {
int num = 123;
static {
System.loadLibrary("NativeCode");
}
public native void sayHello();
public int getMax(int num1, int num2) {
return num1 > num2 ? num1 : num2;
}
public static void main(String[] args) {
Main main = new Main();
main.sayHello();
System.out.println("Java: 这是Java输出得num = " + main.num);
}
}
------------------------------jni-----------------------------------------------
#include<iostream>
#include"com_koimy_Main.h"
using namespace std;
JNIEXPORT void JNICALL Java_com_koimy_Main_sayHello (JNIEnv *env, jobject obj)
{
// cout<<"This message is from JNI by C++!"<<endl;
jclass class_nativecode = env->GetObjectClass(obj);
//===========================c/c++调用Java类得属性==========================================
jfieldID id_num = env->GetFieldID(class_nativecode,"num","I");
//拿到java层调用sayHello的类对象class_nativecode 调这个类的成员num 和方法 getMax num的类型是int GetFieldID的签名用I 表示,getMax 返回值int 形参类型 int int,所以GetMethodID的签名是(II)I
jint num = env->GetIntField(obj,id_num);
cout<<"C++: num = "<<num<<endl;
env->SetIntField(obj,id_num,666L);
//===========================c/c++调用Java类的方法==========================================
jmethodID id_getmax = env->GetMethodID(class_nativecode,"getMax","(II)I");
jint max = env->CallIntMethod(obj,id_getmax,100L,36L);
cout<<"C++: max = "<<max<<endl;
}
调用属性和方法的步骤:
1.获得jclass
2.获得 jfiledID/ jmethodID GetFieldID() GetMthordID //原型参考下面
3.通过env调用 set<TYPE>Field() 或者调用Call<Type>Method();
7.C/C++函数分析:
//获取jclass对象,参数:this的意思,就是native方法所在的类
1.GetObjectClass(jobject)
//获取普通属性id,第一个参数:类对象, 第二个参数:属性名,第三个参数:属性签名(不知道的同学点击这里)
2.GetFieldID(jclass clazz, const char* name, const char* sig)
//设置int属性的值, 第一个参数:this的意思, 第二个参数:获取属性id, 第三个参数:要设置的值
3.SetIntField(jobject obj, jfieldID fieldID, jint value)
当然这里就只列举SetIntField函数了,同理还有很多,比如:SetCharField,SetFloatField,SetObjectField ......。有Set函数肯定也会有Get函数,与之对应的就是GetIntField(jobject obj, jfieldID fieldID),这个函数是获取指定属性的值,参数含义同SetIntField函数
//获取静态属性Id, 第一个参数:类对象, 第二个参数: 属性名, 第三个参数: 属性签名
4.GetStaticFieldID(jclass clazz, const char* name, const char* sig)
//设置静态属性的值, 第一个参数: 类对象, 第二个参数: 属性id, 第三个参数: 要设置的值
5.SetStaticIntField(jclass clazz, jfieldID fieldID, jint value)
//获取函数id, 第一参数:类对象, 第二个参数:函数名, 第三个参数: 函数签名(不知道的同学点击这里)
6.GetMethodID(jclass clazz, const char* name, const char* sig)
//调用java中的无返回值函数, 第一个参数: this的意思, 第二个参数: 函数id, 第三个参数:需要传入的实参
7.CallVoidMethod(jobject obj, jmethodID methodID, ...)
//获取静态函数id, 第一个参数: 类对象, 第二个参数: 函数名, 第三个参数: 函数签名
8.GetStaticMethodID(jclass clazz, const char* name, const char* sig)
//调用java中无返回值的静态函数, 第一个参数: 类对象, 第二个参数: 函数id, 第三个参数: 需要传入的实参
9.CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
//生成一个jstring类型的方法转换,该方法会返回一个jstring类型
10.NewStringUTF(const char* bytes)
//调用java中的对象类型(String类型被认为对象类型),第一参数:this的意思, 第二个参数:函数Id, 第三个参数:需要传入的实参
11.CallObjectMethod(jobject, jmethodID, ...);
//获取类中的对象属性,第一个参数:this的意思 , 第二个参数:属性id
12.GetObjectField(jobject obj, jfieldID fieldID)
//根据子类的类对象,获取父类的类对象, 第一参数:子类类对象
13.GetSuperclass(jclass clazz)
//调用java中父类的方法,第一个参数:子类的对象, 第二个参数:父类的类对象, 第三个参数:父类的函数id, 第四个参数:需要传入的实参
14.CallNonvirtualVoidMethod(jobject obj, jclass clazz, jmethodID methodID, ...)
Java_com_liyahong_jni_1field_1method_MainActivity_stringFromJNI(
JNIEnv *env, jobject jobj) {
//修改普通成员变量
jclass jclazz = env->GetObjectClass(jobj);
jfieldID jfieilId = env->GetFieldID(jclazz, "anInt", "I");
jint anInt = 35;
env->SetIntField(jobj, jfieilId, anInt);
//修改静态成员变量
jfieldID jstaticFieldId = env->GetStaticFieldID(jclazz, "anIntS", "I");
env->SetStaticIntField(jclazz, jstaticFieldId, 55);
//通过jni调用普通java方法
jmethodID jmethodId = env->GetMethodID(jclazz, "test", "()V");
env->CallVoidMethod(jobj, jmethodId);
//通过jni调用静态java方法
jmethodID jstaticMethodId = env->GetStaticMethodID(jclazz, "staticTest", "(I)V");
env->CallStaticVoidMethod(jclazz, jstaticMethodId, 55);
//通过jni调用java中带参方法
jmethodID methodId = env->GetMethodID(jclazz, "test", "(ILjava/lang/String;)Ljava/lang/String;");
jstring str = env->NewStringUTF("小丽");
env->CallObjectMethod(jobj, methodId, 18, str);
//通过jni调用其他类中的方法
jfieldID sonJfieldId = env->GetFieldID(jclazz, "son", "Lcom/liyahong/jni_field_method/Son;");
jobject sonJobj = env->GetObjectField(jobj, sonJfieldId);
jclass sonClazz = env->GetObjectClass(sonJobj);
jmethodID sonMethodId = env->GetMethodID(sonClazz, "ride", "()V");
env->CallVoidMethod(sonJobj, sonMethodId);
//通过jni调用父类中的方法
jclass jfatherClazz = env->GetSuperclass(sonClazz);
jmethodID jfatherMethodId = env->GetMethodID(jfatherClazz, "ride", "()V");
env->CallNonvirtualVoidMethod(sonJobj, jfatherClazz, jfatherMethodId);
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
NewGlobalRef 未完待续。。。
DeleteLocalRef