메인 콘텐츠로 건너뛰기

개요

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

특징

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

구현 단계

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

기본 구현

AdropInterstitialAd 인스턴스 생성

import io.adrop.ads.interstitial.AdropInterstitialAd

class MainActivity : AppCompatActivity() {
    private var interstitialAd: AdropInterstitialAd? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. 전면 광고 인스턴스 생성
        interstitialAd = AdropInterstitialAd(this, "YOUR_UNIT_ID")
    }
}

AdropInterstitialAd 생성자

context
Context
required
Android Context 객체 (Activity 또는 Application Context)
unitId
String
required
광고 유닛 ID (콘솔에서 발급)

리스너 설정

광고 이벤트를 수신하려면 AdropInterstitialAdListener를 구현하고 설정해야 합니다.
import io.adrop.ads.interstitial.AdropInterstitialAdListener
import io.adrop.ads.model.AdropErrorCode

class MainActivity : AppCompatActivity() {
    private var interstitialAd: AdropInterstitialAd? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. 전면 광고 인스턴스 생성
        interstitialAd = AdropInterstitialAd(this, "YOUR_UNIT_ID")

        // 2. 리스너 설정
        interstitialAd?.interstitialAdListener = object : AdropInterstitialAdListener {
            override fun onAdReceived(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 수신 완료")
            }

            override fun onAdFailedToReceive(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
                Log.e("Adrop", "전면 광고 수신 실패: $errorCode")
            }

            override fun onAdImpression(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 노출")
            }

            override fun onAdClicked(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 클릭")
            }

            override fun onAdWillPresentFullScreen(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 표시 직전")
            }

            override fun onAdDidPresentFullScreen(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 표시 완료")
            }

            override fun onAdWillDismissFullScreen(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 닫히기 직전")
            }

            override fun onAdDidDismissFullScreen(ad: AdropInterstitialAd) {
                Log.d("Adrop", "전면 광고 닫힘")
                // 다음 광고를 미리 로드
                loadInterstitialAd()
            }

            override fun onAdFailedToShowFullScreen(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
                Log.e("Adrop", "전면 광고 표시 실패: $errorCode")
            }
        }

        // 3. 광고 로드
        loadInterstitialAd()
    }

    private fun loadInterstitialAd() {
        interstitialAd?.load()
    }
}

광고 로드

load() 메서드를 호출하여 광고를 요청합니다.
private fun loadInterstitialAd() {
    interstitialAd?.load()
}
광고 로드 완료 시 onAdReceived 콜백이 호출되며, 실패 시 onAdFailedToReceive 콜백이 호출됩니다.

광고 표시

광고가 로드된 후 show() 메서드를 호출하여 광고를 표시합니다.

isLoaded 프로퍼티

광고가 로드되었는지 확인하는 프로퍼티입니다. show() 호출 전에 이 값을 확인하는 것이 좋습니다.
private fun showInterstitialAd() {
    if (interstitialAd?.isLoaded == true) {
        interstitialAd?.show(this)
    } else {
        Log.d("Adrop", "광고가 아직 로드되지 않았습니다")
    }
}

show 메서드

activity
Activity
required
광고를 표시할 Activity 객체

AdropInterstitialAd 프로퍼티

unitId

광고 유닛 ID를 반환합니다.
val unitId: String = interstitialAd?.unitId ?: ""

isLoaded

광고가 로드되었는지 여부를 반환합니다.
val isLoaded: Boolean = interstitialAd?.isLoaded ?: false

creativeId

현재 로드된 광고의 크리에이티브 ID를 반환합니다.
val creativeId: String = interstitialAd?.creativeId ?: ""

txId

현재 로드된 광고의 트랜잭션 ID를 반환합니다.
val txId: String = interstitialAd?.txId ?: ""

campaignId

현재 로드된 광고의 캠페인 ID를 반환합니다.
val campaignId: String = interstitialAd?.campaignId ?: ""

isBackfilled

현재 로드된 광고가 백필 광고인지 여부를 반환합니다.
val isBackfilled: Boolean = interstitialAd?.isBackfilled ?: false

AdropInterstitialAdListener 메서드

필수 메서드

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

선택 메서드

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

생명주기 관리

destroy 메서드

Activity나 Fragment가 종료될 때 destroy() 메서드를 호출하여 리소스를 해제해야 합니다.
override fun onDestroy() {
    super.onDestroy()
    interstitialAd?.destroy()
    interstitialAd = null
}
메모리 누수를 방지하기 위해 반드시 destroy()를 호출하세요.

사전 로드 전략

사용자 경험을 향상시키기 위해 광고를 미리 로드하는 것이 좋습니다.

기본 사전 로드

