> ## Documentation Index
> Fetch the complete documentation index at: https://beta-guide.daro.so/llms.txt
> Use this file to discover all available pages before exploring further.

# 리워드 비디오 광고

## 리워드 비디오 형태 소개

* 광고 시청을 대가로 인앱 가치를 지닌 보상(재화, 기능, 컨텐츠 등)을 제공하는 형태의 광고입니다.
* 보상을 대가로 시청하므로 동영상 광고의 스킵이 불가능하며 일반적인 길이는 30초입니다.

<img src="https://mintcdn.com/delightroom-daro-beta/LsM-dUbMsm8UZFwD/sdk-integration/common-img/ad-formats/rv-example-image.png?fit=max&auto=format&n=LsM-dUbMsm8UZFwD&q=85&s=22a35894fa40b8c3364b29198618b14e" alt="Rv Example Image Pn" title="Rv Example Image Pn" style={{ width:"38%" }} width="1080" height="2336" data-path="sdk-integration/common-img/ad-formats/rv-example-image.png" />

### 동작 예시

<img src="https://mintcdn.com/delightroom-daro-beta/LsM-dUbMsm8UZFwD/sdk-integration/common-img/ad-formats/rv-example-gif.gif?s=235f7d5630c6f07363fc32565d3b7556" alt="Rv Example Gif Gi" title="Rv Example Gif Gi" style={{ width:"38%" }} width="180" height="389" data-path="sdk-integration/common-img/ad-formats/rv-example-gif.gif" />

***

## 패키지별 구현하기

