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

Android中Rust库调用JNI_GetCreatedJavaVMs符号缺失问题求助

解决Android Rust库中获取JavaVM引用的问题

直接调用JNI_GetCreatedJavaVMs出现符号找不到的问题,本质是Android平台下该函数的符号不属于默认链接的系统库,且手动加载libjvm、libdvm等系统库会带来兼容性风险(不同版本/设备的库路径、符号可能不一致)。更可靠的方案是在JNI库加载时通过JNI_OnLoad保存JavaVM引用,这是Android JNI的标准实践。

具体实现步骤

  1. 定义静态变量存储JavaVM引用
    使用原子指针保证跨线程安全访问:

    use std::sync::atomic::{AtomicPtr, Ordering};
    use jni::JavaVM;
    
    static JAVA_VM: AtomicPtr<JavaVM> = AtomicPtr::new(std::ptr::null_mut());
    
  2. 实现JNI_OnLoad函数保存JavaVM
    当你的Rust库被Android系统加载时,会自动调用JNI_OnLoad,此时可以直接获取并保存JavaVM实例:

    #[no_mangle]
    pub extern "system" fn JNI_OnLoad(vm: JavaVM, _env: jni::JNIEnv) -> jni::sys::jint {
        JAVA_VM.store(vm.into_raw(), Ordering::Relaxed);
        // 返回适配的JNI版本,通常用JNI_VERSION_1_6
        jni::sys::JNI_VERSION_1_6
    }
    
  3. 在任意线程中获取JavaVM
    后续需要跨线程调用回调时,从静态变量中取出JavaVM,再通过它关联当前线程的JNI环境:

    fn get_java_vm() -> Option<JavaVM> {
        let ptr = JAVA_VM.load(Ordering::Relaxed);
        if ptr.is_null() {
            None
        } else {
            unsafe { Some(JavaVM::from_raw(ptr)) }
        }
    }
    
    // 示例:在其他线程中获取JNIEnv
    fn use_jvm_in_other_thread() {
        if let Some(vm) = get_java_vm() {
            let env = vm.attach_current_thread().unwrap();
            // 这里可以使用env进行JNI操作,比如调用Java回调
        }
    }
    

关键注意事项

  • 确保你的Rust项目依赖jni crate(在Cargo.toml中添加jni = "0.21"或对应兼容版本)
  • JNI_OnLoad必须标注#[no_mangle]和extern "system"调用约定,否则Android系统无法识别该函数
  • JavaVM本身是线程安全的,因此使用原子指针存储是安全的;但JNIEnv是线程绑定的,必须通过attach_current_thread在目标线程中获取

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:35:23