jni第一个案例
环境配置
- android gradle.kts
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.18.1"
}
}
- CMakeLists.txt
#cmake使用的版本 最低版本
cmake_minimum_required(VERSION 3.4.1)
# 项目名称
project("calculator")
# 库名字 以及cpp文件
# SHARED 生成动态库。 必须大写
add_library(
"nativeTools"
SHARED
"calculator.cpp"
)
# 使用的库
find_library(log-lib log)
#连接到一起
target_link_libraries(
nativeTools
# calculator
${log-lib}
)
- cpp代码
#include <jni.h>
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_calculator_jni_JniController_add(JNIEnv *env, jobject thiz, jint a, jint b) {
// TODO: implement add()
return a + b;
}
- java
public native int add(int a, int b);
- JNIEnv每个线程一个
- thiz:旨在每次有效,本身是一个localRef
类型映射
| java | JNI |
|---|---|
| int | jint |
| double | jdouble |
| boolean | jboolean |
| String | jstring |
转换
- java->C++
const char* cstr = env->GetStringUTFChars(jstr,nullptr);
env->RealseStringUTFChars(jstr,cstr);
- c++->java
jstring result = env->NewStringUTF(cstr);
- c++->c
result.c_str()
- 总
env->NewStringUTF(nativeString);
std::string strx = "xxxxxxxxxxxxx";
env->NewStringUTF(strx.c_str());
- 容易出问题
for (int i = 0; i < 10000; i++) {
jstring str = env->NewStringUTF("xxx");
}
jni局部表会溢出
jni调用java
- 找到class
- 找到方法
- 调用
方法的签名规则
| java | Jni |
|---|---|
| void test() | ()V |
| int add() | ()I |
| String getName() | ()Ljava/lang/String |
| void print(String msg) | (Ljava/lang/String;)V |
| void add(int a,String b) | (ILjava/lang/String;)V |
返回值类型表
| Java | JNI |
|---|---|
| int | I |
| boolean | Z |
| long | J |
| float | F |
| double | D |
| String | Ljava/lang/String; |
| void | V |
调用
extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_Calculator_callJava(
JNIEnv* env,
jobject thiz,
jobject student) {
jclass cls =
env->GetObjectClass(student);
jmethodID method =
env->GetMethodID(
cls,
"sayHello",
"()V");
env->CallVoidMethod(
student,
method);
}
| Java返回值 | JNI调用 |
|---|---|
| void | CallVoidMethod |
| int | CallIntMethod |
| long | CallLongMethod |
| boolean | CallBooleanMethod |
| float | CallFloatMethod |
| double | CallDoubleMethod |
| String/Object | CallObjectMethod |
创建对象并字段操作
创建对象
找到class,获取初始化方法,创建对象
- 找到class
jclass cls = env->FindClass("com/example/Person");
- 获取方法
jmethodID constructor =
env->GetMethodID(
cls,
"<init>",
"()V");
- 创建对象
jobject obj =
env->NewObject(
cls,
constructor);
操作字段
找到class,找到methodid,
- 找到class
jclass cls = env->GetObjectClass(person);
- 找到字段
jfieldID nameField =
env->GetFieldID(cls, "name","Ljava/lang/String;");
- 读取和设置
// 读取
jstring name =
(jstring) env->GetObjectField(person, nameField);
jint age =
env->GetIntField(person, ageField);
// 修改
env->SetObjectField(
person,
nameField,
env->NewStringUTF("JNI Changed"));
局部变量和全局变量
方法内的都是局部变量,比如jobject obj = thiz;局部变量,如果想全局使用需要使用env->NewGlobalRef()
局部的生命周期:
- jni开始->创建
- jni结束->销毁
全局
JNI开始->创建->JNI结束->仍然存在->DeleteGlobalRef->释放