메인 콘텐츠로 건너뛰기

개요

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

특징

  • 화면 중앙 또는 하단에 표시되는 팝업 형태
  • 이미지 및 동영상 광고 지원
  • 닫기, 딤(배경) 클릭, “오늘 하루 보지 않기” 옵션 제공
  • 배경색, 텍스트 색상 등 커스터마이징 가능
  • 비침투적이면서도 효과적인 광고 경험
개발 환경에서는 테스트 유닛 ID를 사용하세요. 테스트 유닛 ID 섹션을 참고하세요.

구현 단계

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

기본 구현

AdropPopupAd 클래스

AdropPopupAd 클래스는 팝업 광고를 관리하는 메인 클래스입니다.
import AdropPopupAd, { AdropPopupAdColors } from 'adrop-ads-react-native';

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

생성자 파라미터

unitId
string
required
팝업 광고 유닛 ID. 애드컨트롤 콘솔에서 생성한 유닛 ID를 사용합니다.
colors
AdropPopupAdColors
팝업 광고의 색상을 커스터마이징하는 옵션입니다.
  • closeTextColor: 닫기 버튼 텍스트 색상
  • hideForTodayTextColor: “오늘 하루 보지 않기” 텍스트 색상
  • backgroundColor: 팝업 배경(딤) 색상
useCustomClick
boolean
default:"false"
커스텀 클릭 처리 사용 여부. true로 설정하면 광고 클릭 시 기본 브라우저 열기 대신 onAdClicked 콜백만 호출됩니다.

기본 사용법

import React, { useEffect, useState, useMemo } from 'react';
import { Button, View } from 'react-native';
import AdropPopupAd, { 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 인터페이스

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

필수 콜백

onAdReceived
(ad: AdropPopupAd) => void
광고 수신 성공 시 호출됩니다. 이 시점에서 show()를 호출하여 광고를 표시할 수 있습니다.
onAdFailedToReceive
(ad: AdropPopupAd, errorCode?: any) => void
광고 수신 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

선택 콜백

onAdImpression
(ad: AdropPopupAd) => void
광고 노출이 기록되었을 때 호출됩니다.
onAdClicked
(ad: AdropPopupAd) => void
사용자가 광고를 클릭했을 때 호출됩니다. 이 콜백에서 ad.close()를 호출하여 팝업을 닫을 수 있습니다.
onAdWillPresentFullScreen
(ad: AdropPopupAd) => void
팝업 광고가 표시되기 직전에 호출됩니다.
onAdDidPresentFullScreen
(ad: AdropPopupAd) => void
팝업 광고가 화면에 표시된 직후 호출됩니다.
onAdWillDismissFullScreen
(ad: AdropPopupAd) => void
팝업 광고가 닫히기 직전에 호출됩니다.
onAdDidDismissFullScreen
(ad: AdropPopupAd) => void
팝업 광고가 닫힌 직후 호출됩니다. 다음 광고를 미리 로드하기 좋은 시점입니다.
onAdFailedToShowFullScreen
(ad: AdropPopupAd, errorCode?: any) => void
광고 표시 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

리스너 구현 예시

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);
  },
}), []);

메서드

load()

광고를 요청하고 로드합니다.
popupAd.load();

show()

로드된 광고를 화면에 표시합니다. onAdReceived 콜백이 호출된 후에만 호출할 수 있습니다.
popupAd.show();
show()는 광고가 로드된 상태(isLoaded === true)에서만 호출해야 합니다.

close()

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

destroy()

광고 인스턴스를 정리하고 리소스를 해제합니다. 컴포넌트 언마운트 시 반드시 호출해야 합니다.
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

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

광고 속성

팝업 광고 객체에서 다음 속성들을 사용할 수 있습니다:
unitId
string
광고 유닛 ID
isLoaded
boolean
광고가 로드되었는지 여부
creativeId
string
현재 표시 중인 광고 크리에이티브 ID
destinationURL
string
광고 클릭 시 이동할 URL
txId
string
트랜잭션 ID (광고 노출 추적용)
campaignId
string
캠페인 ID

