Cocos2d-x(C++)安卓端多AdMob激励视频加载与展示冲突解决问询
解决AdMob激励视频单例限制:同时加载与展示不同广告单元的方案
嘿,这个问题我之前也踩过坑——AdMob旧版的RewardedVideoAd单例设计确实会卡死“加载新广告时无法展示已加载广告”的场景,咱们来拆解问题,再给你两个可行的方案:
核心问题根源
旧版RewardedVideoAd是全局单例,它的isLoaded()、show()方法都是绑定到当前单例的状态上的:当你调用loadAd()加载AdUnit2时,单例会进入“加载中”状态,此时不管之前AdUnit1是否加载完成,isLoaded()都会返回false,自然没法触发展示。而且这个单例根本不区分广告单元ID,所以没法同时跟踪多个广告的加载状态。
最优方案:迁移到新版RewardedAd API
Google早就弃用了旧版的RewardedVideoAd,推出了非单例的RewardedAd API——每个广告单元可以创建独立的RewardedAd实例,完美支持并行加载和独立展示。这是最彻底的解决方案,步骤如下:
Java侧实现思路
- 维护一个
Map<String, RewardedAd>,用广告单元ID作为key,存储每个广告单元对应的RewardedAd实例。 - 提供两个JNI可调用的方法:
loadRewardedAd(String adUnitId)和showRewardedAd(String adUnitId),分别负责加载指定广告单元和展示已加载的广告。 - 加载回调中,把成功加载的
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,可以用这个临时方案规避问题,但它只能模拟“并行”,无法真正同时加载多个广告:
- 维护两个队列:一个加载请求队列,一个已加载广告队列。
- 当发起加载请求时,先检查当前
RewardedVideoAd是否处于加载中:- 如果是,把广告单元ID加入加载请求队列;
- 如果不是,直接调用
loadAd()加载该广告单元。
- 当
onAdLoaded()触发时:- 把当前广告单元ID加入已加载队列;
- 如果加载请求队列不为空,取出队首的广告单元ID,继续调用
loadAd()加载。
- 当需要展示广告时,从已加载队列中取出任意广告单元ID,调用
show(),展示完成后重新加载该广告单元。
这个方案的缺点很明显:同一时间只能有一个广告在加载,效率较低,而且旧版API已经被弃用,后续可能会被移除,所以还是优先推荐迁移到新版API。
内容的提问来源于stack exchange,提问作者dddkirby
相关产品推荐
相关产品推荐

