메인 콘텐츠로 건너뛰기

개요

전면 광고(Interstitial Ad)는 앱의 화면 전체를 덮는 형태로 표시되는 광고입니다. 게임의 레벨 전환, 콘텐츠 페이지 전환 등 앱의 자연스러운 전환 시점에 표시하기 적합합니다.

특징

  • 전체 화면을 덮는 몰입형 광고
  • 사용자가 명시적으로 닫기 전까지 유지
  • 이미지 및 동영상 광고 지원
  • 높은 시각적 주목도
개발 환경에서는 테스트 유닛 ID를 사용하세요: PUBLIC_TEST_UNIT_ID_INTERSTITIAL

구현 단계

전면 광고는 다음 4단계로 구현합니다:
  1. 초기화 - AdropInterstitialAd 인스턴스 생성
  2. 델리게이트 설정 - 광고 이벤트 수신을 위한 델리게이트 설정
  3. 광고 로드 - 광고 요청 및 수신
  4. 광고 표시 - 화면에 광고 표시

UIKit 구현

기본 구현

import AdropAds

class ViewController: UIViewController {
    private var interstitialAd: AdropInterstitialAd?

    override func viewDidLoad() {
        super.viewDidLoad()
        loadInterstitialAd()
    }

    // 1. 광고 초기화 및 로드
    private func loadInterstitialAd() {
        interstitialAd = AdropInterstitialAd(unitId: "YOUR_UNIT_ID")
        interstitialAd?.delegate = self
        interstitialAd?.load()
    }

    // 2. 광고 표시
    private func showInterstitialAd() {
        guard let interstitialAd = interstitialAd,
              interstitialAd.isLoaded else { return }
        interstitialAd.show(fromRootViewController: self)
    }
}

isLoaded 프로퍼티

광고가 로드되었는지 확인하는 프로퍼티입니다. show() 호출 전에 이 값을 확인하는 것이 좋습니다.
if interstitialAd?.isLoaded == true {
    interstitialAd?.show(fromRootViewController: self)
}

델리게이트 구현

extension ViewController: AdropInterstitialAdDelegate {
    // 광고 수신 성공 (필수)
    func onAdReceived(_ ad: AdropInterstitialAd) {
        print("전면 광고 수신 완료")
        // 광고가 준비되면 표시
        showInterstitialAd()
    }

    // 광고 수신 실패 (필수)
    func onAdFailedToReceive(_ ad: AdropInterstitialAd, _ errorCode: AdropErrorCode) {
        print("전면 광고 수신 실패: \(errorCode)")
    }

    // 광고 노출 (선택)
    func onAdImpression(_ ad: AdropInterstitialAd) {
        print("전면 광고 노출")
    }

    // 광고 클릭 (선택)
    func onAdClicked(_ ad: AdropInterstitialAd) {
        print("전면 광고 클릭")
    }

    // 전면 광고가 표시되기 직전 (선택)
    func onAdWillPresentFullScreen(_ ad: AdropInterstitialAd) {
        print("전면 광고 표시 직전")
    }

    // 전면 광고가 표시된 직후 (선택)
    func onAdDidPresentFullScreen(_ ad: AdropInterstitialAd) {
        print("전면 광고 표시 완료")
    }

    // 전면 광고가 닫히기 직전 (선택)
    func onAdWillDismissFullScreen(_ ad: AdropInterstitialAd) {
        print("전면 광고 닫히기 직전")
    }

    // 전면 광고가 닫힌 직후 (선택)
    func onAdDidDismissFullScreen(_ ad: AdropInterstitialAd) {
        print("전면 광고 닫힘")
        // 다음 광고를 미리 로드
        loadInterstitialAd()
    }

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

SwiftUI 구현

SwiftUI에서는 UIViewControllerRepresentable을 사용하거나, UIWindow에서 rootViewController를 가져와 표시할 수 있습니다.

방법 1: ViewModel 패턴

import SwiftUI
import AdropAds

// ViewModel
class InterstitialAdViewModel: ObservableObject {
    @Published var isAdReady = false
    @Published var isAdShowing = false

    private var interstitialAd: AdropInterstitialAd?

    init() {
        loadAd()
    }

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

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

        interstitialAd.show(fromRootViewController: rootViewController)
    }
}

// Delegate
extension InterstitialAdViewModel: AdropInterstitialAdDelegate {
    func onAdReceived(_ ad: AdropInterstitialAd) {
        DispatchQueue.main.async {
            self.isAdReady = true
        }
    }

    func onAdFailedToReceive(_ ad: AdropInterstitialAd, _ errorCode: AdropErrorCode) {
        print("광고 수신 실패: \(errorCode)")
    }