커스터마이징

색상 설정

AdropPopupAdColors 타입을 사용하여 팝업 광고의 색상을 커스터마이징할 수 있습니다.
import AdropPopupAd, { 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 타입

closeTextColor
string
닫기 버튼 텍스트 색상. HEX 색상 코드 또는 RGBA 형식을 지원합니다.
hideForTodayTextColor
string
“오늘 하루 보지 않기” 텍스트 색상. HEX 색상 코드 또는 RGBA 형식을 지원합니다.
backgroundColor
string
팝업 배경(딤) 색상. HEX 색상 코드 또는 RGBA 형식을 지원합니다. 투명도 조절이 가능합니다.

커스텀 클릭 처리

광고 클릭 시 기본 브라우저 열기 대신 커스텀 처리를 하려면 useCustomClick 파라미터를 사용하세요.
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;

구현 예제

완전한 구현 예제

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
import AdropPopupAd, {
  AdropListener,
  AdropPopupAdColors,
} from 'adrop-ads-react-native';

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

  // 리스너 정의
  const listener: AdropListener = useMemo(() => ({
    onAdReceived: (ad: AdropPopupAd) => {
      console.log('팝업 광고 수신 완료');
      setIsLoaded(true);
      setErrorCode('');
    },
    onAdFailedToReceive: (_: AdropPopupAd, error: any) => {
      console.log('팝업 광고 수신 실패:', error);
      setErrorCode(error);
      setIsLoaded(false);
    },
    onAdImpression: (ad: AdropPopupAd) => {
      console.log('팝업 광고 노출:', ad.txId, ad.campaignId);
    },
    onAdClicked: (ad: AdropPopupAd) => {
      console.log('팝업 광고 클릭:', ad.destinationURL);
      // 클릭 시 팝업 닫기
      ad.close();
    },
    onAdDidPresentFullScreen: (ad: AdropPopupAd) => {
      console.log('팝업 광고 표시됨');
    },
    onAdDidDismissFullScreen: (ad: AdropPopupAd) => {
      console.log('팝업 광고 닫힘');
      // 다음 광고 미리 로드
      ad.load();
    },
    onAdFailedToShowFullScreen: (_: AdropPopupAd, error: any) => {
      console.log('팝업 광고 표시 실패:', error);
      setErrorCode(error);
    },
  }), []);

  // 팝업 광고 초기화
  const initializeAd = useCallback((unitId: string) => {
    // 색상 커스터마이징
    const customColors: AdropPopupAdColors = {
      hideForTodayTextColor: '#456789',
      backgroundColor: 'rgba(53, 255, 63, 0.3)',
    };

    // 팝업 광고 생성
    const ad = new AdropPopupAd(unitId, customColors);
    ad.listener = listener;

    setPopupAd((prev) => {
      prev?.destroy();
      return ad;
    });
  }, [listener]);

  // 컴포넌트 마운트 시 초기화
  useEffect(() => {
    initializeAd('YOUR_POPUP_UNIT_ID');
  }, [initializeAd]);

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

  // 광고 로드
  const loadAd = () => {
    popupAd?.load();
    setIsLoaded(false);
  };

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

  return (
    <View style={styles.container}>
      <Button title="광고 로드" onPress={loadAd} />
      <Button
        title="광고 표시"
        onPress={showAd}
        disabled={!isLoaded}
      />
      {errorCode && (
        <Text style={styles.error}>에러 코드: {errorCode}</Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    gap: 10,
  },
  error: {
    color: 'red',
    marginTop: 10,
  },
});

export default PopupAdExample;

”오늘 하루 보지 않기” 구현

사용자가 “오늘 하루 보지 않기”를 선택했을 때 적절히 처리하는 방법입니다.
import AsyncStorage from '@react-native-async-storage/async-storage';

const POPUP_AD_HIDDEN_KEY = 'popup_ad_hidden_date';

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

    const hiddenDate = new Date(parseInt(lastHiddenDate, 10));
    const today = new Date();

    // 저장된 날짜가 오늘이 아니면 표시 가능
    return (
      hiddenDate.getFullYear() !== today.getFullYear() ||
      hiddenDate.getMonth() !== today.getMonth() ||
      hiddenDate.getDate() !== today.getDate()
    );
  } catch (error) {
    console.error('Error checking popup ad visibility:', error);
    return true;
  }
};

