在 iOS 中,广告 SDK 判断广告真实展示主要通过以下几种方式:
1. 基于视图可见性的检测
可视区域检测
objective-c
// 检查广告视图是否在屏幕可见区域内
CGRect screenRect = [UIScreen mainScreen].bounds;
CGRect adRect = [adView convertRect:adView.bounds toView:nil];
BOOL isVisible = CGRectIntersectsRect(screenRect, adRect);
// 检查视图是否被其他视图遮挡
BOOL isNotCovered = (adView.superview != nil &&
!adView.hidden &&
adView.alpha > 0.1);
视图层级检查
objective-c
- (BOOL)isViewVisible:(UIView *)view {
// 检查视图及其父视图是否可见
UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
UIView *currentView = view;
while (currentView != nil) {
if (currentView.hidden || currentView.alpha < 0.01) {
return NO;
}
currentView = currentView.superview;
}
return YES;
}
2. 展示时间要求
大多数广告 SDK 要求广告必须:
-
持续展示:通常需要连续展示 1-2 秒
-
足够的像素比例:通常要求 50% 以上的广告像素可见
-
处于活跃状态:应用在前台运行
objective-c
// 计时器检测持续展示时间
__block NSTimeInterval startTime = 0;
__block BOOL hasTracked = NO;
- (void)checkAdDisplayDuration {
if ([self isAdViewVisible] && !hasTracked) {
if (startTime == 0) {
startTime = [[NSDate date] timeIntervalSince1970];
} else {
NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
if (currentTime - startTime >= 1.0) { // 至少1秒
[self trackImpression];
hasTracked = YES;
}
}
} else {
startTime = 0;
}
}
3. 像素面积计算
objective-c
- (CGFloat)calculateVisiblePercentage {
CGRect screenBounds = [UIScreen mainScreen].bounds;
CGRect adFrameInScreen = [adView convertRect:adView.bounds toView:nil];
// 计算交集矩形
CGRect intersectionRect = CGRectIntersection(screenBounds, adFrameInScreen);
if (CGRectIsNull(intersectionRect)) {
return 0.0;
}
CGFloat adArea = adView.bounds.size.width * adView.bounds.size.height;
CGFloat visibleArea = intersectionRect.size.width * intersectionRect.size.height;
return (adArea > 0) ? (visibleArea / adArea) : 0.0;
}
4. 主流广告 SDK 的实现
Google AdMob
objective-c
// AdMob 自动处理展示检测
GADBannerView *bannerView = [[GADBannerView alloc] init];
bannerView.adUnitID = @"your-ad-unit-id";
bannerView.rootViewController = self;
// 通过 delegate 接收展示回调
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView {
// 广告成功展示时会调用此方法
}
Facebook Audience Network
objective-c
FBAdView *adView = [[FBAdView alloc] initWithPlacementID:@"your-placement-id"
adSize:kFBAdSizeHeight50Banner
rootViewController:self];
// 展示回调
- (void)adView:(FBAdView *)adView didLoadWithError:(NSError *)error {
if (!error) {
// 广告准备展示
}
}
5. 自定义展示检测
objective-c
@interface AdDisplayTracker : NSObject
@property (nonatomic, weak) UIView *adView;
@property (nonatomic, strong) NSTimer *displayTimer;
@property (nonatomic, assign) BOOL impressionTracked;
@end
@implementation AdDisplayTracker
- (void)startTracking {
self.displayTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(checkDisplay)
userInfo:nil
repeats:YES];
}
- (void)checkDisplay {
if (self.impressionTracked) return;
BOOL isVisible = [self isViewVisible:self.adView];
CGFloat visiblePercentage = [self calculateVisiblePercentage];
if (isVisible && visiblePercentage >= 0.5) {
[self trackImpressionIfNeeded];
}
}
- (void)trackImpressionIfNeeded {
// 确保只跟踪一次展示
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self sendImpressionTracking];
self.impressionTracked = YES;
});
}
6. 注意事项
-
避免重复计数:确保每个广告只记录一次展示
-
考虑设备方向:横竖屏切换时重新计算可见区域
-
性能优化:检测频率不宜过高,避免影响应用性能
-
遵守平台政策:按照各广告平台的展示定义标准实现
这些方法组合使用可以比较准确地判断广告是否真实展示,符合行业标准的展示定义。