Kotlin调用JNI笔记总结

基本概要

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;
}

  • 37
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值