> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 전면 광고

> Android 앱에서 전면 광고를 구현하는 방법을 안내합니다.

## 개요

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

### 특징

* 전체 화면을 덮는 몰입형 광고
* 사용자가 명시적으로 닫기 전까지 유지
* 이미지 및 동영상 광고 지원
* 높은 시각적 주목도

<Note>
  개발 환경에서는 테스트 유닛 ID를 사용하세요: `PUBLIC_TEST_UNIT_ID_INTERSTITIAL`
</Note>

***

## 구현 단계

전면 광고는 다음 4단계로 구현합니다:

1. **초기화** - AdropInterstitialAd 인스턴스 생성
2. **리스너 설정** - 광고 이벤트 수신을 위한 리스너 설정
3. **광고 로드** - 광고 요청 및 수신
4. **광고 표시** - 화면에 광고 표시

***

## 기본 구현

### AdropInterstitialAd 인스턴스 생성

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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")
      }
  }
  ```

  ```java Java theme={null}
  import io.adrop.ads.interstitial.AdropInterstitialAd;

  public class MainActivity extends AppCompatActivity {
      private AdropInterstitialAd interstitialAd;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);

          // 1. 전면 광고 인스턴스 생성
          interstitialAd = new AdropInterstitialAd(this, "YOUR_UNIT_ID");
      }
  }
  ```
</CodeGroup>

### AdropInterstitialAd 생성자

<ParamField body="context" type="Context" required>
  Android Context 객체 (Activity 또는 Application Context)
</ParamField>

<ParamField body="unitId" type="String" required>
  광고 유닛 ID (콘솔에서 발급)
</ParamField>

***

## 리스너 설정

광고 이벤트를 수신하려면 `AdropInterstitialAdListener`를 구현하고 설정해야 합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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")
              }
          }

          // 2-1. 백버튼 콜백 리스너 설정
          interstitialAd?.closeListener = object : AdropInterstitialAdCloseListener {
              override fun onBackPressed(ad: AdropInterstitialAd) {
                  Log.d("Adrop", "뒤로가기 버튼 클릭")
              }
          }

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

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

  ```java Java theme={null}
  import io.adrop.ads.interstitial.AdropInterstitialAdListener;
  import io.adrop.ads.model.AdropErrorCode;

  public class MainActivity extends AppCompatActivity {
      private AdropInterstitialAd interstitialAd;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);

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

          // 2. 리스너 설정
          interstitialAd.setInterstitialAdListener(new AdropInterstitialAdListener() {
              @Override
              public void onAdReceived(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 수신 완료");
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.e("Adrop", "전면 광고 수신 실패: " + errorCode);
              }

              @Override
              public void onAdImpression(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 노출");
              }

              @Override
              public void onAdClicked(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 클릭");
              }

              @Override
              public void onAdWillPresentFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 표시 직전");
              }

              @Override
              public void onAdDidPresentFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 표시 완료");
              }

              @Override
              public void onAdWillDismissFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 닫히기 직전");
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "전면 광고 닫힘");
                  // 다음 광고를 미리 로드
                  loadInterstitialAd();
              }

              @Override
              public void onAdFailedToShowFullScreen(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.e("Adrop", "전면 광고 표시 실패: " + errorCode);
              }
          });

          // 2-1. 백버튼 콜백 리스너 설정
          interstitialAd.setCloseListener(new AdropInterstitialAdCloseListener() {
              @Override
              public void onBackPressed(@NonNull AdropInterstitialAd ad) {
                  Log.d("Adrop", "뒤로가기 버튼 클릭");
              }
          });

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

      private void loadInterstitialAd() {
          interstitialAd.load();
      }
  }
  ```
</CodeGroup>

***

## 광고 로드

`load()` 메서드를 호출하여 광고를 요청합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  private fun loadInterstitialAd() {
      interstitialAd?.load()
  }
  ```

  ```java Java theme={null}
  private void loadInterstitialAd() {
      interstitialAd.load();
  }
  ```