    func onAdDidPresentFullScreen(_ ad: AdropInterstitialAd) {
        DispatchQueue.main.async {
            self.isAdShowing = true
        }
    }

    func onAdDidDismissFullScreen(_ ad: AdropInterstitialAd) {
        DispatchQueue.main.async {
            self.isAdShowing = false
            self.isAdReady = false
        }
        // 다음 광고 미리 로드
        loadAd()
    }
}

// View
struct ContentView: View {
    @StateObject private var adViewModel = InterstitialAdViewModel()

    var body: some View {
        VStack {
            Text("전면 광고 예제")
                .font(.title)

            Button("전면 광고 표시") {
                adViewModel.showAd()
            }
            .disabled(!adViewModel.isAdReady)
            .padding()
        }
    }
}

방법 2: Helper를 이용한 간단한 구현

import SwiftUI
import AdropAds

// Helper
class InterstitialAdHelper: NSObject, ObservableObject, AdropInterstitialAdDelegate {
    @Published var isAdReady = false
    private var interstitialAd: AdropInterstitialAd?

    func loadAd(unitId: String) {
        interstitialAd = AdropInterstitialAd(unitId: unitId)
        interstitialAd?.delegate = self
        interstitialAd?.load()
    }

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

        interstitialAd?.show(fromRootViewController: rootViewController)
    }

    func onAdReceived(_ ad: AdropInterstitialAd) {
        DispatchQueue.main.async {
            self.isAdReady = true
        }
    }

    func onAdFailedToReceive(_ ad: AdropInterstitialAd, _ errorCode: AdropErrorCode) {
        print("광고 수신 실패: \(errorCode)")
    }

    func onAdDidDismissFullScreen(_ ad: AdropInterstitialAd) {
        DispatchQueue.main.async {
            self.isAdReady = false
        }
    }
}

// View
struct GameView: View {
    @StateObject private var interstitialHelper = InterstitialAdHelper()
    @State private var level = 1

    var body: some View {
        VStack(spacing: 20) {
            Text("레벨 \(level)")
                .font(.largeTitle)

            Button("다음 레벨") {
                if interstitialHelper.isAdReady {
                    interstitialHelper.showAd()
                }
                level += 1
            }
            .padding()
        }
        .onAppear {
            interstitialHelper.loadAd(unitId: "YOUR_UNIT_ID")
        }
    }
}

델리게이트 메서드

필수 메서드

onAdReceived
(AdropInterstitialAd) -> Void
광고 수신 성공 시 호출됩니다. 이 시점에서 show()를 호출하여 광고를 표시할 수 있습니다.
onAdFailedToReceive
(AdropInterstitialAd, AdropErrorCode) -> Void
광고 수신 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

선택 메서드

onAdImpression
(AdropInterstitialAd) -> Void
광고 노출이 기록되었을 때 호출됩니다.
onAdClicked
(AdropInterstitialAd) -> Void
사용자가 광고를 클릭했을 때 호출됩니다.
onAdWillPresentFullScreen
(AdropInterstitialAd) -> Void
전면 광고가 표시되기 직전에 호출됩니다. 애니메이션 일시정지 등의 작업을 수행할 수 있습니다.
onAdDidPresentFullScreen
(AdropInterstitialAd) -> Void
전면 광고가 화면에 표시된 직후 호출됩니다.
onAdWillDismissFullScreen
(AdropInterstitialAd) -> Void
전면 광고가 닫히기 직전에 호출됩니다.
onAdDidDismissFullScreen
(AdropInterstitialAd) -> Void
전면 광고가 닫힌 직후 호출됩니다. 다음 광고를 미리 로드하기 좋은 시점입니다.
onAdFailedToShowFullScreen
(AdropInterstitialAd, AdropErrorCode) -> Void
광고 표시 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

생명주기

전면 광고는 다음과 같은 생명주기를 가집니다:

베스트 프랙티스

1. 광고 미리 로드

광고를 표시하기 전에 미리 로드하여 사용자 경험을 개선하세요.
class GameViewController: UIViewController {
    private var interstitialAd: AdropInterstitialAd?
    private var isAdReady = false

    override func viewDidLoad() {
        super.viewDidLoad()
        // 화면 진입 시 미리 로드
        preloadInterstitialAd()
    }

    private func preloadInterstitialAd() {
        interstitialAd = AdropInterstitialAd(unitId: "YOUR_UNIT_ID")
        interstitialAd?.delegate = self
        interstitialAd?.load()
    }

    func onGameLevelComplete() {
        // 레벨 완료 시 즉시 표시
        if isAdReady {
            interstitialAd?.show(fromRootViewController: self)
        }
    }
}

