基本概要
JNIEnv作用说明
访问 Java 对象和类:JNIEnv
可以获取 Java 对象的引用、获取 Java 类的引用,以及访问 Java 对象的字段和方法。通过 JNIEnv
,本地方法可以操作 Java 对象的属性和行为。
调用 Java 方法:JNIEnv
提供了一系列的 Call<Type>Method
函数,可以在本地方法中调用 Java 对象的实例方法,并获取其返回值。例如,CallIntMethod
可以调用返回 int
类型值的 Java 方法。
创建和操作 Java 对象:JNIEnv
提供了函数用于创建新的 Java 对象、访问对象的字段、调用对象的方法等。通过这些函数,本地方法可以在本地代码中操作 Java 对象。
异常处理:JNIEnv
可以检查是否有 Java 异常抛出,并提供了函数来处理和清除异常。本地方法可以通过 JNIEnv
处理 Java 代码中抛出的异常。
字符串操作:JNIEnv
提供了函数用于创建、操作和释放 Java 字符串。本地方法可以使用 JNIEnv
处理 Java 字符串,例如获取字符串的 UTF-8 编码。
数组操作:JNIEnv
提供了函数用于创建、操作和释放 Java 数组。本地方法可以通过 JNIEnv
处理 Java 数组,例如获取数组的元素或设置数组的元素值。
总的来说,JNIEnv
提供了一系列函数和操作,使得本地方法能够与 Java 代码进行交互,访问 Java 对象和类,调用 Java 方法,处理异常,操作字符串和数组等。
Kotlin与JNI类型对应列表
调用实例
Kotlin对Native部分调用
Kotlin部分代码
class MainActivity : AppCompatActivity() {
companion object {
// Used to load the 'myapplication' library on application startup.
init {
System.loadLibrary("myapplication")
}
}
/**
* A native method that is implemented by the 'myapplication' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Example of a call to a native method
binding.sampleText.text = stringFromJNI()
}
}
Navtive部分代码
extern "C" JNIEXPORT jstring
JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject mainActivityThis) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
Native代码说明
extern "C"
:这是一个 C++ 中的语法,用于指示编译器将下面的函数名按照 C 语言的命名规则进行处理,即不进行名称修饰(name mangling)。在 JNI 中,由于 JNI 函数是用 C 语言编写的,因此需要通过extern "C"
来明确告诉 C++ 编译器,这些函数遵循 C 语言的命名规则,以便 JNI 可以正确地调用它们。JNIEXPORT
:这是一个宏,在 JNI 中用于标记一个函数是 JNI 函数,以便 JNI 可以正确地识别和使用它。在 JNI 的头文件jni.h
中,JNIEXPORT
被定义为__attribute__((visibility ("default")))
,用于指示编译器将函数标记为默认的可见性,以便 JNI 可以在动态链接时正确地导出函数。jstring
:这是 JNI 中表示 Java 字符串的类型。在 JNI 中,Java 的对象类型都是以j
开头的,表示它们是 JNI 提供的数据类型。jstring
表示一个 Java 字符串。更多类型查看Kotlin与JNI类型对应列表。JNICALL
:这是一个宏,在 JNI 中用于标记一个函数的调用约定。在 JNI 的头文件jni.h
中,JNICALL
被定义为空,它的作用主要是为了更好地可读性,提示这是一个 JNI 函数的声明。有些系统不定义是会出错的,如windows。
Native对Java的调用
加载kotlin类实例并调用
例1:无参,返回是引用类型
class MyKotlinClass {
fun sayHello(): String {
return "Hello from Kotlin!"
}
}
#include <jni.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_MyNativeClass_callKotlinMethod(JNIEnv *env, jobject thiz) {
// 加载 Kotlin 类的类引用
jclass kotlinClass = env->FindClass("com/example/MyKotlinClass");
if (kotlinClass == nullptr) {
return env->NewStringUTF("Kotlin class not found!");
}
// 获取 Kotlin 方法的方法 ID
jmethodID methodID = env->GetMethodID(kotlinClass, "sayHello", "()Ljava/lang/String;");
if (methodID == nullptr) {
return env->NewStringUTF("Kotlin method not found!");
}
// 创建 Kotlin 类的实例并调用方法
jobject kotlinObj = env->AllocObject(kotlinClass);
if (kotlinObj == nullptr) {
return env->NewStringUTF("Failed to create Kotlin object!");
}
jstring result = (jstring) env->CallObjectMethod(kotlinObj, methodID);
// 返回方法调用的结果
return result;
}
例2:参数是基本类型,返回也是基本类型
class MyKotlinClass {
fun add(a: Int, b: Int): Int {
return a + b
}
}
#include <jni.h>
extern "C" JNIEXPORT jint JNICALL
Java_com_example_MyNativeClass_callKotlinMethodWithArgs(JNIEnv *env, jobject thiz, jint a, jint b) {
// 加载 Kotlin 类的类引用
jclass kotlinClass = env->FindClass("com/example/MyKotlinClass");
if (kotlinClass == nullptr) {
return -1; // 如果找不到类,则返回一个错误码
}
// 获取 Kotlin 方法的方法 ID
jmethodID methodID = env->GetMethodID(kotlinClass, "add", "(II)I");
if (methodID == nullptr) {
return -1; // 如果找不到方法,则返回一个错误码
}
// 创建 Kotlin 类的实例
jobject kotlinObj = env->AllocObject(kotlinClass);
if (kotlinObj == nullptr) {
return -1; // 如果创建实例失败,则返回一个错误码
}
// 调用 Kotlin 方法
jint result = env->CallIntMethod(kotlinObj, methodID, a, b);
// 返回方法调用的结果
return result;
}
例3:参数是引用类型,返回也是引用类型
class MyKotlinClass {
fun concatenate(str1: String, str2: String): String {
return str1 + str2
}
}
#include <jni.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_MyNativeClass_callKotlinMethodWithArgs(JNIEnv *env, jobject thiz, jstring str1, jstring str2) {
// 将 jstring 转换为 char* 类型
const char *nativeString1 = env->GetStringUTFChars(str1, nullptr);
const char *nativeString2 = env->GetStringUTFChars(str2, nullptr);
if (nativeString1 == nullptr || nativeString2 == nullptr) {
return nullptr; // 如果转换失败,则返回空指针
}
// 加载 Kotlin 类的类引用
jclass kotlinClass = env->FindClass("com/example/MyKotlinClass");
if (kotlinClass == nullptr) {
return nullptr; // 如果找不到类,则返回空指针
}
// 获取 Kotlin 方法的方法 ID
jmethodID methodID = env->GetMethodID(kotlinClass, "concatenate", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
if (methodID == nullptr) {
return nullptr; // 如果找不到方法,则返回空指针
}
// 创建 Kotlin 类的实例
jobject kotlinObj = env->AllocObject(kotlinClass);
if (kotlinObj == nullptr) {
return nullptr; // 如果创建实例失败,则返回空指针
}
// 调用 Kotlin 方法
jstring result = (jstring)env->CallObjectMethod(kotlinObj, methodID, str1, str2);
// 释放 char* 类型的字符串
env->ReleaseStringUTFChars(str1, nativeString1);
env->ReleaseStringUTFChars(str2, nativeString2);
// 返回方法调用的结果
return result;
}
调用TOP方法
package com.example
fun add(a: Int, b: Int): Int {
return a + b
}
#include <jni.h>
extern "C" JNIEXPORT jint JNICALL
Java_com_example_MyNativeClass_callKotlinTopFunction(JNIEnv *env, jobject thiz, jint a, jint b) {
// 加载 Kotlin 文件中的类引用
jclass kotlinFileClass = env->FindClass("com/example/MyKotlinFileKt");
if (kotlinFileClass == nullptr) {
return -1; // 如果找不到类,则返回一个错误码
}
// 获取 Kotlin 顶级函数的方法 ID
jmethodID methodID = env->GetStaticMethodID(kotlinFileClass, "add", "(II)I");
if (methodID == nullptr) {
return -1; // 如果找不到方法,则返回一个错误码
}
// 调用 Kotlin 顶级函数
jint result = env->CallStaticIntMethod(kotlinFileClass, methodID, a, b);
// 返回方法调用的结果
return result;
}
调用伴生方法
package com.example
class MyKotlinClass {
companion object {
fun multiply(a: Int, b: Int): Int {
return a * b
}
}
}
#include <jni.h>
extern "C" JNIEXPORT jint JNICALL
Java_com_example_MyNativeClass_callKotlinCompanionMethod(JNIEnv *env, jobject thiz, jint a, jint b) {
// 加载 Kotlin 类的类引用
jclass kotlinClass = env->FindClass("com/example/MyKotlinClass$Companion");
if (kotlinClass == nullptr) {
return -1; // 如果找不到类,则返回一个错误码
}
// 获取 Kotlin 伴生对象方法的方法 ID
jmethodID methodID = env->GetStaticMethodID(kotlinClass, "multiply", "(II)I");
if (methodID == nullptr) {
return -1; // 如果找不到方法,则返回一个错误码
}
// 调用 Kotlin 伴生对象方法
jint result = env->CallStaticIntMethod(kotlinClass, methodID, a, b);
// 返回方法调用的结果
return result;
}