</CodeGroup>

광고 로드 완료 시 `onAdReceived` 콜백이 호출되며, 실패 시 `onAdFailedToReceive` 콜백이 호출됩니다.

***

## 광고 표시

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

### isLoaded 프로퍼티

광고가 로드되었는지 확인하는 프로퍼티입니다. `show()` 호출 전에 이 값을 확인하는 것이 좋습니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  private fun showInterstitialAd() {
      if (interstitialAd?.isLoaded == true) {
          interstitialAd?.show(this)
      } else {
          Log.d("Adrop", "광고가 아직 로드되지 않았습니다")
      }
  }
  ```

  ```java Java theme={null}
  private void showInterstitialAd() {
      if (interstitialAd != null && interstitialAd.isLoaded()) {
          interstitialAd.show(this);
      } else {
          Log.d("Adrop", "광고가 아직 로드되지 않았습니다");
      }
  }
  ```
</CodeGroup>

### show 메서드

<ParamField body="fromActivity" type="Activity" required>
  광고를 표시할 Activity 객체
</ParamField>

***

## AdropInterstitialAd 프로퍼티

### unitId

광고 유닛 ID를 반환합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val unitId: String = interstitialAd?.unitId ?: ""
  ```

  ```java Java theme={null}
  String unitId = interstitialAd.getUnitId();
  ```
</CodeGroup>

### isLoaded

광고가 로드되었는지 여부를 반환합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val isLoaded: Boolean = interstitialAd?.isLoaded ?: false
  ```

  ```java Java theme={null}
  boolean isLoaded = interstitialAd.isLoaded();
  ```
</CodeGroup>

### creativeId

현재 로드된 광고의 크리에이티브 ID를 반환합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val creativeId: String = interstitialAd?.creativeId ?: ""
  ```

  ```java Java theme={null}
  String creativeId = interstitialAd.getCreativeId();
  ```
</CodeGroup>

### txId

현재 로드된 광고의 트랜잭션 ID를 반환합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val txId: String = interstitialAd?.txId ?: ""
  ```

  ```java Java theme={null}
  String txId = interstitialAd.getTxId();
  ```
</CodeGroup>

### campaignId

현재 로드된 광고의 캠페인 ID를 반환합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val campaignId: String = interstitialAd?.campaignId ?: ""
  ```

  ```java Java theme={null}
  String campaignId = interstitialAd.getCampaignId();
  ```
</CodeGroup>

### isBackfilled

현재 로드된 광고가 백필 광고인지 여부를 반환합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val isBackfilled: Boolean = interstitialAd?.isBackfilled ?: false
  ```

  ```java Java theme={null}
  boolean isBackfilled = interstitialAd.isBackfilled();
  ```
</CodeGroup>

### close()

프로그래밍 방식으로 전면 광고를 닫습니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  interstitialAd?.close()
  ```

  ```java Java theme={null}
  interstitialAd.close();
  ```
</CodeGroup>

***

## AdropInterstitialAdListener 메서드

### 필수 메서드

<ParamField body="onAdReceived" type="(AdropInterstitialAd) -> Unit">
  광고 수신 성공 시 호출됩니다. 이 시점에서 `show()`를 호출하여 광고를 표시할 수 있습니다.
</ParamField>

<ParamField body="onAdFailedToReceive" type="(AdropInterstitialAd, AdropErrorCode) -> Unit">
  광고 수신 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.
</ParamField>

### 선택 메서드

<ParamField body="onAdImpression" type="(AdropInterstitialAd) -> Unit">
  광고 노출이 기록되었을 때 호출됩니다.
</ParamField>

<ParamField body="onAdClicked" type="(AdropInterstitialAd) -> Unit">
  사용자가 광고를 클릭했을 때 호출됩니다.
</ParamField>

