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

iOS Swift区分AdMob激励广告完整观看与中途关闭的回调方法

问题根源

你当前逻辑出错的核心原因是用错了AdMob激励广告的回调方法:

  • adDidDismissFullScreenContent是所有全屏广告通用的关闭回调,不管用户是看完广告正常关闭,还是看了一半手动点关闭,甚至广告播放出错被系统关闭,这个方法都会触发,它本身不携带任何「是否满足奖励发放条件」的状态,完全不能作为发奖励、弹奖励弹窗的判断依据。
修复方案

最新版AdMob iOS SDK的奖励判定回调,根本不在GADFullScreenContentDelegate代理里,而是在GADRewardedAd调用present方法时传入的完成闭包中:只有用户完整观看完整个激励广告,满足奖励发放条件时,这个闭包才会被触发;用户中途关闭广告的话,这个闭包不会执行。
你只需要加一个布尔标记位记录奖励状态,再配合关闭回调做判断即可:

  • 在广告管理类中新增isUserEarnedReward布尔属性,专门标记当前广告播放完成后用户是否有资格拿奖励
  • 每次展示广告前先把这个标记重置为false
  • 在present方法的完成闭包里,把标记设为true,核心发奖逻辑也可以放在这里
  • 在adDidDismissFullScreenContent回调中,只有标记为true时才执行奖励弹窗逻辑,否则直接跳过,最后统一重置所有广告状态
核心修改代码

1. 新增状态标记属性

class RewardAdManager : NSObject
{
    //MARK: - PROPERTIES
    var rewardBasedVideoAd : GADRewardedAd? = nil
    var rewardValue = ""
    var type: RewardAdType? = nil
    // 新增:记录用户是否满足奖励发放条件
    private var isUserEarnedReward = false
}

2. 修改广告展示逻辑,正确接收奖励回调

func showRewardedAd(viewController: UIViewController, type: RewardAdType? = nil, completion: @escaping AD_COMPLETION_BLOCK)
{
    Helpers.hidehud()
    
    if let ad = self.rewardBasedVideoAd {
        self.type = type
        // 每次展示前重置奖励状态,避免上次广告的状态干扰
        isUserEarnedReward = false
        DispatchQueueHelper.delay { [weak self] in
            guard let self = self else { return }
            // 不要传空闭包,通过present的完成回调判定用户是否看完广告
            ad.present(fromRootViewController: viewController) {
                // 走到这里就代表用户完整看完了广告,符合奖励要求
                self.isUserEarnedReward = true
                // 这里可以直接写奖励发放的核心逻辑,比如增加金币、解锁道具
            }
        }
        completion(true)
    } else {
        self.type = nil
        self.checkForSavedLanguage(viewController: viewController)
    }
}

3. 修改广告关闭回调,按状态判断是否弹出奖励窗

func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd)
{
    // 方法结束前统一重置所有广告状态,避免状态残留
    defer {
        self.rewardBasedVideoAd = nil
        self.type = nil
        self.isUserEarnedReward = false
    }
    // 中途关闭广告的话isUserEarnedReward为false,直接返回不弹奖励窗
    guard isUserEarnedReward, let adType = self.type else { return }
    // 只有完整看完广告才会走到这里,弹出奖励弹窗
    let userInfo: [String:RewardAdType] = ["type":adType]
    NotificationCaller.shared.showRewardTypePopup(userInfo: userInfo)
}
补充说明
  • 如果你的奖励是高价值虚拟道具/货币,不要完全依赖客户端的状态标记发奖,你代码里已经接入的服务端验证(SSV)才是最终发奖依据,客户端的标记只用来控制弹窗等前端交互即可,避免被恶意抓包刷奖励。
  • 除了广告关闭时,在广告加载失败、展示失败的回调里,也要记得重置isUserEarnedReward标记,避免状态污染。
  • 修改后逻辑完全符合预期:用户中途关闭广告时不会触发奖励弹窗,完整看完广告才会正常走奖励发放、弹窗逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:42:26