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

如何通过JNI C++获取Java接口枚举值并转换为UE4枚举

解决AdMob JNI调用getInitializationState崩溃并转换枚举到UE4的方案

崩溃原因

直接通过JNI调用getInitializationState触发java.lang.NoSuchMethodError,核心原因是实际返回的AdapterStatus实现类是混淆后的内部类com.google.android.gms.internal.ads.zzbrt,该类的方法签名或名称与公开API的AdapterStatus接口不一致,常规JNI方法调用无法匹配到对应方法。

可行解决方案

方案1:Java层提前转换枚举为int再传递

修改Java端回调逻辑,先将AdapterStatus的State枚举转为int值,再传递给JNI,彻底避免C++层处理复杂的JNI枚举调用:

// Java端代码示例
public class AdMobInitializer {
    private void onInitializationComplete(Map<String, AdapterStatus> statusMap) {
        HashMap<String, Integer> stateIntMap = new HashMap<>();
        for (Map.Entry<String, AdapterStatus> entry : statusMap.entrySet()) {
            // 直接取枚举的ordinal值,若枚举有自定义getValue()方法可替换为该方法
            int stateInt = entry.getValue().getInitializationState().ordinal();
            stateIntMap.put(entry.getKey(), stateInt);
        }
        // 调用JNI方法传递转换后的int集合
        nativeOnInitializationResponse(stateIntMap);
    }

    private native void nativeOnInitializationResponse(Map<String, Integer> stateIntMap);
}

C++层直接读取int值并映射到UE4枚举:

// C++ JNI实现示例
JNIEXPORT void JNICALL Java_com_yourpackage_AdMobInitializer_nativeOnInitializationResponse(
        JNIEnv* env, jobject thiz, jobject stateIntMap) {
    jclass hashMapCls = env->FindClass("java/util/HashMap");
    jmethodID entrySetMethod = env->GetMethodID(hashMapCls, "entrySet", "()Ljava/util/Set;");
    jobject entrySet = env->CallObjectMethod(stateIntMap, entrySetMethod);

    jclass setCls = env->FindClass("java/util/Set");
    jmethodID iteratorMethod = env->GetMethodID(setCls, "iterator", "()Ljava/util/Iterator;");
    jobject iterator = env->CallObjectMethod(entrySet, iteratorMethod);

    jclass iteratorCls = env->FindClass("java/util/Iterator");
    jmethodID hasNextMethod = env->GetMethodID(iteratorCls, "hasNext", "()Z");
    jmethodID nextMethod = env->GetMethodID(iteratorCls, "next", "()Ljava/lang/Object;");

    jclass entryCls = env->FindClass("java/util/Map$Entry");
    jmethodID getKeyMethod = env->GetMethodID(entryCls, "getKey", "()Ljava/lang/Object;");
    jmethodID getValueMethod = env->GetMethodID(entryCls, "getValue", "()Ljava/lang/Object;");

    while (env->CallBooleanMethod(iterator, hasNextMethod)) {
        jobject entry = env->CallObjectMethod(iterator, nextMethod);
        jstring adapterName = (jstring)env->CallObjectMethod(entry, getKeyMethod);
        jint stateInt = env->CallIntMethod(entry, getValueMethod);

        // 转换为UE4枚举
        EAdMobInitializationState ueState = static_cast<EAdMobInitializationState>(stateInt);
        // 后续业务逻辑处理...

        env->DeleteLocalRef(adapterName);
        env->DeleteLocalRef(entry);
    }

    // 释放局部引用
    env->DeleteLocalRef(iterator);
    env->DeleteLocalRef(entrySet);
    env->DeleteLocalRef(hashMapCls);
    env->DeleteLocalRef(setCls);
    env->DeleteLocalRef(iteratorCls);
    env->DeleteLocalRef(entryCls);
}

方案2:JNI反射获取枚举的int值

若必须在C++层处理原始AdapterStatus Map,可通过反射调用方法并提取枚举的int值:

// C++中处理单个AdapterStatus对象的逻辑示例
jobject adapterStatus = ...; // 从Map中取出的AdapterStatus实例
jclass adapterStatusCls = env->GetObjectClass(adapterStatus);

// 反射调用getInitializationState方法
jmethodID getStateMethod = env->GetMethodID(adapterStatusCls, "getInitializationState", 
    "()Lcom/google/android/gms/ads/initialization/InitializationState;");
jobject stateEnum = env->CallObjectMethod(adapterStatus, getStateMethod);

// 获取枚举的ordinal值(若枚举有自定义值方法,替换为对应方法名)
jclass enumCls = env->FindClass("java/lang/Enum");
jmethodID ordinalMethod = env->GetMethodID(enumCls, "ordinal", "()I");
jint stateInt = env->CallIntMethod(stateEnum, ordinalMethod);

// 转换为UE4枚举
EAdMobInitializationState ueState = static_cast<EAdMobInitializationState>(stateInt);

// 释放局部引用
env->DeleteLocalRef(adapterStatusCls);
env->DeleteLocalRef(stateEnum);
env->DeleteLocalRef(enumCls);

方案3:直接读取混淆类的字段值

若反射调用方法仍失败,可尝试直接读取zzbrt类中存储状态的字段(需反编译AdMob SDK确认实际字段名,比如zzb、zzc等):

// 假设混淆后的状态字段名为zzb(需反编译验证)
jclass zzbrtCls = env->GetObjectClass(adapterStatus);
jfieldID stateField = env->GetFieldID(zzbrtCls, "zzb", "I");
jint stateInt = env->GetIntField(adapterStatus, stateField);

// 转换为UE4枚举
EAdMobInitializationState ueState = static_cast<EAdMobInitializationState>(stateInt);

env->DeleteLocalRef(zzbrtCls);

注意:该方案依赖AdMob内部实现细节,SDK更新后可能失效,仅作为应急方案使用。

优先级建议

优先采用方案1,Java层转换的方式最稳定,完全规避对AdMob内部实现的依赖;方案2次之,依赖公开API的方法签名,兼容性较好;方案3仅在极端场景下使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:01:18