<ParamField body="onAdWillPresentFullScreen" type="(AdropInterstitialAd) -> Unit">
  전면 광고가 표시되기 직전에 호출됩니다. 게임 일시정지 등의 작업을 수행할 수 있습니다.
</ParamField>

<ParamField body="onAdDidPresentFullScreen" type="(AdropInterstitialAd) -> Unit">
  전면 광고가 화면에 표시된 직후 호출됩니다.
</ParamField>

<ParamField body="onAdWillDismissFullScreen" type="(AdropInterstitialAd) -> Unit">
  전면 광고가 닫히기 직전에 호출됩니다.
</ParamField>

<ParamField body="onAdDidDismissFullScreen" type="(AdropInterstitialAd) -> Unit">
  전면 광고가 닫힌 직후 호출됩니다. 다음 광고를 미리 로드하기 좋은 시점입니다.
</ParamField>

<ParamField body="onAdFailedToShowFullScreen" type="(AdropInterstitialAd, AdropErrorCode) -> Unit">
  광고 표시 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.
</ParamField>

***

## 백버튼 콜백

전면 광고가 표시된 상태에서 사용자가 뒤로가기 버튼을 누르면 `AdropInterstitialAdCloseListener`를 통해 콜백을 받을 수 있습니다.

### AdropInterstitialAdCloseListener

<ParamField body="onBackPressed" type="(AdropInterstitialAd) -> Unit">
  사용자가 전면 광고에서 뒤로가기 버튼을 눌렀을 때 호출됩니다.
</ParamField>

### 사용 예시

<CodeGroup>
  ```kotlin Kotlin theme={null}
  import io.adrop.ads.interstitial.AdropInterstitialAd
  import io.adrop.ads.interstitial.AdropInterstitialAdCloseListener

  // 1. closeListener 정의
  private val closeListener = object : AdropInterstitialAdCloseListener {
      override fun onBackPressed(ad: AdropInterstitialAd) {
          // 사용자가 뒤로가기 버튼을 눌렀을 때 호출됩니다
          Log.d("InterstitialAd", "Back button pressed")

          // 광고를 닫으려면 close()를 호출하세요
          ad.close()
      }
  }

  // 2. 전면 광고 생성 시 closeListener 설정
  val interstitialAd = AdropInterstitialAd(context, "YOUR_UNIT_ID").apply {
      interstitialAdListener = yourAdListener
      closeListener = this@YourActivity.closeListener
      load()
  }
  ```

  ```java Java theme={null}
  import io.adrop.ads.interstitial.AdropInterstitialAd;
  import io.adrop.ads.interstitial.AdropInterstitialAdCloseListener;
  import io.adrop.ads.interstitial.AdropInterstitialAdListener;

  // 1. closeListener 정의
  private final AdropInterstitialAdCloseListener closeListener = new AdropInterstitialAdCloseListener() {
      @Override
      public void onBackPressed(@NonNull AdropInterstitialAd ad) {
          // 사용자가 뒤로가기 버튼을 눌렀을 때 호출됩니다
          Log.d("InterstitialAd", "Back button pressed");

          // 광고를 닫으려면 close()를 호출하세요
          ad.close();
      }
  };

  // 2. 전면 광고 생성 시 closeListener 설정
  AdropInterstitialAd interstitialAd = new AdropInterstitialAd(context, "YOUR_UNIT_ID");
  interstitialAd.setInterstitialAdListener(yourAdListener);
  interstitialAd.setCloseListener(closeListener);  // 새로 추가
  interstitialAd.load();
  ```
</CodeGroup>

### 동작 설명

* **백버튼 콜백**: 사용자가 뒤로가기 버튼을 누르면 `closeListener.onBackPressed()`가 먼저 호출됩니다.
* **자동 닫힘 조건**: 광고가 표시된 후 30초 이상 경과하거나, WebView가 없는 경우 백버튼 시 자동으로 광고가 닫힙니다.
* **수동 닫기**: `ad.close()`를 호출하면 언제든 프로그래밍 방식으로 광고를 닫을 수 있습니다.
* **closeListener를 설정하지 않으면**: 기존 동작과 동일하게 30초 후 자동 닫힘만 동작합니다.

