> ## 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.

# 팝업 광고

> React Native 앱에서 팝업 광고를 구현하는 방법을 안내합니다.

## 개요

팝업 광고(Popup Ad)는 특정 순간에 화면에 나타나는 광고 포맷입니다. 앱 실행 시, 콘텐츠 로드 완료 시, 특정 이벤트 발생 시 등 원하는 타이밍에 표시할 수 있으며, 사용자가 닫기 버튼을 누르거나 "오늘 하루 보지 않기"를 선택하여 종료할 수 있습니다.

### 특징

* 화면 중앙 또는 하단에 표시되는 팝업 형태
* 이미지 및 동영상 광고 지원
* 닫기, 딤(배경) 클릭, "오늘 하루 보지 않기" 옵션 제공
* 배경색, 텍스트 색상 등 커스터마이징 가능
* 비침투적이면서도 효과적인 광고 경험

<Note>
  개발 환경에서는 테스트 유닛 ID를 사용하세요. [테스트 유닛 ID](#테스트-유닛-id) 섹션을 참고하세요.
</Note>

***

## 구현 단계

팝업 광고는 다음 4단계로 구현합니다:

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

***

## 기본 구현

### AdropPopupAd 클래스

`AdropPopupAd` 클래스는 팝업 광고를 관리하는 메인 클래스입니다.

```typescript theme={null}
import { AdropPopupAd, type AdropPopupAdColors } from 'adrop-ads-react-native';

const popupAd = new AdropPopupAd(
  unitId: string,
  colors?: AdropPopupAdColors,
  useCustomClick?: boolean
);
```

#### 생성자 파라미터

<ParamField path="unitId" type="string" required>
  팝업 광고 유닛 ID. 애드컨트롤 콘솔에서 생성한 유닛 ID를 사용합니다.
</ParamField>

<ParamField path="colors" type="AdropPopupAdColors">
  팝업 광고의 색상을 커스터마이징하는 옵션입니다.

  * `closeTextColor`: 닫기 버튼 텍스트 색상
  * `hideForTodayTextColor`: "오늘 하루 보지 않기" 텍스트 색상
  * `backgroundColor`: 팝업 배경(딤) 색상
</ParamField>

<ParamField path="useCustomClick" type="boolean" default="false">
  커스텀 클릭 처리 사용 여부. `true`로 설정하면 광고 클릭 시 기본 브라우저 열기 대신 `onAdClicked` 콜백만 호출됩니다.
</ParamField>

### 기본 사용법

```typescript theme={null}
import React, { useEffect, useState, useMemo } from 'react';
import { Button, View } from 'react-native';
import { AdropPopupAd, type AdropListener } from 'adrop-ads-react-native';

const App: React.FC = () => {
  const [popupAd, setPopupAd] = useState<AdropPopupAd>();
  const [isLoaded, setIsLoaded] = useState(false);

  const listener: AdropListener = useMemo(() => ({
    onAdReceived: (ad: AdropPopupAd) => {
      console.log('팝업 광고 수신 완료');
      setIsLoaded(true);
    },
    onAdFailedToReceive: (_: AdropPopupAd, errorCode: any) => {
      console.log('팝업 광고 수신 실패:', errorCode);
    },
    onAdClicked: (ad: AdropPopupAd) => {
      console.log('팝업 광고 클릭');
      // 광고 클릭 시 팝업 닫기
      ad.close();
    },
  }), []);

  useEffect(() => {
    // 1. 팝업 광고 생성
    const ad = new AdropPopupAd('YOUR_POPUP_UNIT_ID');
    ad.listener = listener;
    setPopupAd(ad);

    // 2. 광고 로드
    ad.load();

    // 컴포넌트 언마운트 시 정리
    return () => {
      ad.destroy();
    };
  }, [listener]);

  // 3. 광고 표시
  const showAd = () => {
    if (popupAd && isLoaded) {
      popupAd.show();
    }
  };

  return (
    <View>
      <Button
        title="팝업 광고 표시"
        onPress={showAd}
        disabled={!isLoaded}
      />
    </View>
  );
};

export default App;
```

***

## AdropListener 인터페이스

팝업 광고의 이벤트를 수신하기 위한 리스너 인터페이스입니다.

### 권장 콜백

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

<ParamField path="onAdFailedToReceive" type="(ad: AdropPopupAd, errorCode?: any) => void">
  광고 수신 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.
</ParamField>

### 선택 콜백

<ParamField path="onAdImpression" type="(ad: AdropPopupAd) => void">
  광고 노출이 기록되었을 때 호출됩니다.
</ParamField>

<ParamField path="onAdClicked" type="(ad: AdropPopupAd) => void">
  사용자가 광고를 클릭했을 때 호출됩니다. 이 콜백에서 `ad.close()`를 호출하여 팝업을 닫을 수 있습니다.
</ParamField>

<ParamField path="onAdWillPresentFullScreen" type="(ad: AdropPopupAd) => void">
  팝업 광고가 표시되기 직전에 호출됩니다.
</ParamField>

<ParamField path="onAdDidPresentFullScreen" type="(ad: AdropPopupAd) => void">
  팝업 광고가 화면에 표시된 직후 호출됩니다.
</ParamField>

<ParamField path="onAdWillDismissFullScreen" type="(ad: AdropPopupAd) => void">
  팝업 광고가 닫히기 직전에 호출됩니다.
</ParamField>

<ParamField path="onAdDidDismissFullScreen" type="(ad: AdropPopupAd) => void">
  팝업 광고가 닫힌 직후 호출됩니다. 다음 광고를 미리 로드하기 좋은 시점입니다.
</ParamField>

<ParamField path="onAdFailedToShowFullScreen" type="(ad: AdropPopupAd, errorCode?: any) => void">
  광고 표시 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.
</ParamField>

<ParamField path="onAdBackButtonPressed" type="(ad: AdropPopupAd) => void">
  광고 표시 중 사용자가 뒤로가기 버튼을 눌렀을 때 호출됩니다. **Android 전용.**
</ParamField>

<ParamField path="onAdVideoStart" type="(ad: AdropPopupAd) => void">
  동영상 광고 재생이 시작되었을 때 호출됩니다.
</ParamField>

<ParamField path="onAdVideoEnd" type="(ad: AdropPopupAd) => void">
  동영상 광고 재생이 종료되었을 때 호출됩니다.
</ParamField>

### 리스너 구현 예시

```typescript theme={null}
const listener: AdropListener = useMemo(() => ({
  // 광고 수신 성공
  onAdReceived: (ad: AdropPopupAd) => {
    console.log('팝업 광고 수신 완료');
    console.log('Creative ID:', ad.creativeId);
    console.log('Campaign ID:', ad.campaignId);
    // 광고가 준비되면 자동으로 표시
    ad.show();
  },

  // 광고 수신 실패
  onAdFailedToReceive: (ad: AdropPopupAd, errorCode?: any) => {
    console.log('팝업 광고 수신 실패:', errorCode);
  },

  // 광고 노출
  onAdImpression: (ad: AdropPopupAd) => {
    console.log('팝업 광고 노출됨');
    console.log('TX ID:', ad.txId);
    console.log('Destination URL:', ad.destinationURL);
  },

  // 광고 클릭
  onAdClicked: (ad: AdropPopupAd) => {
    console.log('팝업 광고 클릭:', ad.destinationURL);
    // 클릭 시 팝업 닫기
    ad.close();
  },

  // 팝업 표시 직전
  onAdWillPresentFullScreen: (ad: AdropPopupAd) => {
    console.log('팝업 광고 표시 직전');
  },

  // 팝업 표시 완료
  onAdDidPresentFullScreen: (ad: AdropPopupAd) => {
    console.log('팝업 광고 표시 완료');
  },

  // 팝업 닫히기 직전
  onAdWillDismissFullScreen: (ad: AdropPopupAd) => {
    console.log('팝업 광고 닫히기 직전');
  },

  // 팝업 닫힘
  onAdDidDismissFullScreen: (ad: AdropPopupAd) => {
    console.log('팝업 광고 닫힘');
    // 다음 광고 미리 로드
    loadNextAd();
  },

  // 팝업 표시 실패
  onAdFailedToShowFullScreen: (ad: AdropPopupAd, errorCode?: any) => {
    console.log('팝업 광고 표시 실패:', errorCode);
  },

  // 동영상 광고 재생 시작
  onAdVideoStart: (ad: AdropPopupAd) => {
    console.log('동영상 광고 재생 시작:', ad.creativeId);
  },

  // 동영상 광고 재생 종료
  onAdVideoEnd: (ad: AdropPopupAd) => {
    console.log('동영상 광고 재생 종료:', ad.creativeId);
  },
}), []);
```

***

## 메서드

### load()

광고를 요청하고 로드합니다.

```typescript theme={null}
popupAd.load();
```

### show()

로드된 광고를 화면에 표시합니다. `onAdReceived` 콜백이 호출된 후에만 호출할 수 있습니다.

```typescript theme={null}
popupAd.show();
```

<Warning>
  `show()`는 광고가 로드된 상태(`isLoaded === true`)에서만 호출해야 합니다.
</Warning>

### close()

현재 표시 중인 팝업 광고를 닫습니다. 주로 `onAdClicked` 콜백에서 사용됩니다.

```typescript theme={null}
popupAd.close();
```

### destroy()

광고 인스턴스를 정리하고 리소스를 해제합니다. 컴포넌트 언마운트 시 반드시 호출해야 합니다.

```typescript theme={null}
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

  return () => {
    ad.destroy();
  };
}, []);
```

***

## 광고 속성

팝업 광고 객체에서 다음 속성들을 사용할 수 있습니다:

<ParamField path="unitId" type="string">
  광고 유닛 ID
</ParamField>

<ParamField path="isLoaded" type="boolean">
  광고가 로드되었는지 여부
</ParamField>

<ParamField path="creativeId" type="string">
  현재 표시 중인 광고 크리에이티브 ID
</ParamField>

<ParamField path="destinationURL" type="string">
  광고 클릭 시 이동할 URL
</ParamField>

<ParamField path="txId" type="string">
  트랜잭션 ID (광고 노출 추적용)
</ParamField>

<ParamField path="campaignId" type="string">
  캠페인 ID
</ParamField>

<ParamField path="browserTarget" type="BrowserTarget">
  광고 클릭 시 브라우저 타겟. `BrowserTarget.EXTERNAL` (0)은 시스템 브라우저, `BrowserTarget.INTERNAL` (1)은 인앱 브라우저로 열립니다.
</ParamField>

***

## 커스터마이징

### 색상 설정

`AdropPopupAdColors` 타입을 사용하여 팝업 광고의 색상을 커스터마이징할 수 있습니다.

```typescript theme={null}
import { AdropPopupAd, type AdropPopupAdColors } from 'adrop-ads-react-native';

// 색상 옵션 정의
const customColors: AdropPopupAdColors = {
  closeTextColor: '#FFFFFF',                    // 닫기 버튼 색상
  hideForTodayTextColor: '#456789',             // "오늘 하루 보지 않기" 색상
  backgroundColor: 'rgba(53, 255, 63, 0.3)',    // 배경(딤) 색상
};

// 팝업 광고 생성 시 색상 적용
const popupAd = new AdropPopupAd(
  'YOUR_POPUP_UNIT_ID',
  customColors
);
```

#### AdropPopupAdColors 타입

<ParamField path="closeTextColor" type="string">
  닫기 버튼 텍스트 색상. HEX 색상 코드 또는 RGBA 형식을 지원합니다.
</ParamField>

<ParamField path="hideForTodayTextColor" type="string">
  "오늘 하루 보지 않기" 텍스트 색상. HEX 색상 코드 또는 RGBA 형식을 지원합니다.
</ParamField>

<ParamField path="backgroundColor" type="string">
  팝업 배경(딤) 색상. HEX 색상 코드 또는 RGBA 형식을 지원합니다. 투명도 조절이 가능합니다.
</ParamField>

### 커스텀 클릭 처리

광고 클릭 시 기본 브라우저 열기 대신 커스텀 처리를 하려면 `useCustomClick` 파라미터를 사용하세요.

```typescript theme={null}
const listener: AdropListener = useMemo(() => ({
  onAdReceived: (ad: AdropPopupAd) => {
    ad.show();
  },
  onAdFailedToReceive: (_: AdropPopupAd, errorCode: any) => {
    console.log('광고 수신 실패:', errorCode);
  },
  onAdClicked: (ad: AdropPopupAd) => {
    // 커스텀 클릭 처리
    console.log('광고 클릭됨:', ad.destinationURL);

    // 원하는 방식으로 URL 처리
    // 예: In-App 브라우저로 열기
    openInAppBrowser(ad.destinationURL);

    // 팝업 닫기
    ad.close();
  },
}), []);

// useCustomClick을 true로 설정
const popupAd = new AdropPopupAd(
  'YOUR_POPUP_UNIT_ID',
  undefined,  // colors
  true        // useCustomClick
);
popupAd.listener = listener;
```

***

## 테스트 유닛 ID

개발 및 테스트 시 다음 테스트 유닛 ID를 사용하세요.

| 광고 타입            | 테스트 유닛 ID                                     |
| ---------------- | --------------------------------------------- |
| 팝업 (하단 이미지)      | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM`            |
| 팝업 (중앙 이미지)      | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER`            |
| 팝업 비디오 (하단 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_16_9` |
| 팝업 비디오 (하단 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_9_16` |
| 팝업 비디오 (중앙 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_16_9` |
| 팝업 비디오 (중앙 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_9_16` |

### 테스트 광고 사용 예시

```typescript theme={null}
// 개발/프로덕션 환경 분리
const POPUP_UNIT_ID = __DEV__
  ? 'PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM'  // 테스트 유닛 ID
  : 'YOUR_PRODUCTION_UNIT_ID';           // 실제 유닛 ID

const popupAd = new AdropPopupAd(POPUP_UNIT_ID);
```

<Warning>
  실제 배포 시에는 반드시 애드컨트롤 콘솔에서 생성한 실제 유닛 ID를 사용하세요.
</Warning>

***

## 에러 처리

광고 로드 또는 표시 실패 시 에러 코드를 확인하여 적절히 처리하세요.

```typescript theme={null}
const listener: AdropListener = {
  onAdFailedToReceive: (ad: AdropPopupAd, errorCode?: any) => {
    console.error('광고 수신 실패:', errorCode);

    switch (errorCode) {
      case AdropErrorCode.network:
        // 네트워크 오류 처리
        console.log('네트워크 연결을 확인해주세요');
        break;
      case AdropErrorCode.adNoFill:
        // 광고 인벤토리 부족
        console.log('현재 표시할 수 있는 광고가 없습니다');
        break;
      case AdropErrorCode.invalidUnit:
        // 잘못된 유닛 ID
        console.log('광고 유닛 ID를 확인해주세요');
        break;
      default:
        console.log('광고를 불러올 수 없습니다');
    }
  },

  onAdFailedToShowFullScreen: (ad: AdropPopupAd, errorCode?: any) => {
    console.error('광고 표시 실패:', errorCode);

    // 다음에 다시 시도
    setTimeout(() => {
      ad.load();
    }, 30000); // 30초 후 재시도
  },
};
```

***

## 모범 사례

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

팝업 광고는 다음 시점에 표시하는 것이 효과적입니다:

```typescript theme={null}
// ✅ 좋은 예: 앱 시작 시
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  ad.listener = {
    onAdReceived: (ad) => ad.show(),
    onAdFailedToReceive: (_, error) => console.log(error),
  };
  ad.load();

  return () => ad.destroy();
}, []);

// ✅ 좋은 예: 콘텐츠 로드 완료 시
const onContentLoaded = () => {
  if (shouldShowPopupAd()) {
    popupAd?.show();
  }
};

// ✅ 좋은 예: 특정 이벤트 완료 시
const onAchievementUnlocked = () => {
  popupAd?.show();
};

// ❌ 나쁜 예: 사용자가 작업 중일 때
const onUserTyping = () => {
  popupAd?.show(); // 사용자 경험 저해
};
```

### 2. 빈도 제한

팝업 광고를 너무 자주 표시하지 마세요.

```typescript theme={null}
import AsyncStorage from '@react-native-async-storage/async-storage';

const LAST_SHOWN_KEY = 'popup_ad_last_shown';
const MINIMUM_INTERVAL = 3600000; // 1시간 (밀리초)

// 광고를 표시할 수 있는지 확인
const canShowAd = async (): Promise<boolean> => {
  try {
    const lastShown = await AsyncStorage.getItem(LAST_SHOWN_KEY);
    if (!lastShown) return true;

    const currentTime = Date.now();
    const lastShownTime = parseInt(lastShown, 10);

    return currentTime - lastShownTime >= MINIMUM_INTERVAL;
  } catch (error) {
    return true;
  }
};

// 광고 표시 기록
const recordAdShown = async () => {
  try {
    await AsyncStorage.setItem(LAST_SHOWN_KEY, Date.now().toString());
  } catch (error) {
    console.error('Error recording ad shown:', error);
  }
};

// 사용
const showAdIfAllowed = async () => {
  if (await canShowAd()) {
    popupAd?.show();
    await recordAdShown();
  }
};
```

### 3. 광고 미리 로드

사용자 경험을 위해 광고를 미리 로드하세요.

```typescript theme={null}
const [isAdReady, setIsAdReady] = useState(false);

useEffect(() => {
  // 앱 시작 시 미리 로드
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  ad.listener = {
    onAdReceived: () => setIsAdReady(true),
    onAdFailedToReceive: (_, error) => console.log(error),
  };
  ad.load();

  setPopupAd(ad);
  return () => ad.destroy();
}, []);

// 원하는 시점에 즉시 표시
const showPopupNow = () => {
  if (isAdReady) {
    popupAd?.show();
  }
};
```

### 4. 메모리 관리

컴포넌트 언마운트 시 반드시 광고를 정리하세요.

```typescript theme={null}
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

  // 정리 함수
  return () => {
    ad.destroy();
  };
}, []);
```

### 5. 클릭 시 팝업 닫기

광고 클릭 시 팝업을 닫아 사용자 경험을 개선하세요.

```typescript theme={null}
const listener: AdropListener = {
  onAdClicked: (ad: AdropPopupAd) => {
    console.log('광고 클릭:', ad.destinationURL);
    // 클릭 시 팝업 자동 닫기
    ad.close();
  },
};
```

***

## 문제 해결

### 광고가 표시되지 않음

<AccordionGroup>
  <Accordion title="onAdReceived가 호출되지 않음">
    * SDK가 초기화되었는지 확인
    * 유닛 ID가 올바른지 확인
    * 네트워크 연결 상태 확인
    * 테스트 환경에서는 테스트 유닛 ID 사용
  </Accordion>

  <Accordion title="onAdFailedToReceive가 호출됨">
    * 에러 코드를 확인하여 원인 파악
    * 광고 인벤토리 부족 시 나중에 재시도
    * 네이티브 SDK가 올바르게 연동되었는지 확인
  </Accordion>

  <Accordion title="show() 호출 후 아무 일도 일어나지 않음">
    * `onAdReceived` 콜백 이후에 `show()`를 호출했는지 확인
    * `isLoaded` 속성을 확인하여 광고가 로드되었는지 확인
    * 네이티브 모듈이 올바르게 연결되었는지 확인
  </Accordion>
</AccordionGroup>

### 메모리 누수

```typescript theme={null}
// ✅ 좋은 예: 정리 함수 사용
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

  return () => {
    ad.destroy();  // 반드시 호출
  };
}, []);

// ❌ 나쁜 예: 정리하지 않음
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);
  // destroy() 호출 없음 - 메모리 누수!
}, []);
```

***

## 관련 문서

<CardGroup cols={2}>
  <Card title="시작하기" href="/ko/sdk/react-native">
    SDK 설치 및 초기화
  </Card>

  <Card title="전면 광고" href="/ko/sdk/react-native/interstitial">
    전면 광고 구현하기
  </Card>

  <Card title="보상형 광고" href="/ko/sdk/react-native/rewarded">
    보상형 광고 구현하기
  </Card>

  <Card title="배너 광고" href="/ko/sdk/react-native/banner">
    배너 광고 구현하기
  </Card>
</CardGroup>
