메인 콘텐츠로 건너뛰기

개요

보상형 광고는 사용자가 동영상 광고를 끝까지 시청하면 게임 내 재화, 생명, 힌트 등의 보상을 제공하는 전면 동영상 광고입니다.

주요 특징

  • 전면 화면을 차지하는 동영상 광고
  • 사용자가 광고를 완전히 시청한 경우에만 보상 제공
  • 사용자가 직접 광고 시청을 선택 (예: “동영상 보고 생명 받기” 버튼)
  • 보상 타입과 수량을 설정 가능
개발 환경에서는 테스트 유닛 ID를 사용하세요: PUBLIC_TEST_UNIT_ID_REWARDED

구현 방법

보상형 광고는 다음과 같은 단계로 구현합니다:
  1. AdropRewardedAd 인스턴스 생성 - 유닛 ID로 광고 객체 생성
  2. Delegate 설정 - 광고 이벤트 처리를 위한 delegate 지정
  3. 광고 로드 - load() 메서드로 광고 요청
  4. 광고 표시 - show() 메서드로 광고 표시 및 보상 처리

Swift 예제

기본 구현

import UIKit
import AdropAds

class RewardedViewController: UIViewController {
    private var rewardedAd: AdropRewardedAd?

    override func viewDidLoad() {
        super.viewDidLoad()

        // 1. AdropRewardedAd 인스턴스 생성
        rewardedAd = AdropRewardedAd(unitId: "YOUR_UNIT_ID")

        // 2. Delegate 설정
        rewardedAd?.delegate = self

        // 3. 광고 로드
        rewardedAd?.load()
    }

    @IBAction func showRewardedAdButtonTapped(_ sender: UIButton) {
        // 광고가 로드되었는지 확인
        guard rewardedAd?.isLoaded == true else {
            print("광고가 아직 로드되지 않았습니다")
            return
        }

        // 4. 광고 표시 및 보상 처리
        rewardedAd?.show(fromRootViewController: self) { [weak self] type, amount in
            // 보상 지급 처리
            print("보상 획득 - 타입: \(type), 수량: \(amount)")
            self?.grantReward(type: type, amount: amount)
        }
    }

    private func grantReward(type: Int, amount: Int) {
        // 사용자에게 보상 지급
        // 예: 게임 재화 추가, 생명 회복 등

        // ⚠️ 중요: 서버에서 보상을 검증하는 것을 권장합니다
        // 클라이언트에서만 보상을 처리하면 부정행위가 가능합니다
    }
}

// MARK: - AdropRewardedAdDelegate
extension RewardedViewController: AdropRewardedAdDelegate {
    // 필수: 광고 수신 성공
    func onAdReceived(_ ad: AdropRewardedAd) {
        print("광고 수신 완료")
        // 광고 시청 버튼 활성화 등
    }

    // 필수: 광고 수신 실패
    func onAdFailedToReceive(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        print("광고 수신 실패: \(errorCode)")
        // 광고 시청 버튼 비활성화 유지 등
    }

    // 선택: 광고 노출
    func onAdImpression(_ ad: AdropRewardedAd) {
        print("광고 노출됨")
    }

    // 선택: 광고 클릭
    func onAdClicked(_ ad: AdropRewardedAd) {
        print("광고 클릭됨")
    }

    // 선택: 광고 화면 표시 직전
    func onAdWillPresentFullScreen(_ ad: AdropRewardedAd) {
        print("광고 화면 표시 예정")
        // 배경 음악 일시정지 등
    }

    // 선택: 광고 화면 표시 완료
    func onAdDidPresentFullScreen(_ ad: AdropRewardedAd) {
        print("광고 화면 표시 완료")
    }

    // 선택: 광고 화면 닫기 직전
    func onAdWillDismissFullScreen(_ ad: AdropRewardedAd) {
        print("광고 화면 닫기 예정")
    }

    // 선택: 광고 화면 닫기 완료
    func onAdDidDismissFullScreen(_ ad: AdropRewardedAd) {
        print("광고 화면 닫힘")
        // 배경 음악 재개 등

        // 다음 광고 미리 로드
        rewardedAd?.load()
    }