### Android 15+ 호환성

Android 13(Tiramisu) 이상에서 `OnBackInvokedCallback`을 사용하여 예측형 뒤로가기(Predictive Back)를 지원합니다. 앱에서 `enableOnBackInvokedCallback="true"`를 설정한 경우에도 정상 동작합니다.

```xml theme={null}
<!-- AndroidManifest.xml -->
<application
    android:enableOnBackInvokedCallback="true"
    ... >
```

***

## 생명주기 관리

### destroy 메서드

Activity나 Fragment가 종료될 때 `destroy()` 메서드를 호출하여 리소스를 해제해야 합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onDestroy() {
      super.onDestroy()
      interstitialAd?.destroy()
      interstitialAd = null
  }
  ```

  ```java Java theme={null}
  @Override
  protected void onDestroy() {
      super.onDestroy();
      if (interstitialAd != null) {
          interstitialAd.destroy();
          interstitialAd = null;
      }
  }
  ```
</CodeGroup>

<Warning>
  메모리 누수를 방지하기 위해 반드시 `destroy()`를 호출하세요.
</Warning>

***

## 사전 로드 전략

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

### 기본 사전 로드

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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)
          }
      }
  }
  ```

  ```java Java theme={null}
  public class GameActivity extends AppCompatActivity {
      private AdropInterstitialAd interstitialAd;
      private boolean isAdReady = false;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_game);

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

      private void preloadInterstitialAd() {
          interstitialAd = new AdropInterstitialAd(this, "YOUR_UNIT_ID");
          interstitialAd.setInterstitialAdListener(new AdropInterstitialAdListener() {
              @Override
              public void onAdReceived(@NonNull AdropInterstitialAd ad) {
                  isAdReady = true;
                  Log.d("Adrop", "전면 광고 준비 완료");
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
                  isAdReady = false;
                  Log.e("Adrop", "전면 광고 로드 실패: " + errorCode);
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropInterstitialAd ad) {
                  isAdReady = false;
                  // 다음 광고 미리 로드
                  preloadInterstitialAd();
              }
          });
          interstitialAd.load();
      }

      private void onGameLevelComplete() {
          // 레벨 완료 시 즉시 표시
          if (isAdReady) {
              interstitialAd.show(this);
          }
      }
  }
  ```
</CodeGroup>

### 닫기 후 재로드