extension GameViewController: AdropInterstitialAdDelegate {
    func onAdReceived(_ ad: AdropInterstitialAd) {
        isAdReady = true
    }

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

2. 적절한 표시 시점

앱의 자연스러운 전환 시점에 광고를 표시하세요.
// ✅ 좋은 예: 게임 레벨 전환
func onLevelComplete() {
    saveProgress()
    showInterstitialAd()
    loadNextLevel()
}

// ✅ 좋은 예: 콘텐츠 읽기 완료
func onArticleFinished() {
    showInterstitialAd()
}

// ❌ 나쁜 예: 사용자 액션 중간
func onButtonTap() {
    showInterstitialAd() // 사용자 경험 저해
    performAction()
}

3. 닫기 후 재로드

광고가 닫힌 후 다음 광고를 미리 로드하세요.
func onAdDidDismissFullScreen(_ ad: AdropInterstitialAd) {
    // 즉시 다음 광고 로드
    loadInterstitialAd()
}

4. 에러 처리

광고 로드 실패에 대비한 처리를 구현하세요.
func onAdFailedToReceive(_ ad: AdropInterstitialAd, _ errorCode: AdropErrorCode) {
    switch errorCode {
    case .networkError:
        print("네트워크 오류: 나중에 다시 시도")
        retryAfterDelay()
    case .noFill:
        print("표시할 광고 없음")
        continueWithoutAd()
    default:
        print("광고 로드 실패: \(errorCode)")
    }
}

private func retryAfterDelay() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
        self.loadInterstitialAd()
    }
}

5. 빈도 제한

너무 자주 광고를 표시하지 않도록 제한하세요.
class AdFrequencyManager {
    private var lastAdShownTime: Date?
    private let minimumInterval: TimeInterval = 180 // 3분

    func canShowAd() -> Bool {
        guard let lastTime = lastAdShownTime else {
            return true
        }

        return Date().timeIntervalSince(lastTime) >= minimumInterval
    }

    func recordAdShown() {
        lastAdShownTime = Date()
    }
}

// 사용 예시
let frequencyManager = AdFrequencyManager()

func showInterstitialIfAllowed() {
    guard frequencyManager.canShowAd() else {
        print("광고 표시 간격이 너무 짧음")
        return
    }

    interstitialAd?.show(fromRootViewController: self)
}

func onAdDidPresentFullScreen(_ ad: AdropInterstitialAd) {
    frequencyManager.recordAdShown()
}

테스트

테스트 유닛 ID 사용

개발 중에는 테스트 유닛 ID를 사용하세요.
#if DEBUG
let unitId = "PUBLIC_TEST_UNIT_ID_INTERSTITIAL"
#else
let unitId = "YOUR_PRODUCTION_UNIT_ID"
#endif

interstitialAd = AdropInterstitialAd(unitId: unitId)

광고 로드 확인

광고가 정상적으로 로드되는지 확인하세요.
func onAdReceived(_ ad: AdropInterstitialAd) {
    print("✅ 전면 광고 로드 성공")
    assert(interstitialAd != nil, "광고 인스턴스가 nil입니다")
}

func onAdFailedToReceive(_ ad: AdropInterstitialAd, _ errorCode: AdropErrorCode) {
    print("❌ 전면 광고 로드 실패: \(errorCode)")
    // 개발 환경에서는 경고 표시
    #if DEBUG
    showDebugAlert("광고 로드 실패: \(errorCode)")
    #endif
}

문제 해결

광고가 표시되지 않음

  • SDK가 초기화되었는지 확인
  • 유닛 ID가 올바른지 확인
  • 네트워크 연결 상태 확인
  • production 모드 설정 확인 (배포 시 true)
  • 에러 코드를 확인하여 원인 파악
  • 테스트 환경에서는 production: false 설정
  • 광고 인벤토리 부족 시 나중에 재시도
  • onAdReceived 콜백 이후에 show()를 호출했는지 확인
  • rootViewController가 유효한지 확인
  • 다른 뷰 컨트롤러가 이미 present되어 있지 않은지 확인

SwiftUI에서 rootViewController를 찾을 수 없음

// 안전하게 rootViewController 가져오기
func getRootViewController() -> UIViewController? {
    guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
          let rootViewController = windowScene.windows.first?.rootViewController else {
        print("rootViewController를 찾을 수 없습니다")
        return nil
    }

    // 최상위 presented view controller 찾기
    var topController = rootViewController
    while let presented = topController.presentedViewController {
        topController = presented
    }

    return topController
}

// 사용
if let rootVC = getRootViewController() {
    interstitialAd?.show(fromRootViewController: rootVC)
}

다음 단계