    // 선택: 광고 표시 실패
    func onAdFailedToShowFullScreen(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        print("광고 표시 실패: \(errorCode)")
    }
}

SwiftUI 예제

import SwiftUI
import AdropAds

class RewardedAdViewModel: NSObject, ObservableObject, AdropRewardedAdDelegate {
    @Published var isAdReady = false
    @Published var showingAlert = false
    @Published var alertMessage = ""

    private var rewardedAd: AdropRewardedAd?

    override init() {
        super.init()
        loadAd()
    }

    func loadAd() {
        rewardedAd = AdropRewardedAd(unitId: "YOUR_UNIT_ID")
        rewardedAd?.delegate = self
        rewardedAd?.load()
    }

    func showAd() {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let rootViewController = windowScene.windows.first?.rootViewController else {
            return
        }

        rewardedAd?.show(fromRootViewController: rootViewController) { [weak self] type, amount in
            self?.alertMessage = "보상 획득! 타입: \(type), 수량: \(amount)"
            self?.showingAlert = true
            self?.grantReward(type: type, amount: amount)
        }
    }

    private func grantReward(type: Int, amount: Int) {
        // 보상 지급 처리
        print("보상 지급 - 타입: \(type), 수량: \(amount)")
    }

    // MARK: - AdropRewardedAdDelegate

    func onAdReceived(_ ad: AdropRewardedAd) {
        isAdReady = true
    }

    func onAdFailedToReceive(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        isAdReady = false
        alertMessage = "광고 로드 실패: \(errorCode)"
        showingAlert = true
    }

    func onAdDidDismissFullScreen(_ ad: AdropRewardedAd) {
        isAdReady = false
        // 다음 광고 미리 로드
        loadAd()
    }

    func onAdFailedToShowFullScreen(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        alertMessage = "광고 표시 실패: \(errorCode)"
        showingAlert = true
    }
}

struct RewardedAdView: View {
    @StateObject private var viewModel = RewardedAdViewModel()

    var body: some View {
        VStack(spacing: 20) {
            Text("보상형 광고 예제")
                .font(.title)

            Button(action: {
                viewModel.showAd()
            }) {
                Text("동영상 보고 보상 받기")
                    .padding()
                    .background(viewModel.isAdReady ? Color.blue : Color.gray)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
            .disabled(!viewModel.isAdReady)
        }
        .alert(isPresented: $viewModel.showingAlert) {
            Alert(
                title: Text("알림"),
                message: Text(viewModel.alertMessage),
                dismissButton: .default(Text("확인"))
            )
        }
    }
}

Objective-C 예제

@import AdropAds;

@interface RewardedViewController () <AdropRewardedAdDelegate>
@property (nonatomic, strong) AdropRewardedAd *rewardedAd;
@end

@implementation RewardedViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 1. AdropRewardedAd 인스턴스 생성
    self.rewardedAd = [[AdropRewardedAd alloc] initWithUnitId:@"YOUR_UNIT_ID"];

    // 2. Delegate 설정
    self.rewardedAd.delegate = self;

    // 3. 광고 로드
    [self.rewardedAd load];
}

- (IBAction)showRewardedAdButtonTapped:(UIButton *)sender {
    // 광고가 로드되었는지 확인
    if (!self.rewardedAd.isLoaded) {
        NSLog(@"광고가 아직 로드되지 않았습니다");
        return;
    }

    // 4. 광고 표시 및 보상 처리
    __weak typeof(self) weakSelf = self;
    [self.rewardedAd showFromRootViewController:self
                        userDidEarnRewardHandler:^(NSInteger type, NSInteger amount) {
        NSLog(@"보상 획득 - 타입: %ld, 수량: %ld", (long)type, (long)amount);
        [weakSelf grantRewardWithType:type amount:amount];
    }];
}

- (void)grantRewardWithType:(NSInteger)type amount:(NSInteger)amount {
    // 사용자에게 보상 지급
}

#pragma mark - AdropRewardedAdDelegate

// 필수: 광고 수신 성공
- (void)onAdReceived:(AdropRewardedAd *)ad {
    NSLog(@"광고 수신 완료");
}