광고가 닫힌 후 `onAdDidDismissFullScreen` 콜백에서 다음 광고를 미리 로드합니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdDidDismissFullScreen(ad: AdropInterstitialAd) {
      Log.d("Adrop", "전면 광고 닫힘")
      // 즉시 다음 광고 로드
      interstitialAd?.load()
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdDidDismissFullScreen(@NonNull AdropInterstitialAd ad) {
      Log.d("Adrop", "전면 광고 닫힘");
      // 즉시 다음 광고 로드
      interstitialAd.load();
  }
  ```
</CodeGroup>

***

## 모범 사례

### 1. 적절한 표시 시점

앱의 자연스러운 전환 시점에 광고를 표시하세요.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // ✅ 좋은 예: 게임 레벨 전환
  fun onLevelComplete() {
      saveProgress()
      showInterstitialAd()
      loadNextLevel()
  }

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

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

  ```java Java theme={null}
  // ✅ 좋은 예: 게임 레벨 전환
  private void onLevelComplete() {
      saveProgress();
      showInterstitialAd();
      loadNextLevel();
  }

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

  // ❌ 나쁜 예: 사용자 액션 중간
  private void onButtonClick() {
      showInterstitialAd(); // 사용자 경험 저해
      performAction();
  }
  ```
</CodeGroup>

### 2. 에러 처리

광고 로드 실패에 대비한 처리를 구현하세요.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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()
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdFailedToReceive(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
      switch (errorCode) {
          case ERROR_CODE_NETWORK:
              Log.e("Adrop", "네트워크 오류: 나중에 다시 시도");
              retryAfterDelay();
              break;
          case ERROR_CODE_AD_NO_FILL:
              Log.w("Adrop", "표시할 광고 없음");
              continueWithoutAd();
              break;
          default:
              Log.e("Adrop", "광고 로드 실패: " + errorCode);
              break;
      }
  }

  private void retryAfterDelay() {
      new Handler(Looper.getMainLooper()).postDelayed(() -> {
          interstitialAd.load();
      }, 30000); // 30초 후 재시도
  }

  private void continueWithoutAd() {
      // 광고 없이 계속 진행
      proceedToNextScreen();
  }
  ```
</CodeGroup>

### 3. 빈도 제한

너무 자주 광고를 표시하지 않도록 제한하세요.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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()
      }
  }
  ```

  ```java Java theme={null}
  public class AdFrequencyManager {
      private long lastAdShownTime = 0;
      private final long minimumInterval = 180_000L; // 3분

      public boolean canShowAd() {
          long currentTime = System.currentTimeMillis();
          return currentTime - lastAdShownTime >= minimumInterval;
      }

      public void recordAdShown() {
          lastAdShownTime = System.currentTimeMillis();
      }
  }

  // 사용 예시
  public class MainActivity extends AppCompatActivity {
      private final AdFrequencyManager frequencyManager = new AdFrequencyManager();

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

          interstitialAd.show(this);
      }

      // 리스너에서 호출
      @Override
      public void onAdDidPresentFullScreen(@NonNull AdropInterstitialAd ad) {
          frequencyManager.recordAdShown();
      }
  }
  ```
</CodeGroup>

### 4. 게임 일시정지 처리

전면 광고 표시 시 게임이나 애니메이션을 일시정지하세요.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdWillPresentFullScreen(ad: AdropInterstitialAd) {
      // 게임 일시정지
      pauseGame()
      // 배경음악 중지
      pauseBackgroundMusic()
  }

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

  ```java Java theme={null}
  @Override
  public void onAdWillPresentFullScreen(@NonNull AdropInterstitialAd ad) {
      // 게임 일시정지
      pauseGame();
      // 배경음악 중지
      pauseBackgroundMusic();
  }

  @Override
  public void onAdDidDismissFullScreen(@NonNull AdropInterstitialAd ad) {
      // 게임 재개
      resumeGame();
      // 배경음악 재생
      resumeBackgroundMusic();
  }
  ```
</CodeGroup>

***

## 테스트

### 테스트 유닛 ID 사용

개발 중에는 테스트 유닛 ID를 사용하세요.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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)
      }
  }
  ```

  ```java Java theme={null}
  public class MainActivity extends AppCompatActivity {
      private final String unitId = BuildConfig.DEBUG ?
          "PUBLIC_TEST_UNIT_ID_INTERSTITIAL" :
          "YOUR_PRODUCTION_UNIT_ID";

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);

          interstitialAd = new AdropInterstitialAd(this, unitId);
      }
  }
  ```
</CodeGroup>

### 광고 로드 확인

