Unity中AdMob激励广告奖励堆叠问题及解决方法咨询
解决AdMob激励广告奖励逐次递增的问题
问题核心:每次调用showRewarded时,都会重复给rewardedAd.OnUserEarnedReward绑定新的匿名委托,但从未执行解绑操作。多次调用后,这个事件会积累多个委托实例,当用户获得奖励时,所有绑定过的委托都会触发,导致奖励次数1、2、3...逐次递增。
快速修复方案
方案1:使用命名方法,绑定前先解绑
把匿名委托改为命名方法,每次绑定前先移除旧的事件绑定,确保事件上始终只有一个委托:
private Action<bool> _currentRewardCallback; public void showRewarded(Action<bool> giveReward) { _currentRewardCallback = giveReward; if (rewardedAd.IsLoaded()) { // 先移除之前的绑定,避免堆叠 rewardedAd.OnUserEarnedReward -= OnUserEarnedReward; rewardedAd.OnUserEarnedReward += OnUserEarnedReward; rewardedAd.Show(); } else { giveReward(false); } requestRewarded(); } private void OnUserEarnedReward(object sender, Reward reward) { // 触发回调后立刻解绑 rewardedAd.OnUserEarnedReward -= OnUserEarnedReward; _currentRewardCallback?.Invoke(true); _currentRewardCallback = null; }
方案2:绑定一次性委托,执行后自动解绑
用临时变量保存匿名委托,在委托内部先解绑自己再执行奖励逻辑:
public void showRewarded(Action<bool> giveReward) { if (rewardedAd.IsLoaded()) { EventHandler<Reward> rewardHandler = null; rewardHandler = delegate(object sender, Reward reward) { // 先解绑自己,防止重复执行 rewardedAd.OnUserEarnedReward -= rewardHandler; giveReward(true); }; rewardedAd.OnUserEarnedReward += rewardHandler; rewardedAd.Show(); } else { giveReward(false); } requestRewarded(); }
更优的实现方式
上面的修复是应急方案,更规范的做法是统一管理广告生命周期,事件仅绑定一次,从根源避免委托堆叠:
public class AdsController : MonoBehaviour { public static AdsController Instance; private RewardedAd _rewardedAd; private Action<bool> _pendingRewardCallback; private bool _isRequestingAd; private void Awake() { Instance = this; InitializeRewardedAd(); } // 初始化广告,仅绑定一次所有生命周期事件 private void InitializeRewardedAd() { _rewardedAd = new RewardedAd("你的AdMob广告ID"); _rewardedAd.OnAdLoaded += OnRewardedAdLoaded; _rewardedAd.OnAdFailedToShow += OnRewardedAdShowFailed; _rewardedAd.OnUserEarnedReward += OnUserEarnedReward; RequestRewardedAd(); } public void ShowRewarded(Action<bool> onRewardCompleted) { _pendingRewardCallback = onRewardCompleted; if (_rewardedAd.IsLoaded()) { _rewardedAd.Show(); } else { onRewardCompleted?.Invoke(false); // 未加载完成时,仅在未请求广告时发起请求 if (!_isRequestingAd) RequestRewardedAd(); } } private void RequestRewardedAd() { if (_isRequestingAd) return; _isRequestingAd = true; AdRequest adRequest = new AdRequest.Builder().Build(); _rewardedAd.LoadAd(adRequest); } private void OnRewardedAdLoaded(object sender, EventArgs e) { _isRequestingAd = false; } private void OnRewardedAdShowFailed(object sender, AdErrorEventArgs e) { _pendingRewardCallback?.Invoke(false); _pendingRewardCallback = null; RequestRewardedAd(); } private void OnUserEarnedReward(object sender, Reward e) { _pendingRewardCallback?.Invoke(true); _pendingRewardCallback = null; RequestRewardedAd(); } // 销毁时清理资源,避免内存泄漏 private void OnDestroy() { _rewardedAd.OnAdLoaded -= OnRewardedAdLoaded; _rewardedAd.OnAdFailedToShow -= OnRewardedAdShowFailed; _rewardedAd.OnUserEarnedReward -= OnUserEarnedReward; _rewardedAd.Destroy(); } }
这种方式的优势:
- 事件仅绑定一次,彻底避免委托堆叠问题
- 统一管理广告的加载、展示失败、奖励发放逻辑
- 避免重复请求广告,减少无效请求
- 销毁时自动清理资源,防止内存泄漏
内容的提问来源于stack exchange,提问作者SengunSipahi
相关产品推荐
相关产品推荐

