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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 00:15:37