광고가 정상적으로 로드되는지 확인하세요.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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()
      }
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdReceived(@NonNull AdropInterstitialAd ad) {
      Log.d("Adrop", "✅ 전면 광고 로드 성공");
      Log.d("Adrop", "Unit ID: " + ad.getUnitId());
      Log.d("Adrop", "Creative ID: " + ad.getCreativeId());
      Log.d("Adrop", "Is Backfilled: " + ad.isBackfilled());
  }

  @Override
  public void onAdFailedToReceive(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
      Log.e("Adrop", "❌ 전면 광고 로드 실패: " + errorCode);
      if (BuildConfig.DEBUG) {
          Toast.makeText(this, "광고 로드 실패: " + errorCode, Toast.LENGTH_SHORT).show();
      }
  }
  ```
</CodeGroup>

***

## 완전한 구현 예제

<CodeGroup>
  ```kotlin Kotlin theme={null}
  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"
      }
  }
  ```

  ```java Java theme={null}
  import android.os.Bundle;
  import android.util.Log;
  import android.widget.Button;
  import android.widget.Toast;
  import androidx.annotation.NonNull;
  import androidx.appcompat.app.AppCompatActivity;
  import io.adrop.ads.interstitial.AdropInterstitialAd;
  import io.adrop.ads.interstitial.AdropInterstitialAdListener;
  import io.adrop.ads.model.AdropErrorCode;

  public class InterstitialAdActivity extends AppCompatActivity {
      private static final String TAG = "InterstitialAdActivity";

      private AdropInterstitialAd interstitialAd;
      private Button loadButton;
      private Button showButton;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_interstitial_ad);

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

          // 버튼 초기 상태 설정
          showButton.setEnabled(false);

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

          // 버튼 클릭 리스너
          loadButton.setOnClickListener(v -> loadInterstitialAd());
          showButton.setOnClickListener(v -> showInterstitialAd());

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

      private void setupInterstitialAd() {
          String unitId = BuildConfig.DEBUG ?
              "PUBLIC_TEST_UNIT_ID_INTERSTITIAL" :
              "YOUR_PRODUCTION_UNIT_ID";

          interstitialAd = new AdropInterstitialAd(this, unitId);
          interstitialAd.setInterstitialAdListener(new AdropInterstitialAdListener() {
              @Override
              public void onAdReceived(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 수신 완료");
                  showButton.setEnabled(true);
                  loadButton.setEnabled(false);
                  Toast.makeText(
                      InterstitialAdActivity.this,
                      "광고가 준비되었습니다",
                      Toast.LENGTH_SHORT
                  ).show();
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.e(TAG, "전면 광고 수신 실패: " + errorCode);
                  showButton.setEnabled(false);
                  loadButton.setEnabled(true);
                  Toast.makeText(
                      InterstitialAdActivity.this,
                      "광고 로드 실패: " + errorCode,
                      Toast.LENGTH_SHORT
                  ).show();
              }

              @Override
              public void onAdImpression(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 노출");
              }

              @Override
              public void onAdClicked(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 클릭");
              }

              @Override
              public void onAdWillPresentFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 표시 직전");
              }

              @Override
              public void onAdDidPresentFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 표시 완료");
              }

              @Override
              public void onAdWillDismissFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 닫히기 직전");
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropInterstitialAd ad) {
                  Log.d(TAG, "전면 광고 닫힘");
                  showButton.setEnabled(false);
                  loadButton.setEnabled(true);
                  Toast.makeText(
                      InterstitialAdActivity.this,
                      "광고가 닫혔습니다",
                      Toast.LENGTH_SHORT
                  ).show();

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

              @Override
              public void onAdFailedToShowFullScreen(@NonNull AdropInterstitialAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.e(TAG, "전면 광고 표시 실패: " + errorCode);
                  showButton.setEnabled(false);
                  loadButton.setEnabled(true);
                  Toast.makeText(
                      InterstitialAdActivity.this,
                      "광고 표시 실패: " + errorCode,
                      Toast.LENGTH_SHORT
                  ).show();
              }
          });
      }

      private void loadInterstitialAd() {
          Log.d(TAG, "전면 광고 로드 시작");
          loadButton.setEnabled(false);
          interstitialAd.load();
      }

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

      @Override
      protected void onDestroy() {
          super.onDestroy();
          if (interstitialAd != null) {
              interstitialAd.destroy();
              interstitialAd = null;
          }
      }
  }
  ```
</CodeGroup>

***

## 문제 해결

<AccordionGroup>
  <Accordion title="onAdReceived가 호출되지 않음">
    * SDK가 초기화되었는지 확인
    * 유닛 ID가 올바른지 확인
    * 네트워크 연결 상태 확인
    * AndroidManifest.xml에 인터넷 권한이 설정되어 있는지 확인
  </Accordion>

  <Accordion title="onAdFailedToReceive가 호출됨">
    * 에러 코드를 확인하여 원인 파악
    * `ERROR_CODE_AD_NO_FILL`: 광고 인벤토리 부족, 나중에 재시도
    * `ERROR_CODE_NETWORK`: 네트워크 연결 확인
    * `ERROR_CODE_INVALID_UNIT`: 유닛 ID 확인
  </Accordion>

  <Accordion title="show() 호출 후 아무 일도 일어나지 않음">
    * `onAdReceived` 콜백 이후에 `show()`를 호출했는지 확인
    * `isLoaded` 프로퍼티가 `true`인지 확인
    * Activity가 유효한지 확인
    * 다른 전면 광고가 이미 표시 중이지 않은지 확인
  </Accordion>

  <Accordion title="메모리 누수 경고">
    * `onDestroy()`에서 `destroy()` 메서드 호출 확인
    * Context 참조가 WeakReference로 관리되는지 확인
    * 리스너를 null로 설정하는지 확인
  </Accordion>
</AccordionGroup>

***

## 백필 광고

백필 광고가 활성화된 경우, 직광고가 없을 때 자동으로 백필 광고가 로드됩니다. `isBackfilled` 프로퍼티로 백필 광고 여부를 확인할 수 있습니다.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  interstitialAd.interstitialAdListener = object : AdropInterstitialAdListener {
      override fun onAdReceived(ad: AdropInterstitialAd) {
          if (ad.isBackfilled) {
              println("백필 광고가 로드되었습니다")
          } else {
              println("직광고가 로드되었습니다")
          }
      }

      override fun onAdFailedToReceive(ad: AdropInterstitialAd, errorCode: AdropErrorCode) {
          when (errorCode) {
              AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
                  println("직광고 없음, 백필 광고 요청 중...")
              }
              AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL -> {
                  println("백필 광고도 없음")
              }
              else -> {
                  println("광고 로드 실패: $errorCode")
              }
          }
      }
  }
  ```

  ```java Java theme={null}
  interstitialAd.setInterstitialAdListener(new AdropInterstitialAdListener() {
      @Override
      public void onAdReceived(AdropInterstitialAd ad) {
          if (ad.isBackfilled()) {
              System.out.println("백필 광고가 로드되었습니다");
          } else {
              System.out.println("직광고가 로드되었습니다");
          }
      }

      @Override
      public void onAdFailedToReceive(AdropInterstitialAd ad, AdropErrorCode errorCode) {
          if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
              System.out.println("직광고 없음, 백필 광고 요청 중...");
          } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL) {
              System.out.println("백필 광고도 없음");
          } else {
              System.out.println("광고 로드 실패: " + errorCode);
          }
      }
  });
  ```
</CodeGroup>

<Note>
  백필 광고를 사용하려면 `io.adrop:adrop-ads-backfill` 의존성을 추가해야 합니다. [시작하기](/ko/sdk/android/overview)를 참고하세요.
</Note>

***

## 다음 단계

<CardGroup cols={2}>
  <Card title="보상형 광고" href="/ko/sdk/android/rewarded">
    보상형 광고로 사용자 인게이지먼트 향상
  </Card>

  <Card title="배너 광고" href="/ko/sdk/android/banner">
    배너 광고 구현하기
  </Card>

  <Card title="타겟팅 설정" href="/ko/sdk/android/targeting">
    사용자 속성 및 문맥 타겟팅
  </Card>

  <Card title="레퍼런스" href="/ko/sdk/android/reference">
    API 레퍼런스 문서
  </Card>
</CardGroup>