// 필수: 광고 수신 실패
- (void)onAdFailedToReceive:(AdropRewardedAd *)ad :(AdropErrorCode)errorCode {
    NSLog(@"광고 수신 실패: %ld", (long)errorCode);
}

// 선택: 광고 노출
- (void)onAdImpression:(AdropRewardedAd *)ad {
    NSLog(@"광고 노출됨");
}

// 선택: 광고 클릭
- (void)onAdClicked:(AdropRewardedAd *)ad {
    NSLog(@"광고 클릭됨");
}

// 선택: 광고 화면 표시 직전
- (void)onAdWillPresentFullScreen:(AdropRewardedAd *)ad {
    NSLog(@"광고 화면 표시 예정");
}

// 선택: 광고 화면 표시 완료
- (void)onAdDidPresentFullScreen:(AdropRewardedAd *)ad {
    NSLog(@"광고 화면 표시 완료");
}

// 선택: 광고 화면 닫기 직전
- (void)onAdWillDismissFullScreen:(AdropRewardedAd *)ad {
    NSLog(@"광고 화면 닫기 예정");
}

// 선택: 광고 화면 닫기 완료
- (void)onAdDidDismissFullScreen:(AdropRewardedAd *)ad {
    NSLog(@"광고 화면 닫힘");

    // 다음 광고 미리 로드
    [self.rewardedAd load];
}

// 선택: 광고 표시 실패
- (void)onAdFailedToShowFullScreen:(AdropRewardedAd *)ad :(AdropErrorCode)errorCode {
    NSLog(@"광고 표시 실패: %ld", (long)errorCode);
}

@end

Delegate 메서드

필수 메서드

onAdReceived(_:)
void
광고 수신에 성공했을 때 호출됩니다. 이 시점부터 show() 메서드로 광고를 표시할 수 있습니다.
onAdFailedToReceive(_:_:)
void
광고 수신에 실패했을 때 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

선택 메서드

onAdImpression(_:)
void
광고가 노출되어 노출 기록이 전송되었을 때 호출됩니다.
onAdClicked(_:)
void
사용자가 광고를 클릭했을 때 호출됩니다.
onAdWillPresentFullScreen(_:)
void
광고 화면이 표시되기 직전에 호출됩니다. 배경 음악을 일시정지하는 등의 처리를 할 수 있습니다.
onAdDidPresentFullScreen(_:)
void
광고 화면이 완전히 표시된 후 호출됩니다.
onAdWillDismissFullScreen(_:)
void
광고 화면이 닫히기 직전에 호출됩니다.
onAdDidDismissFullScreen(_:)
void
광고 화면이 완전히 닫힌 후 호출됩니다. 배경 음악을 재개하거나 다음 광고를 미리 로드할 수 있습니다.
onAdFailedToShowFullScreen(_:_:)
void
광고 표시에 실패했을 때 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

보상 처리

보상 콜백

show() 메서드의 userDidEarnRewardHandler 파라미터로 보상 콜백을 전달합니다.
rewardedAd?.show(fromRootViewController: self) { type, amount in
    // type: 보상 타입 (Int)
    // amount: 보상 수량 (Int)
    print("보상 획득 - 타입: \(type), 수량: \(amount)")
}

보상 타입과 수량

  • type: 애드컨트롤 콘솔에서 설정한 보상 타입 (정수 값)
  • amount: 애드컨트롤 콘솔에서 설정한 보상 수량 (정수 값)

Best Practices

1. 광고 미리 로드하기

사용자 경험을 위해 광고를 미리 로드해두는 것이 좋습니다.
class GameViewController: UIViewController {
    private var rewardedAd: AdropRewardedAd?

    override func viewDidLoad() {
        super.viewDidLoad()

        // 화면 진입 시 광고 미리 로드
        loadRewardedAd()
    }

    private func loadRewardedAd() {
        rewardedAd = AdropRewardedAd(unitId: "YOUR_UNIT_ID")
        rewardedAd?.delegate = self
        rewardedAd?.load()
    }