class GameActivity : AppCompatActivity() {
    private var interstitialAd: AdropInterstitialAd? = null
    private var isAdReady = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_game)

        // 화면 진입 시 미리 로드
        preloadInterstitialAd()
    }

    private fun preloadInterstitialAd() {
        interstitialAd = AdropInterstitialAd(this, "YOUR_UNIT_ID")
        interstitialAd?.interstitialAdListener = object : AdropInterstitialAdListener {
            override fun onAdReceived(ad: AdropInterstitialAd) {
                isAdReady = true
                Log.d("Adrop", "전면 광고 준비 완료")
            }

            override fun onAdFailedToReceive(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
                isAdReady = false
                Log.e("Adrop", "전면 광고 로드 실패: $errorCode")
            }

            override fun onAdDidDismissFullScreen(ad: AdropInterstitialAd) {
                isAdReady = false
                // 다음 광고 미리 로드
                preloadInterstitialAd()
            }
        }
        interstitialAd?.load()
    }

    private fun onGameLevelComplete() {
        // 레벨 완료 시 즉시 표시
        if (isAdReady) {
            interstitialAd?.show(this)
        }
    }
}

닫기 후 재로드

광고가 닫힌 후 onAdDidDismissFullScreen 콜백에서 다음 광고를 미리 로드합니다.
override fun onAdDidDismissFullScreen(ad: AdropInterstitialAd) {
    Log.d("Adrop", "전면 광고 닫힘")
    // 즉시 다음 광고 로드
    interstitialAd?.load()
}

베스트 프랙티스

1. 적절한 표시 시점

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

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

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

2. 에러 처리

광고 로드 실패에 대비한 처리를 구현하세요.
override fun onAdFailedToReceive(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
    when (errorCode) {
        AdropErrorCode.ERROR_CODE_NETWORK -> {
            Log.e("Adrop", "네트워크 오류: 나중에 다시 시도")
            retryAfterDelay()
        }
        AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
            Log.w("Adrop", "표시할 광고 없음")
            continueWithoutAd()
        }
        else -> {
            Log.e("Adrop", "광고 로드 실패: $errorCode")
        }
    }
}

private fun retryAfterDelay() {
    Handler(Looper.getMainLooper()).postDelayed({
        interstitialAd?.load()
    }, 30000) // 30초 후 재시도
}

private fun continueWithoutAd() {
    // 광고 없이 계속 진행
    proceedToNextScreen()
}

3. 빈도 제한

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

    fun canShowAd(): Boolean {
        val currentTime = System.currentTimeMillis()
        return currentTime - lastAdShownTime >= minimumInterval
    }

    fun recordAdShown() {
        lastAdShownTime = System.currentTimeMillis()
    }
}

// 사용 예시
class MainActivity : AppCompatActivity() {
    private val frequencyManager = AdFrequencyManager()

    private fun showInterstitialIfAllowed() {
        if (!frequencyManager.canShowAd()) {
            Log.d("Adrop", "광고 표시 간격이 너무 짧음")
            return
        }

        interstitialAd?.show(this)
    }

    // 리스너에서 호출
    override fun onAdDidPresentFullScreen(ad: AdropInterstitialAd) {
        frequencyManager.recordAdShown()
    }
}

4. 게임 일시정지 처리

전면 광고 표시 시 게임이나 애니메이션을 일시정지하세요.
override fun onAdWillPresentFullScreen(ad: AdropInterstitialAd) {
    // 게임 일시정지
    pauseGame()
    // 배경음악 중지
    pauseBackgroundMusic()
}

override fun onAdDidDismissFullScreen(ad: AdropInterstitialAd) {
    // 게임 재개
    resumeGame()
    // 배경음악 재생
    resumeBackgroundMusic()
}

테스트

테스트 유닛 ID 사용

개발 중에는 테스트 유닛 ID를 사용하세요.
import io.adrop.ads.AdropAds

class MainActivity : AppCompatActivity() {
    private val unitId = if (BuildConfig.DEBUG) {
        "PUBLIC_TEST_UNIT_ID_INTERSTITIAL"
    } else {
        "YOUR_PRODUCTION_UNIT_ID"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        interstitialAd = AdropInterstitialAd(this, unitId)
    }
}

광고 로드 확인

광고가 정상적으로 로드되는지 확인하세요.
override fun onAdReceived(ad: AdropInterstitialAd) {
    Log.d("Adrop", "✅ 전면 광고 로드 성공")
    Log.d("Adrop", "Unit ID: ${ad.unitId}")
    Log.d("Adrop", "Creative ID: ${ad.creativeId}")
    Log.d("Adrop", "Is Backfilled: ${ad.isBackfilled}")
}

override fun onAdFailedToReceive(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
    Log.e("Adrop", "❌ 전면 광고 로드 실패: $errorCode")
    if (BuildConfig.DEBUG) {
        Toast.makeText(this, "광고 로드 실패: $errorCode", Toast.LENGTH_SHORT).show()
    }
}

