ndk c++调java

转载 这位同学的这两篇文章挺好,讲清楚了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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值