当前位置:网站首页>Getting Started with JNI
Getting Started with JNI
2022-08-11 06:35:00 【rest of my life love static】
JNIData types and ANDJava数据类型的映射关系
Java数据类型 | JNI数据类型 |
---|---|
byte | jbyte |
char | jchar |
short | jshort |
int | jint |
long | jlong |
float | jfloat |
double | jdouble |
javaThe correspondence between data types and signature types
Java类型 | 类型签名 |
---|---|
boolean | Z |
byte | B |
int | I |
char | C |
short | S |
long | L |
float | F |
double | D |
void | V |
数组 | [类型签名,比如String[] 是[Ljava/lang/String; |
类 | L全限定名;,比如String, 其签名为Ljava/lang/String;(Note the semicolon after it) |
Static registration function
根据函数名来建立 java 方法与 JNI 函数的一一对应关系;
命名规则如下:Java+方法的全路径(must be used in the path“_”代替Javain the full path"“.”)
在MainActivity里面定义了一个native方法:
public native String stringFromJNI();
Follow the naming rules,JNIThe layer's function is registered as :
extern "C" JNIEXPORT jstring JNICALL
Java_com_anniljing_jnidemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
LOGD("Get native message success");
return env->NewStringUTF(hello.c_str());
}
动态注册函数
原理:利用 RegisterNatives 方法来注册 java 方法与 JNI 函数的一一对应关系;
实现流程:
1、实现 JNI_OnLoad 方法,该方法在jni.h的头文件中定义,which also definesJNI_OnUnload方法,在加载动态库后,执行动态注册;
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
}
2、调用 FindClass 方法,获取 java 对象;
jclass jcls;
jcls = env->FindClass(name);
if (jcls == nullptr) {
return JNI_FALSE;
}
3、利用结构体 JNINativeMethod 数组记录 java 方法与 JNI 函数的对应关系;
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
name为java层的方法名,signature为javaThe type signature of the layer's parameters and return value,fnPtr为jni层方法名
static JNINativeMethod gMethods[] = {
{"sum", "(II)I", (void *) sum},
{"getNativeString", "()Ljava/lang/String;", (void *) getMessage}
};
4、调用 RegisterNatives 方法,传入 java 对象,以及 JNINativeMethod 数组,以及注册数目完成注册;
if (env->RegisterNatives(jcls, methods, nMethods) < 0) {
return JNI_FALSE;
}
JNI层访问JavaLayer class properties
JNI获取属性方法 | 含义 |
---|---|
GetFieldID(jclass clazz, const char* name, const char* sig) | 获取属性Id,形参:clazz-java类,name-java类属性名,sig-java类属性类型签名 |
GetObjectField(jobject obj, jfieldID fieldID) | Get the property as an object |
GetBooleanField(jobject obj, jfieldID fieldID) | Gets a property of type boolean |
GetByteField(jobject obj, jfieldID fieldID) | 获取类型为byte的属性 |
GetCharField(jobject obj, jfieldID fieldID) | 获取类型为Char的属性 |
GetShortField(jobject obj, jfieldID fieldID) | 获取类型为Short的属性 |
GetIntField(jobject obj, jfieldID fieldID) | 获取类型为Int的属性 |
GetLongField(jobject obj, jfieldID fieldID) | 获取类型为long的属性 |
GetFloatField(jobject obj, jfieldID fieldID) | 获取类型为float的属性 |
GetDoubleField(jobject obj, jfieldID fieldID) | 获取类型为double的属性 |
JNI层设置JavaLayer class attribute value
JNI设置属性方法 | 含义 |
---|---|
SetObjectField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Object的属性值 |
SetBooleanField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Boolean的属性值 |
SetByteField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Byte的属性值 |
SetCharField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Char的属性值 |
SetShortField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Short的属性值 |
SetIntField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Int的属性值 |
SetLongField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Long的属性值 |
SetFloatField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Float的属性值 |
SetDoubleField(jobject obj, jfieldID fieldID, jobject value) | 设置类型为Double的属性值 |
第一步、获取到Java类
jclass jc = env->GetObjectClass(people);
第二步、GetFieldID方法获取到JavaLayer class properties
jfieldID fidAge = env->GetFieldID(jc, "age", "I");
第三步、调用SetXXXField()方法,为javaThe layer's class attribute sets the value
env->SetIntField(people, fidAge, 18);
JNI层访问JavaLayer class member methods
第一步、获取Java类
jclass jc = env->GetObjectClass(people);
第二步、调用GetMethodID()方法,获取jMethodID
jmethodID jMethod = env->GetMethodID(jc, "doIntroduce", "()V");
第三步、调用CallVoidMethod()方法,调用Java类成员方法
env->CallVoidMethod(people, jMethod);
问题1:新增加的AndroidLog.hThe header files have been unable to be precompiled<android/log.h>和<jni.h>头文件
解决方法:
先创建空的AndroidLog.h文件,然后在其他的cppSource files are added to their precompiled header files,重新编译一下,AndroidLogThe header files are then re-added to the relevant header files,编译即可通过
问题2:新增加jni_dynamic_load.cpp,实现动态注册jni,CMakeList.txt的编写如下:
新增了如下代码:
add_library(
dynamicLoad-lib
SHARED
jni_dynamic_load.cpp
)
但是编译的时候,throw beforeAndroidLog.hFile undefined exception
解决方法:
1、把jni_dynamic_load.cpp放到 native-lib里面,CMakeList.txt如下:
cmake_minimum_required(VERSION 3.10.2)
project("jnidemo")
add_library(
native-lib
SHARED
native-lib.cpp
jni_dynamic_load.cpp
)
find_library(
log-lib
log
)
include_directories(${CMAKE_HOME_DIRECTORY}/base)
target_link_libraries(
native-lib
${log-lib})
这样的话,in a library.
2、But this is not the effect I wanted at first,I am trying to generate two libraries.The reason must be that there is a problem where the library is linked,于是CMakeList.txt改为如下内容:
cmake_minimum_required(VERSION 3.10.2)
project("jnidemo")
add_library(
native-lib
SHARED
native-lib.cpp
)
add_library(
dynamicLoad-lib
SHARED
jni_dynamic_load.cpp
)
find_library(
log-lib
log
)
include_directories(${CMAKE_HOME_DIRECTORY}/base)
target_link_libraries(
native-lib
${log-lib})
target_link_libraries(
dynamicLoad-lib
${log-lib}
)
The core code is the second one at the bottomtarget_link_libraries,就是做了dynamicLoad-lib库与Log库的连接.
target_link_libraries(
dynamicLoad-lib
${log-lib}
问题3:illegal class name
cppThe file is not recognized“.”的路径,要把“.”换成“/”即可
#define JAVA_CLASS "com/anniljing/jnidemo/JniDynamicLoad"
边栏推荐
猜你喜欢
随机推荐
OpenMLDB官网升级,神秘贡献者地图带你快速进阶
gerrit configure SSH Key and account, email information
品优购项目实战笔记
USB URB
Regular expression replacement for batch quick modification code
The whole process of Tinker access --- Compilation
JS进阶网页特效(pink老师笔记)
栈stack
STM32F407-浅~~析UART异步通信&USART_Init函数入口参数
stack stack
JNI入门
Interpretation of the paper: GAN and detection network multi-task/SOD-MTGAN: Small Object Detection via Multi-Task Generative Adversarial Network
promise 改变状态的方法和promise 的then方法
论文解读TransFG: A Transformer Architecture for Fine-grained Recognition
mount命令--挂载出现只读,解决方案
C语言实现简易扫雷(附带源码)
Scene-driven feature calculation method OpenMLDB, efficient implementation of "calculate first use"
无效的修订:3.18.1-g262b901-dirty
哥德巴赫猜想与整数环
Tinker's self-introduction