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

Cocos2d-x(C++)安卓端多AdMob激励视频加载与展示冲突解决问询

解决AdMob激励视频单例限制:同时加载与展示不同广告单元的方案

嘿,这个问题我之前也踩过坑——AdMob旧版的RewardedVideoAd单例设计确实会卡死“加载新广告时无法展示已加载广告”的场景,咱们来拆解问题,再给你两个可行的方案:

核心问题根源

旧版RewardedVideoAd是全局单例,它的isLoaded()、show()方法都是绑定到当前单例的状态上的:当你调用loadAd()加载AdUnit2时,单例会进入“加载中”状态,此时不管之前AdUnit1是否加载完成,isLoaded()都会返回false,自然没法触发展示。而且这个单例根本不区分广告单元ID,所以没法同时跟踪多个广告的加载状态。

最优方案:迁移到新版RewardedAd API

Google早就弃用了旧版的RewardedVideoAd,推出了非单例的RewardedAd API——每个广告单元可以创建独立的RewardedAd实例,完美支持并行加载和独立展示。这是最彻底的解决方案,步骤如下:

Java侧实现思路

  1. 维护一个Map<String, RewardedAd>,用广告单元ID作为key,存储每个广告单元对应的RewardedAd实例。
  2. 提供两个JNI可调用的方法:loadRewardedAd(String adUnitId)和showRewardedAd(String adUnitId),分别负责加载指定广告单元和展示已加载的广告。
  3. 加载回调中,把成功加载的RewardedAd实例存入Map,并通过JNI通知C++层对应广告单元加载完成;展示后移除该实例(因为RewardedAd实例只能展示一次)。

示例代码片段:

// AppActivity.java
private Map<String, RewardedAd> mRewardedAdMap = new HashMap<>();

// JNI调用:加载指定广告单元的激励视频
public void loadRewardedAd(String adUnitId) {
    RewardedAd rewardedAd = new RewardedAd(this, adUnitId);
    RewardedAdLoadCallback loadCallback = new RewardedAdLoadCallback() {
        @Override
        public void onAdLoaded(RewardedAd ad) {
            mRewardedAdMap.put(adUnitId, ad);
            // 回调C++层:AdUnitId加载完成
            nativeNotifyAdLoaded(adUnitId);
        }

        @Override
        public void onAdFailedToLoad(LoadAdError error) {
            // 回调C++层:AdUnitId加载失败
            nativeNotifyAdFailed(adUnitId, error.getMessage());
        }
    };
    rewardedAd.loadAd(new AdRequest.Builder().build(), loadCallback);
}

// JNI调用:展示指定广告单元的激励视频
public void showRewardedAd(String adUnitId) {
    RewardedAd rewardedAd = mRewardedAdMap.get(adUnitId);
    if (rewardedAd != null && rewardedAd.isLoaded()) {
        rewardedAd.show(this, rewardItem -> {
            // 回调C++层:用户获得奖励
            nativeNotifyRewardEarned(adUnitId, rewardItem.getType(), rewardItem.getAmount());
            // 展示后移除实例,避免重复展示
            mRewardedAdMap.remove(adUnitId);
        });
    } else {
        // 回调C++层:广告未加载完成
        nativeNotifyAdNotReady(adUnitId);
    }
}

// 声明native方法,对应C++侧的JNI接口
private native void nativeNotifyAdLoaded(String adUnitId);
private native void nativeNotifyAdFailed(String adUnitId, String errorMsg);
private native void nativeNotifyRewardEarned(String adUnitId, String type, int amount);
private native void nativeNotifyAdNotReady(String adUnitId);

C++侧适配

通过JNI调用Java侧的loadRewardedAd和showRewardedAd时,传入对应的广告单元ID即可,比如:

// 加载AdUnit1
jmethodID loadAdMethod = env->GetMethodID(activityClass, "loadRewardedAd", "(Ljava/lang/String;)V");
jstring adUnit1 = env->NewStringUTF("ca-app-pub-xxx/xxx");
env->CallVoidMethod(activityObj, loadAdMethod, adUnit1);
env->DeleteLocalRef(adUnit1);

// 展示已加载的AdUnit1
jmethodID showAdMethod = env->GetMethodID(activityClass, "showRewardedAd", "(Ljava/lang/String;)V");
jstring adUnit1Show = env->NewStringUTF("ca-app-pub-xxx/xxx");
env->CallVoidMethod(activityObj, showAdMethod, adUnit1Show);
env->DeleteLocalRef(adUnit1Show);

这样你就可以同时加载AdUnit1和AdUnit2,并且随时展示任意一个已加载完成的广告,完全不受单例限制。

临时替代方案:广告队列+状态管理(不推荐长期使用)

如果暂时没法迁移到新版API,可以用这个临时方案规避问题,但它只能模拟“并行”,无法真正同时加载多个广告:

  1. 维护两个队列:一个加载请求队列,一个已加载广告队列。
  2. 当发起加载请求时,先检查当前RewardedVideoAd是否处于加载中:
    • 如果是,把广告单元ID加入加载请求队列;
    • 如果不是,直接调用loadAd()加载该广告单元。
  3. 当onAdLoaded()触发时:
    • 把当前广告单元ID加入已加载队列;
    • 如果加载请求队列不为空,取出队首的广告单元ID,继续调用loadAd()加载。
  4. 当需要展示广告时,从已加载队列中取出任意广告单元ID,调用show(),展示完成后重新加载该广告单元。

这个方案的缺点很明显:同一时间只能有一个广告在加载,效率较低,而且旧版API已经被弃用,后续可能会被移除,所以还是优先推荐迁移到新版API。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:37:48