You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JNI从Rust向Android返回布尔值与字符串Pair

JNI实现Rust向Android返回Pair<Boolean, String>的解决方案

问题背景

我开发了一个基于Kotlin的Android应用,核心处理逻辑由Rust编写,通过JNI通信。原本已实现Rust向Android返回单个bool值,现在需要扩展为同时返回bool和string类型数据,将Kotlin端函数返回类型改为Pair<Boolean, String>后,应用崩溃,报错panic_abort和(core::result::unwrap_failed::h5cd03753bd6180f5+88)。

崩溃原因分析

  1. 返回类型不匹配:Rust端函数签名仍保留原返回类型jboolean,但实际需要返回jobject类型的Pair对象,类型不匹配触发错误。
  2. 基本类型直接转Object错误:Pair构造函数接收的是Object类型参数,直接将jboolean(基本类型)转为jobject传入,会导致JVM类型校验失败,触发panic。

正确实现步骤

1. Android(Kotlin)端代码(保持现有修改)

Kotlin端的函数声明和调用逻辑无需调整,已匹配需求:

package eu.mypackage.rust

class SomeName {
    @Throws(IllegalArgumentException::class)
    external fun checkAnswer(answerInput: String, answerList: Array<String>): Pair<Boolean, String>
}

调用代码:

fun processAnswer(answerInput: String, answerList: List<String>): Int {
    val (isCorrect, corrected_answer) = sn.checkAnswer(answerInput, answerList.toTypedArray())
    // 后续业务逻辑
}

2. Rust端代码修正

2.1 修改函数签名返回类型

将JNI函数的返回类型从jboolean改为jobject,匹配Pair对象类型:

pub extern "system" fn Java_eu_mycompany_rust_MyPackage_checkAnswer<'local>(
    mut env: JNIEnv<'local>,
     _class: JClass<'local>,
    answerInput: JString<'local>,
    answerList: JObjectArray<'local>,
) -> jobject  // 替换原jboolean

2.2 完整Rust实现代码

核心修正点:将基本类型jboolean通过Boolean.valueOf()转为包装类对象,再传入Pair构造函数:

#[cfg(target_os = "android")]
#[allow(non_snake_case)]
pub mod android {
    extern crate jni;

    use self::jni::JNIEnv;
    use self::jni::objects::{JClass, JString, JObjectArray, JObject};
    use self::jni::sys::{jstring, jboolean, jobject};

    #[no_mangle]
    pub extern "system" fn Java_eu_mycompany_rust_MyPackage_checkAnswer<'local>(
        mut env: JNIEnv<'local>,
         _class: JClass<'local>,
        answerInput: JString<'local>,
        answerList: JObjectArray<'local>,
    ) -> jobject
    {
        // 1. 解析输入参数为Rust类型
        let answer_input: String = env.get_string(&answerInput).expect("Failed to get input string").into();
        let answer_list = kotlin_list_to_rust_vec_string(&mut env, &answerList);

        // 2. 执行核心业务逻辑
        let (is_correct, corrected_answer) = answer_in_answer_list(&answer_input, &answer_list);

        // 3. 将布尔值转为Java Boolean包装对象
        let j_is_correct: jboolean = if is_correct { 1 } else { 0 };
        let j_is_correct_obj = env
            .call_static_method(
                "java/lang/Boolean",
                "valueOf",
                "(Z)Ljava/lang/Boolean;",
                &[j_is_correct.into()],
            )
            .expect("Failed to call Boolean.valueOf()")
            .l()
            .expect("Boolean.valueOf() returned null");

        // 4. 将Rust字符串转为Java String
        let j_corrected_answer = match corrected_answer {
            Some(s) => env.new_string(&s).expect("Failed to create Java string"),
            None => env.new_string("").expect("Failed to create empty Java string")
        };

        // 5. 创建Android Pair对象并返回
        let result_pair = env
            .new_object(
                "android/util/Pair",
                "(Ljava/lang/Object;Ljava/lang/Object;)V",
                &[j_is_correct_obj.into(), (&j_corrected_answer).into()],
            )
            .expect("Failed to create Pair object");

        result_pair.into_raw()
    }

    // 辅助函数:将Kotlin字符串数组转为Rust Vec<String>
    fn kotlin_list_to_rust_vec_string(env: &mut JNIEnv, array: &JObjectArray) -> Vec<String> {
        let len = env.get_array_length(array).unwrap();
        (0..len)
            .map(|i| {
                let jstr: JString = env.get_object_array_element(array, i).unwrap().into();
                env.get_string(&jstr).unwrap().into()
            })
            .collect()
    }

    // 核心业务逻辑示例
    fn answer_in_answer_list(answer_input: &String, answer_list: &Vec<String>) -> (bool, Option<&String>) {
        let is_correct = answer_list.contains(answer_input);
        let corrected_answer = if !is_correct { answer_list.first() } else { None };
        (is_correct, corrected_answer)
    }
}

关键注意事项

  • 类型严格匹配:JNI函数返回类型必须与Kotlin声明的返回类型对应,返回Pair时必须返回jobject。
  • 基本类型包装:Java泛型容器(如Pair)仅支持Object类型,必须将基本类型(boolean、int等)转为对应的包装类(Boolean、Integer)。
  • 异常处理优化:示例中使用expect触发panic,生产环境可改为捕获错误并通过JNI抛出异常给Kotlin端处理,避免应用崩溃。

内容的提问来源于stack exchange,提问作者NumesSanguis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:10:54