<Tabs>
  <Tab title="react-native-daro">
    `react-native-daro` 1.0.16 이상에서는 리워드 광고를 Hook API로 사용할 수 있습니다. 컴포넌트 내부에서 `useRewardedAd`를 사용하면 로딩 상태와 리워드 콜백을 함께 관리할 수 있습니다.

    <Warning>
      기존의 정적 API(`RewardedAd.loadAd` 등)는 deprecated입니다. 정적 리스너(`RewardedAd.addAdLoadedEventListener` 등)는 Hook이나 인스턴스 API로 로드한 광고의 이벤트를 받지 못하니, 광고 로드를 새 API로 옮길 때 이벤트 리스너도 함께 옮겨주세요.
    </Warning>

    ```javascript theme={null}
    import { Button } from "react-native";
    import { useRewardedAd } from "react-native-daro";

    function RewardedAdButton({ adUnitId }) {
      const { isLoaded, isLoading, load, show, isAdReady } = useRewardedAd(
        adUnitId,
        {
          onLoaded: (adInfo) => {
            // 광고 로드 성공
          },
          onLoadFailed: (errorInfo) => {
            // 광고 로드 실패
          },
          onReceivedReward: (rewardInfo) => {
            // 리워드 지급
          },
          onHidden: (adInfo) => {
            // 광고 닫힘
          },
          onImpressionRecorded: (adInfo) => {
            // 광고 impression 기록
          },
        }
      );

      const handlePress = async () => {
        if (await isAdReady()) {
          show("CUSTOM_DATA");
          return;
        }

        load();
      };

      return (
        <Button
          disabled={isLoading}
          title={isLoaded ? "Show Rewarded" : "Load Rewarded"}
          onPress={handlePress}
        />
      );
    }
    ```
  </Tab>

  <Tab title="react-native-daro-m">
    `react-native-daro-m`에서는 Static API로 리워드 광고를 구현합니다. `RewardedAd.loadAd(unitId)`를 통해서 광고를 로드할 수 있습니다.

    ```javascript theme={null}
    import { Platform } from "react-native";
    import { RewardedAd } from "react-native-daro-m";
    import { AdDisplayFailedInfo, AdInfo, AdLoadFailedInfo, AdRevenueInfo, AdRewardInfo } from "react-native-daro-m";
    ```

    ```javascript theme={null}


    const REWARDED_AD_UNIT_ID = Platform.select({
      ios: "YOUR_IOS_REWARDED_AD_UNIT_ID",
      android: "YOUR_ANDROID_REWARDED_AD_UNIT_ID",
      default: ''
    });

    const initializeRewardedAds = () => {
      RewardedAd.addAdLoadedEventListener((adInfo: AdInfo) => { ... });
      RewardedAd.addAdLoadFailedEventListener((errorInfo: AdLoadFailedInfo) => { ... });
      RewardedAd.addAdClickedEventListener((adInfo: AdInfo) => { ... });
      RewardedAd.addAdDisplayedEventListener((adInfo: AdInfo) => { ... });
      RewardedAd.addAdFailedToDisplayEventListener((adInfo: AdDisplayFailedInfo) => { ... });
      RewardedAd.addAdHiddenEventListener((adInfo: AdInfo) => { ... });
      RewardedAd.addAdReceivedRewardEventListener((adInfo: AdRewardInfo) => { ... });
      RewardedAd.addAdImpressionRecordedListener((adInfo: AdInfo) => { ... });

      // Load the first rewarded ad
      loadRewardedAd();
    }

    const loadRewardedAd = () => {
      RewardedAd.loadAd(REWARDED_AD_UNIT_ID);
    }
    ```

    ### 광고 보여주기

    `RewardedAd.showAd(unitId)`를 통해서 로드한 광고를 보여줄 수 있습니다.

    ```javascript theme={null}
    const isRewardedReady = await RewardedAd.isAdReady(REWARDED_AD_UNIT_ID);

    if (isRewardedReady) {
      RewardedAd.showAd(REWARDED_AD_UNIT_ID);
    }
    ```

    ### 구현 예시

    <Accordion title="`RewardedAd` 구현 예시입니다." icon="sparkles">
      ```javascript theme={null}

      import { useEffect, useRef, useState } from "react";
      import { StyleSheet } from "react-native";
      // import문은 위의 탭 참조
      import { AdInfo, AdLoadFailedInfo, AdRevenueInfo } from "react-native-daro-m";
      import { RewardedAd } from "react-native-daro-m";
      import { ThemedButton } from "../ThemedButton";

      const MAX_EXPONENTIAL_RETRY_COUNT = 6;

      enum AdLoadState {
        notLoaded = 'NOT_LOADED',
        loading = 'LOADING',
        loaded = 'LOADED',
      }

      type Props = {
        adUnitId: string;
        isInitialized: boolean;
        log: (str: string) => void;
      };

      const RewardedAdExample = ({ adUnitId, isInitialized, log }: Props) => {
        const [adLoadState, setAdLoadState] = useState<AdLoadState>(AdLoadState.notLoaded);

        const retryAttempt = useRef(0);

        useEffect(() => {
          RewardedAd.addAdLoadedEventListener((adInfo: AdInfo) => {
            setAdLoadState(AdLoadState.loaded);

            log('Rewarded ad loaded');

            // Reset retry attempt
            retryAttempt.current = 0;
          });

          RewardedAd.addAdLoadFailedEventListener((errorInfo: AdLoadFailedInfo) => {
            setAdLoadState(AdLoadState.notLoaded);

            if (retryAttempt.current > MAX_EXPONENTIAL_RETRY_COUNT) {
              log('Rewarded ad failed to load with code ' + errorInfo.code);
              return;
            }

            // Rewarded ad failed to load
            // We recommend retrying with exponentially higher delays up to a maximum delay (in this case 64 seconds)
            retryAttempt.current += 1;

            const retryDelay = Math.pow(2, Math.min(MAX_EXPONENTIAL_RETRY_COUNT, retryAttempt.current));
            log('Rewarded ad failed to load with code ' + errorInfo.code + ' - retrying in ' + retryDelay + 's');

            setTimeout(() => {
              setAdLoadState(AdLoadState.loading);
              log('Rewarded ad retrying to load...');
              RewardedAd.loadAd(adUnitId);
            }, retryDelay * 1000);
          });

          RewardedAd.addAdClickedEventListener((/* adInfo: AdInfo */) => {
            log('Rewarded ad clicked');
          });
          RewardedAd.addAdDisplayedEventListener((/* adInfo: AdInfo */) => {
            log('Rewarded ad displayed');
          });
          RewardedAd.addAdFailedToDisplayEventListener((/* adInfo: AdDisplayFailedInfo */) => {
            setAdLoadState(AdLoadState.notLoaded);
            log('Rewarded ad failed to display');
          });
          RewardedAd.addAdHiddenEventListener((/* adInfo: AdInfo */) => {
            setAdLoadState(AdLoadState.notLoaded);
            log('Rewarded ad hidden');
          });
          RewardedAd.addAdReceivedRewardEventListener((/* adInfo: AdRewardInfo */) => {
            log('Rewarded ad granted reward');
          });
          RewardedAd.addAdImpressionRecordedListener((adInfo: AdRevenueInfo) => {
            log('Rewarded ad revenue paid: ' + adInfo.revenue);
          });
        }, [adUnitId, log]);

        const getRewardedButtonTitle = () => {
          if (adLoadState === AdLoadState.notLoaded) {
            return 'Load Rewarded';
          } else if (adLoadState === AdLoadState.loading) {
            return 'Loading...';
          } else {
            return 'Show Rewarded'; // adLoadState.loaded
          }
        };

        return (
          <ThemedButton
            isLoading={adLoadState === AdLoadState.loading}
            isEnabled={isInitialized && adLoadState !== AdLoadState.loading}
            title={getRewardedButtonTitle()}
            onPress={async () => {
              const isRewardedReady = await RewardedAd.isAdReady(adUnitId);
              if (isRewardedReady) {
                log('Rewarded ad ready to show');
                RewardedAd.showAd(adUnitId);
              } else {
                log('Loading rewarded ad...');
                setAdLoadState(AdLoadState.loading);
                RewardedAd.loadAd(adUnitId);
              }
            }}
          />
        );
      }


      const styles = StyleSheet.create({
        button: {
          margin: 5,
        },
      });

      export default RewardedAdExample;
      ```
    </Accordion>

    ## 리워드 비디오 광고 콜백 메서드

    * 다음 코드는 사용자의 내부 User ID를 태그하고, 콜백에 CustomData를 추가하는 방법을 보여줍니다.
      * User ID 문자열의 최대 크기는 8192자입니다.

    ```javascript theme={null}

    setUserId("${USER_ID}");

    ...

    const isRewardedReady = await RewardedAd.isAdReady(REWARDED_AD_UNIT_ID);

    if (isRewardedReady) {
      RewardedAd.showAd(REWARDED_AD_UNIT_ID, "CUSTOM_DATA");
    }
    ```
  </Tab>
</Tabs>