완전한 구현 예제

import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import io.adrop.ads.interstitial.AdropInterstitialAd
import io.adrop.ads.interstitial.AdropInterstitialAdListener
import io.adrop.ads.model.AdropErrorCode

class InterstitialAdActivity : AppCompatActivity() {
    private var interstitialAd: AdropInterstitialAd? = null
    private lateinit var loadButton: Button
    private lateinit var showButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_interstitial_ad)

        loadButton = findViewById(R.id.btn_load_ad)
        showButton = findViewById(R.id.btn_show_ad)

        // 버튼 초기 상태 설정
        showButton.isEnabled = false

        // 전면 광고 초기화
        setupInterstitialAd()

        // 버튼 클릭 리스너
        loadButton.setOnClickListener {
            loadInterstitialAd()
        }

        showButton.setOnClickListener {
            showInterstitialAd()
        }

        // 자동으로 첫 광고 로드
        loadInterstitialAd()
    }

    private fun setupInterstitialAd() {
        val unitId = if (BuildConfig.DEBUG) {
            "PUBLIC_TEST_UNIT_ID_INTERSTITIAL"
        } else {
            "YOUR_PRODUCTION_UNIT_ID"
        }

        interstitialAd = AdropInterstitialAd(this, unitId)
        interstitialAd?.interstitialAdListener = object : AdropInterstitialAdListener {
            override fun onAdReceived(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 수신 완료")
                showButton.isEnabled = true
                loadButton.isEnabled = false
                Toast.makeText(
                    this@InterstitialAdActivity,
                    "광고가 준비되었습니다",
                    Toast.LENGTH_SHORT
                ).show()
            }

            override fun onAdFailedToReceive(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
                Log.e(TAG, "전면 광고 수신 실패: $errorCode")
                showButton.isEnabled = false
                loadButton.isEnabled = true
                Toast.makeText(
                    this@InterstitialAdActivity,
                    "광고 로드 실패: $errorCode",
                    Toast.LENGTH_SHORT
                ).show()
            }

            override fun onAdImpression(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 노출")
            }

            override fun onAdClicked(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 클릭")
            }

            override fun onAdWillPresentFullScreen(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 표시 직전")
            }

            override fun onAdDidPresentFullScreen(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 표시 완료")
            }

            override fun onAdWillDismissFullScreen(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 닫히기 직전")
            }

            override fun onAdDidDismissFullScreen(ad: AdropInterstitialAd) {
                Log.d(TAG, "전면 광고 닫힘")
                showButton.isEnabled = false
                loadButton.isEnabled = true
                Toast.makeText(
                    this@InterstitialAdActivity,
                    "광고가 닫혔습니다",
                    Toast.LENGTH_SHORT
                ).show()

                // 다음 광고를 미리 로드
                loadInterstitialAd()
            }

            override fun onAdFailedToShowFullScreen(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
                Log.e(TAG, "전면 광고 표시 실패: $errorCode")
                showButton.isEnabled = false
                loadButton.isEnabled = true
                Toast.makeText(
                    this@InterstitialAdActivity,
                    "광고 표시 실패: $errorCode",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }

    private fun loadInterstitialAd() {
        Log.d(TAG, "전면 광고 로드 시작")
        loadButton.isEnabled = false
        interstitialAd?.load()
    }

    private fun showInterstitialAd() {
        if (interstitialAd?.isLoaded == true) {
            Log.d(TAG, "전면 광고 표시")
            interstitialAd?.show(this)
        } else {
            Log.w(TAG, "광고가 아직 로드되지 않았습니다")
            Toast.makeText(this, "광고가 준비되지 않았습니다", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        interstitialAd?.destroy()
        interstitialAd = null
    }

    companion object {
        private const val TAG = "InterstitialAdActivity"
    }
}

문제 해결

  • SDK가 초기화되었는지 확인
  • 유닛 ID가 올바른지 확인
  • 네트워크 연결 상태 확인
  • AndroidManifest.xml에 인터넷 권한이 설정되어 있는지 확인
  • 에러 코드를 확인하여 원인 파악
  • ERROR_CODE_AD_NO_FILL: 광고 인벤토리 부족, 나중에 재시도
  • ERROR_CODE_NETWORK: 네트워크 연결 확인
  • ERROR_CODE_INVALID_UNIT: 유닛 ID 확인
  • onAdReceived 콜백 이후에 show()를 호출했는지 확인
  • isLoaded 프로퍼티가 true인지 확인
  • Activity가 유효한지 확인
  • 다른 전면 광고가 이미 표시 중이지 않은지 확인
  • onDestroy()에서 destroy() 메서드 호출 확인
  • Context 참조가 WeakReference로 관리되는지 확인
  • 리스너를 null로 설정하는지 확인

다음 단계