当前位置:网站首页>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"
边栏推荐
- JVM tuning and finishing
- [Meetup] OpenMLDBxDolphinScheduler engineering and scheduling link link characteristics, building the end-to-end MLOps workflow
- 2021-09-11 C language variables and memory allocation
- Scene-driven feature calculation method OpenMLDB, efficient implementation of "calculate first use"
- 微信小程序_开发工具的安装
- 开源之夏 2022 火热来袭 | 欢迎报名 OpenMLDB 社区项目~
- Use the adb command to manage applications
- 经纬度求距离
- C language implementation guess Numbers (with source code, can be directly run)
- js learning advanced BOM part (pink teacher notes)
猜你喜欢

经纬度求距离

vscode插件开发——代码提示、代码补全、代码分析(续)

OpenMLDB Pulsar Connector:高效打通实时数据到特征工程

gerrit 配置SSH Key和账号、邮箱信息

ARM 汇编指令 ADR 与 LDR 使用

The Summer of Open Source 2022 is coming | Welcome to sign up for the OpenMLDB community project~

8-byte standard request parsing during USB enumeration

127.0.0.1 connection refused

JS advanced web page special effects (pink teacher notes)

STM32-串口常用寄存器和库函数及配置串口步骤
随机推荐
Simple mine sweeping in C language (with source code)
论文解读TransFG: A Transformer Architecture for Fine-grained Recognition
openlayer中实现截图框截图的功能
Thesis unscramble TransFG: A Transformer Architecture for Fine - grained Recognition
Building a data ecology for feature engineering - Embrace the open source ecology, OpenMLDB fully opens up the MLOps ecological tool chain
SearchGuard配置
js learning advanced (event senior pink teacher teaching notes)
关于openlayer中swipe位置偏移的问题
umi约定式路由规则修改
PAT乙级刷题之路
STM32F407-浅~~析UART异步通信&USART_Init函数入口参数
Compilation exception resolution
mount命令--挂载出现只读,解决方案
Day 82
批量快速修改代码的正则表达式替换
SearchGuard configuration
STM32学习笔记(白话文理解版)—外部IO中断实验
Day 79
Argparse模块 学习
helm安装