    private func showRewardedAd() {
        rewardedAd?.show(fromRootViewController: self) { [weak self] type, amount in
            self?.grantReward(type: type, amount: amount)
        }
    }
}

extension GameViewController: AdropRewardedAdDelegate {
    func onAdDidDismissFullScreen(_ ad: AdropRewardedAd) {
        // 광고가 닫힌 후 다음 광고 미리 로드
        loadRewardedAd()
    }
}

2. 광고 준비 상태 확인

광고가 로드되었는지 확인하고 UI를 업데이트합니다.
class GameViewController: UIViewController {
    @IBOutlet weak var watchAdButton: UIButton!
    private var rewardedAd: AdropRewardedAd?
    private var isAdReady = false

    private func updateButtonState() {
        watchAdButton.isEnabled = isAdReady
        watchAdButton.alpha = isAdReady ? 1.0 : 0.5
        watchAdButton.setTitle(
            isAdReady ? "동영상 보고 생명 받기" : "광고 로딩중...",
            for: .normal
        )
    }
}

extension GameViewController: AdropRewardedAdDelegate {
    func onAdReceived(_ ad: AdropRewardedAd) {
        isAdReady = true
        updateButtonState()
    }

    func onAdFailedToReceive(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        isAdReady = false
        updateButtonState()
    }

    func onAdDidDismissFullScreen(_ ad: AdropRewardedAd) {
        isAdReady = false
        updateButtonState()

        // 다음 광고 로드
        rewardedAd?.load()
    }
}

3. 배경 음악 처리

광고 표시 전후로 배경 음악을 적절히 제어합니다.
extension GameViewController: AdropRewardedAdDelegate {
    func onAdWillPresentFullScreen(_ ad: AdropRewardedAd) {
        // 광고 표시 직전 배경 음악 일시정지
        AudioManager.shared.pauseBackgroundMusic()
    }

    func onAdDidDismissFullScreen(_ ad: AdropRewardedAd) {
        // 광고 종료 후 배경 음악 재개
        AudioManager.shared.resumeBackgroundMusic()
    }
}

4. 에러 처리

광고 로드 실패 시 재시도 로직을 구현합니다.
extension GameViewController: AdropRewardedAdDelegate {
    func onAdFailedToReceive(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        print("광고 로드 실패: \(errorCode)")

        // 네트워크 에러인 경우 재시도
        if errorCode == .networkError {
            DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { [weak self] in
                self?.rewardedAd?.load()
            }
        }
    }

    func onAdFailedToShowFullScreen(_ ad: AdropRewardedAd, _ errorCode: AdropErrorCode) {
        print("광고 표시 실패: \(errorCode)")

        // 사용자에게 알림
        showAlert(message: "광고를 표시할 수 없습니다. 나중에 다시 시도해주세요.")
    }
}

5. 메모리 관리

ViewController가 해제될 때 광고 객체도 정리합니다.
class GameViewController: UIViewController {
    private var rewardedAd: AdropRewardedAd?

    deinit {
        rewardedAd?.delegate = nil
        rewardedAd = nil
    }
}

테스트

테스트 유닛 ID

개발 중에는 항상 테스트 유닛 ID를 사용하세요.
// 개발 환경
let rewardedAd = AdropRewardedAd(unitId: "PUBLIC_TEST_UNIT_ID_REWARDED")

// 프로덕션 환경
let rewardedAd = AdropRewardedAd(unitId: "YOUR_PRODUCTION_UNIT_ID")
실제 유닛 ID로 테스트하면 무효 트래픽으로 간주되어 계정이 정지될 수 있습니다. 반드시 테스트 유닛 ID를 사용하세요.

환경별 유닛 ID 관리

빌드 구성에 따라 자동으로 유닛 ID를 변경하는 방법입니다.
enum AdUnitID {
    static var rewarded: String {
        #if DEBUG
        return "PUBLIC_TEST_UNIT_ID_REWARDED"
        #else
        return "YOUR_PRODUCTION_UNIT_ID"
        #endif
    }
}

// 사용
let rewardedAd = AdropRewardedAd(unitId: AdUnitID.rewarded)

관련 문서