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

JNI调用Java加密方法致安卓设备背光异常闪退问题求助

问题排查与解决

你的安卓应用闪退问题,核心出在JNI调用Java方法时用错了调用对象,再加上几个JNI使用的细节没处理到位,直接导致了崩溃。我帮你拆解下问题,再给出具体的修复方案:

最关键的错误:调用对象不匹配

你在CPP代码里写了env->CallObjectMethod(obj, encrypt_func, a, key),这里的obj是NativeEncryptionUtils类的实例(因为这个JNI方法本身就是NativeEncryptionUtils的encrypt方法),但encryptdata方法是属于NativeDES类的——你用A类的对象去调用B类的实例方法,这完全不匹配,不崩溃才怪!

两种修复方案,按需选择

方案1:把encryptdata改成静态方法(推荐,JNI调用更简单)

先修改Java端的NativeDES类,给encryptdata加上static修饰符:

public static byte[] encryptdata(byte[] data1, String key) { 
    byte[] clear = null; 
    try { 
        SecretKeySpec sc = new SecretKeySpec(key.getBytes("UTF-8"),"DESede"); 
        Cipher cipher = Cipher.getInstance("DESede"); 
        cipher.init(Cipher.ENCRYPT_MODE,sc); 
        clear = cipher.doFinal(data1); 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
    return clear; 
}

然后修改JNI代码,改用CallStaticObjectMethod调用静态方法,不需要创建NativeDES的实例:

JNIEXPORT jbyteArray JNICALL Java_com_airtel_agilelabs_utils_NativeEncryptionUtils_encrypt( JNIEnv* env, jobject obj, jobject context, jbyteArray data) { 
    // 先检查输入参数是否为空,避免后续空指针操作
    if (data == nullptr) {
        return nullptr;
    }

    jbyteArray input_data = data; 
    jstring key = env->NewStringUTF("[key]"); 
    // 检查字符串分配是否成功
    if (key == nullptr) {
        return nullptr;
    }

    // 查找NativeDES类,注意包名要完全匹配
    jclass des_class = env->FindClass("com/test/test1/utils/NativeDES"); 
    if (des_class == nullptr) {
        env->DeleteLocalRef(key);
        return nullptr; // 类找不到,大概率是包名写错了
    }

    // 获取静态方法ID,方法签名要和Java方法完全对应
    jmethodID encrypt_func = env->GetStaticMethodID(des_class, "encryptdata", "([BLjava/lang/String;)[B"); 
    if (encrypt_func == nullptr) {
        env->DeleteLocalRef(des_class);
        env->DeleteLocalRef(key);
        return nullptr; // 方法找不到,检查方法名或签名
    }

    // 调用静态方法,这里用类对象des_class作为调用者
    jobject result = env->CallStaticObjectMethod(des_class, encrypt_func, input_data, key); 
    jbyteArray byte_result = (jbyteArray) result; 

    // 释放本地引用,避免内存泄漏
    env->DeleteLocalRef(des_class);
    env->DeleteLocalRef(key);

    return byte_result;
}

方案2:保留实例方法,先创建NativeDES对象

如果不想改成静态方法,那你需要先通过JNI创建NativeDES的实例,再用这个实例去调用encryptdata:

JNIEXPORT jbyteArray JNICALL Java_com_airtel_agilelabs_utils_NativeEncryptionUtils_encrypt( JNIEnv* env, jobject obj, jobject context, jbyteArray data) { 
    if (data == nullptr) {
        return nullptr;
    }

    jbyteArray input_data = data; 
    jstring key = env->NewStringUTF("[key]"); 
    if (key == nullptr) {
        return nullptr;
    }

    jclass des_class = env->FindClass("com/test/test1/utils/NativeDES"); 
    if (des_class == nullptr) {
        env->DeleteLocalRef(key);
        return nullptr;
    }

    // 获取NativeDES的无参构造方法ID
    jmethodID constructor = env->GetMethodID(des_class, "<init>", "()V");
    if (constructor == nullptr) {
        env->DeleteLocalRef(des_class);
        env->DeleteLocalRef(key);
        return nullptr;
    }

    // 创建NativeDES的实例对象
    jobject des_obj = env->NewObject(des_class, constructor);
    if (des_obj == nullptr) {
        env->DeleteLocalRef(des_class);
        env->DeleteLocalRef(key);
        return nullptr;
    }

    // 获取实例方法ID
    jmethodID encrypt_func = env->GetMethodID(des_class, "encryptdata", "([BLjava/lang/String;)[B"); 
    if (encrypt_func == nullptr) {
        env->DeleteLocalRef(des_obj);
        env->DeleteLocalRef(des_class);
        env->DeleteLocalRef(key);
        return nullptr;
    }

    // 注意!这里要用des_obj(NativeDES的实例)作为调用者,而不是原来的obj
    jobject result = env->CallObjectMethod(des_obj, encrypt_func, input_data, key); 
    jbyteArray byte_result = (jbyteArray) result; 

    // 释放所有本地引用
    env->DeleteLocalRef(des_obj);
    env->DeleteLocalRef(des_class);
    env->DeleteLocalRef(key);

    return byte_result;
}

额外的JNI注意事项,避免后续踩坑

  • 方法签名要精准:你用的([BLjava/lang/String;)[B是对的,对应byte[] encryptdata(byte[], String),如果后续修改Java方法的参数或返回值,一定要同步更新签名。
  • 释放本地引用:JNI中创建的jclass、jstring、jobject都是本地引用,不用了必须手动释放,否则会内存泄漏,严重时也会引发崩溃。
  • 空指针检查不能少:所有JNI调用的返回值(比如FindClass、GetMethodID)都要检查是否为nullptr,不然一步错就会导致整个应用崩溃。
  • 无用参数处理:你的JNI方法里有个jobject context参数,但代码里没用到,如果不需要可以直接删掉,省得混淆。

关于CallObjectMethod和其他调用函数的选择

  • 如果Java方法是实例方法(非static),必须用CallObjectMethod,而且调用对象必须是该类的实例。
  • 如果Java方法是静态方法,必须用CallStaticObjectMethod,调用对象是该类的jclass对象。
  • 你之前的错误就是把A类的实例当成B类的实例去调用方法,完全不匹配,这是JNI调用里的低级错误,但也是新手常踩的坑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:10:25