// "오늘 하루 보지 않기" 클릭 시 날짜 저장
const saveHiddenDate = async () => {
  try {
    await AsyncStorage.setItem(
      POPUP_AD_HIDDEN_KEY,
      Date.now().toString()
    );
    console.log('오늘 하루 팝업 광고를 표시하지 않습니다');
  } catch (error) {
    console.error('Error saving popup ad hidden date:', error);
  }
};

// 사용 예시
const PopupAdWithHideToday: React.FC = () => {
  const [popupAd, setPopupAd] = useState<AdropPopupAd>();

  useEffect(() => {
    const initAd = async () => {
      // 오늘 표시 가능한지 확인
      const canShow = await canShowAdToday();
      if (!canShow) {
        console.log('오늘은 광고를 표시하지 않습니다');
        return;
      }

      const ad = new AdropPopupAd('YOUR_POPUP_UNIT_ID');
      ad.listener = {
        onAdReceived: (ad: AdropPopupAd) => {
          ad.show();
        },
        onAdFailedToReceive: (_: AdropPopupAd, error: any) => {
          console.log('광고 수신 실패:', error);
        },
        onAdDidDismissFullScreen: async (ad: AdropPopupAd) => {
          // 사용자가 "오늘 하루 보지 않기"를 선택했는지는
          // 네이티브 SDK에서 자동으로 처리됩니다.
          // 필요시 추가 로직 구현
        },
      };

      setPopupAd(ad);
      ad.load();
    };

    initAd();

    return () => {
      popupAd?.destroy();
    };
  }, []);

  return <View />;
};

테스트 유닛 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

테스트 광고 사용 예시

import { Platform } from 'react-native';

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

const popupAd = new AdropPopupAd(POPUP_UNIT_ID);
실제 배포 시에는 반드시 애드컨트롤 콘솔에서 생성한 실제 유닛 ID를 사용하세요.

에러 처리

광고 로드 또는 표시 실패 시 에러 코드를 확인하여 적절히 처리하세요.
const listener: AdropListener = {
  onAdFailedToReceive: (ad: AdropPopupAd, errorCode?: any) => {
    console.error('광고 수신 실패:', errorCode);

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

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

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

모범 사례

1. 적절한 표시 시점

팝업 광고는 다음 시점에 표시하는 것이 효과적입니다:
// ✅ 좋은 예: 앱 시작 시
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. 빈도 제한

팝업 광고를 너무 자주 표시하지 마세요.
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. 광고 미리 로드

사용자 경험을 위해 광고를 미리 로드하세요.
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. 메모리 관리

컴포넌트 언마운트 시 반드시 광고를 정리하세요.
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

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

5. 클릭 시 팝업 닫기

광고 클릭 시 팝업을 닫아 사용자 경험을 개선하세요.
const listener: AdropListener = {
  onAdClicked: (ad: AdropPopupAd) => {
    console.log('광고 클릭:', ad.destinationURL);
    // 클릭 시 팝업 자동 닫기
    ad.close();
  },
};

문제 해결

광고가 표시되지 않음

  • SDK가 초기화되었는지 확인
  • 유닛 ID가 올바른지 확인
  • 네트워크 연결 상태 확인
  • 테스트 환경에서는 테스트 유닛 ID 사용
  • 에러 코드를 확인하여 원인 파악
  • 광고 인벤토리 부족 시 나중에 재시도
  • 네이티브 SDK가 올바르게 연동되었는지 확인
  • onAdReceived 콜백 이후에 show()를 호출했는지 확인
  • isLoaded 속성을 확인하여 광고가 로드되었는지 확인
  • 네이티브 모듈이 올바르게 연결되었는지 확인

메모리 누수

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

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

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

관련 문서