> ## 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 앱에서 배너 광고를 구현하는 방법을 안내합니다.

## 개요

배너 광고는 화면의 일부 영역에 표시되는 직사각형 광고입니다. `AdropBanner` 컴포넌트를 사용하여 손쉽게 구현할 수 있습니다.

### 주요 특징

* 화면 상단, 하단 또는 중간에 고정 배치 가능
* 이미지 및 동영상 광고 지원
* 자동 또는 수동 광고 로드 지원
* 콜백을 통한 광고 이벤트 처리
* 광고 메타데이터 제공 (크리에이티브 ID, 캠페인 ID 등)

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

***

## AdropBanner 컴포넌트

### Props

<ParamField body="unitId" type="string" required>
  애드컨트롤 콘솔에서 생성한 유닛 ID
</ParamField>

<ParamField body="style" type="ViewStyle" required>
  배너의 스타일 (width와 height 필수)
</ParamField>

<ParamField body="autoLoad" type="boolean" default="true">
  컴포넌트가 마운트될 때 자동으로 광고를 로드할지 여부
</ParamField>

<ParamField body="useCustomClick" type="boolean" default="false">
  커스텀 클릭 처리를 사용할지 여부. `true`로 설정하면 광고 클릭 시 자동으로 브라우저가 열리지 않습니다.
</ParamField>

<ParamField body="adSize" type="{ width: number; height: number } | null">
  서버에 요청할 명시적 광고 크기. `style.width`가 숫자이면 스타일 크기에서 자동으로 `adSize`가 파생됩니다(`{ width: style.width, height: style.height }`). `style.width`가 문자열(예: `'100%'`)이면 `adSize`는 기본적으로 `null`이 되며 SDK가 반응형 크기 조정을 사용합니다. 일반적으로 이 prop을 수동으로 설정할 필요가 없습니다.
</ParamField>

<ParamField body="onAdReceived" type="(unitId: string, metadata?: AdropBannerMetadata) => void">
  광고 수신이 성공했을 때 호출되는 콜백
</ParamField>

<ParamField body="onAdClicked" type="(unitId: string, metadata?: AdropBannerMetadata) => void">
  사용자가 광고를 클릭했을 때 호출되는 콜백
</ParamField>

<ParamField body="onAdImpression" type="(unitId: string, metadata?: AdropBannerMetadata) => void">
  광고가 화면에 노출되었을 때 호출되는 콜백
</ParamField>

<ParamField body="onAdFailedToReceive" type="(unitId: string, errorCode?: string) => void">
  광고 수신이 실패했을 때 호출되는 콜백
</ParamField>

<ParamField body="onAdVideoStart" type="(unitId: string) => void">
  동영상 광고 재생이 시작되었을 때 호출되는 콜백
</ParamField>

<ParamField body="onAdVideoEnd" type="(unitId: string) => void">
  동영상 광고 재생이 종료되었을 때 호출되는 콜백
</ParamField>

***

## 기본 사용법

### 자동 로드 (권장)

컴포넌트가 마운트될 때 자동으로 광고를 로드합니다.

```typescript theme={null}
import React from 'react'
import { View, StyleSheet, Dimensions } from 'react-native'
import { AdropBanner } from 'adrop-ads-react-native'

const App = () => {
  const screenWidth = Dimensions.get('window').width

  return (
    <View style={styles.container}>
      {/* 메인 콘텐츠 */}
      <View style={styles.content}>
        {/* ... */}
      </View>

      {/* 배너 광고 */}
      <AdropBanner
        unitId="YOUR_UNIT_ID"
        style={{ width: screenWidth, height: 80 }}
        onAdReceived={(unitId, metadata) => {
          console.log('배너 광고 수신 성공', unitId, metadata)
        }}
        onAdFailedToReceive={(unitId, errorCode) => {
          console.log('배너 광고 수신 실패', unitId, errorCode)
        }}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  content: {
    flex: 1,
  },
})

export default App
```

***

## Ref를 사용한 수동 로드

`ref`를 사용하여 원하는 시점에 광고를 로드할 수 있습니다.

```typescript theme={null}
import React, { useRef } from 'react'
import { View, Button, StyleSheet, Dimensions } from 'react-native'
import { AdropBanner } from 'adrop-ads-react-native'

interface AdropBannerRef {
  load: () => void
}

const App = () => {
  const bannerRef = useRef<AdropBannerRef>(null)
  const screenWidth = Dimensions.get('window').width

  const loadBanner = () => {
    bannerRef.current?.load()
  }

  return (
    <View style={styles.container}>
      <Button title="배너 광고 로드" onPress={loadBanner} />

      <AdropBanner
        ref={bannerRef}
        unitId="YOUR_UNIT_ID"
        style={{ width: screenWidth, height: 80 }}
        autoLoad={false}
        onAdReceived={(unitId, metadata) => {
          console.log('배너 광고 수신 성공', unitId, metadata)
        }}
        onAdFailedToReceive={(unitId, errorCode) => {
          console.log('배너 광고 수신 실패', unitId, errorCode)
        }}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
})

export default App
```

***

## 콜백 함수

### onAdReceived

광고 수신이 성공했을 때 호출됩니다.

```typescript theme={null}
const handleAdReceived = (unitId: string, metadata?: AdropBannerMetadata) => {
  console.log('배너 광고 수신 성공')
  console.log('유닛 ID:', unitId)
  console.log('크리에이티브 ID:', metadata?.creativeId)
  console.log('캠페인 ID:', metadata?.campaignId)
  console.log('트랜잭션 ID:', metadata?.txId)
  console.log('목적지 URL:', metadata?.destinationURL)

  // 로딩 인디케이터 숨기기 등의 처리
}
```

### onAdClicked

사용자가 광고를 클릭했을 때 호출됩니다.

```typescript theme={null}
const handleAdClicked = (unitId: string, metadata?: AdropBannerMetadata) => {
  console.log('배너 광고 클릭')
  console.log('유닛 ID:', unitId)
  console.log('목적지 URL:', metadata?.destinationURL)

  // 클릭 분석 로깅 등의 처리
}
```

### onAdImpression

광고가 화면에 노출되었을 때 호출됩니다.

```typescript theme={null}
const handleAdImpression = (unitId: string, metadata?: AdropBannerMetadata) => {
  console.log('배너 광고 노출')
  console.log('유닛 ID:', unitId)
  console.log('크리에이티브 ID:', metadata?.creativeId)

  // 노출 분석 로깅 등의 처리
}
```

### onAdFailedToReceive

광고 수신이 실패했을 때 호출됩니다.

```typescript theme={null}
const handleAdFailedToReceive = (unitId: string, errorCode?: string) => {
  console.log('배너 광고 수신 실패')
  console.log('유닛 ID:', unitId)
  console.log('에러 코드:', errorCode)

  // 에러 처리 및 대체 콘텐츠 표시
  if (errorCode === AdropErrorCode.network) {
    console.log('네트워크 연결을 확인하세요')
  } else if (errorCode === AdropErrorCode.adNoFill) {
    console.log('노출 가능한 광고가 없습니다')
  }
}
```

### onAdVideoStart

동영상 광고 재생이 시작되었을 때 호출됩니다.

```typescript theme={null}
const handleAdVideoStart = (unitId: string) => {
  console.log('동영상 광고 재생 시작')
  console.log('유닛 ID:', unitId)
}
```

### onAdVideoEnd

동영상 광고 재생이 종료되었을 때 호출됩니다.

```typescript theme={null}
const handleAdVideoEnd = (unitId: string) => {
  console.log('동영상 광고 재생 종료')
  console.log('유닛 ID:', unitId)
}
```

***

## AdropBannerMetadata

광고 메타데이터 타입입니다.

```typescript theme={null}
type AdropBannerMetadata = {
  creativeId: string      // 크리에이티브 ID
  txId: string           // 트랜잭션 ID
  campaignId: string     // 캠페인 ID
  destinationURL: string // 목적지 URL
  browserTarget: BrowserTarget // 브라우저 타겟 (EXTERNAL = 0, INTERNAL = 1)
}
```

이 정보는 광고 분석, 추적, 리포팅에 유용하게 사용할 수 있습니다.

***

## 광고 크기

배너 광고는 유닛에 설정한 크기에 맞춰 스타일의 크기를 지정해야 합니다.

### 일반적인 배너 크기

| 크기        | 용도     |
| --------- | ------ |
| 320 x 50  | 소형 배너  |
| 320 x 100 | 중형 배너  |
| 16:9 비율   | 동영상 배너 |

### 고정 크기 사용

```typescript theme={null}
<AdropBanner
  unitId="YOUR_UNIT_ID"
  style={{ width: 320, height: 100 }}
/>
```

### 화면 너비에 맞추기

```typescript theme={null}
import { Dimensions } from 'react-native'

const screenWidth = Dimensions.get('window').width

<AdropBanner
  unitId="YOUR_UNIT_ID"
  style={{ width: screenWidth, height: 80 }}
/>
```

### 반응형 크기 사용

```typescript theme={null}
<AdropBanner
  unitId="YOUR_UNIT_ID"
  style={{ width: '100%', height: 80 }}
/>
```

<Note>
  `width`를 문자열(`'100%'` 등)로 설정하면 반응형으로 동작하지만, 숫자로 설정하면 해당 값이 광고 서버에 전달되어 적절한 크기의 광고를 요청합니다.
</Note>

***

## 테스트 유닛 ID

개발 및 테스트 시 아래의 테스트 유닛 ID를 사용하세요.

| 광고 유형        | 테스트 유닛 ID                     | 크기        |
| ------------ | ----------------------------- | --------- |
| 배너 (320x50)  | `PUBLIC_TEST_UNIT_ID_320_50`  | 320 x 50  |
| 배너 (320x100) | `PUBLIC_TEST_UNIT_ID_320_100` | 320 x 100 |

### 사용 예시

```typescript theme={null}
<AdropBanner
  unitId="PUBLIC_TEST_UNIT_ID_320_100"
  style={{ width: 320, height: 100 }}
/>
```

***

## 에러 처리

광고 로드 실패 시 적절한 에러 처리를 구현하세요.

### 에러 상태 관리

```typescript theme={null}
import React, { useState } from 'react'
import { View, Text, StyleSheet } from 'react-native'
import { AdropBanner } from 'adrop-ads-react-native'

const App = () => {
  const [error, setError] = useState<string | null>(null)

  const handleAdReceived = () => {
    setError(null)
  }

  const handleAdFailedToReceive = (unitId: string, errorCode?: string) => {
    setError(errorCode || '알 수 없는 오류')
  }

  return (
    <View style={styles.container}>
      <AdropBanner
        unitId="YOUR_UNIT_ID"
        style={{ width: 320, height: 100 }}
        onAdReceived={handleAdReceived}
        onAdFailedToReceive={handleAdFailedToReceive}
      />

      {error && (
        <Text style={styles.errorText}>
          광고 로드 실패: {error}
        </Text>
      )}
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  errorText: {
    marginTop: 8,
    color: 'red',
  },
})

export default App
```

***

## 모범 사례

### 1. 화면 가시성

배너가 화면에 보일 때 광고를 로드하세요.

```typescript theme={null}
import React, { useEffect, useRef } from 'react'
import { AppState } from 'react-native'

const App = () => {
  const bannerRef = useRef<{ load: () => void }>(null)
  const appState = useRef(AppState.currentState)

  useEffect(() => {
    const subscription = AppState.addEventListener('change', nextAppState => {
      if (
        appState.current.match(/inactive|background/) &&
        nextAppState === 'active'
      ) {
        // 앱이 포그라운드로 돌아왔을 때 광고 새로고침
        bannerRef.current?.load()
      }
      appState.current = nextAppState
    })

    return () => {
      subscription.remove()
    }
  }, [])

  return (
    <AdropBanner
      ref={bannerRef}
      unitId="YOUR_UNIT_ID"
      style={{ width: 320, height: 100 }}
    />
  )
}
```

### 2. 로딩 인디케이터

광고 로딩 중 사용자 경험을 개선하세요.

```typescript theme={null}
import React, { useState } from 'react'
import { View, ActivityIndicator, StyleSheet } from 'react-native'
import { AdropBanner } from 'adrop-ads-react-native'

const App = () => {
  const [loading, setLoading] = useState(true)

  return (
    <View style={styles.container}>
      {loading && (
        <ActivityIndicator
          style={styles.loader}
          size="small"
          color="#999"
        />
      )}

      <AdropBanner
        unitId="YOUR_UNIT_ID"
        style={{ width: 320, height: 100 }}
        onAdReceived={() => setLoading(false)}
        onAdFailedToReceive={() => setLoading(false)}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    position: 'relative',
  },
  loader: {
    position: 'absolute',
    top: '50%',
    left: '50%',
    transform: [{ translateX: -12 }, { translateY: -12 }],
  },
})
```

### 3. 다중 배너 관리

여러 배너를 사용할 때는 각각의 상태를 관리하세요.

```typescript theme={null}
import React, { useState } from 'react'
import { View, Text } from 'react-native'
import { AdropBanner } from 'adrop-ads-react-native'

const App = () => {
  const [banner1Loaded, setBanner1Loaded] = useState(false)
  const [banner2Loaded, setBanner2Loaded] = useState(false)

  return (
    <View>
      <Text>배너 1: {banner1Loaded ? '로드됨' : '로딩 중'}</Text>
      <AdropBanner
        unitId="UNIT_ID_1"
        style={{ width: 320, height: 100 }}
        onAdReceived={() => setBanner1Loaded(true)}
      />

      <Text>배너 2: {banner2Loaded ? '로드됨' : '로딩 중'}</Text>
      <AdropBanner
        unitId="UNIT_ID_2"
        style={{ width: 320, height: 100 }}
        onAdReceived={() => setBanner2Loaded(true)}
      />
    </View>
  )
}
```

### 4. 커스텀 클릭 처리

광고 클릭을 직접 처리하려면 `useCustomClick`을 사용하세요.

```typescript theme={null}
import { Linking } from 'react-native'
import { AdropBanner, type AdropBannerMetadata } from 'adrop-ads-react-native'

const App = () => {
  const handleAdClicked = (unitId: string, metadata?: AdropBannerMetadata) => {
    console.log('광고 클릭됨:', unitId)

    // 커스텀 분석 로깅
    analytics.logEvent('ad_clicked', {
      unitId,
      campaignId: metadata?.campaignId,
    })

    // 수동으로 브라우저 열기
    if (metadata?.destinationURL) {
      Linking.openURL(metadata.destinationURL)
    }
  }

  return (
    <AdropBanner
      unitId="YOUR_UNIT_ID"
      style={{ width: 320, height: 100 }}
      useCustomClick={true}
      onAdClicked={handleAdClicked}
    />
  )
}
```

***

## 전체 예제

### TypeScript 예제

```typescript theme={null}
import React, { useRef, useState } from 'react'
import {
  View,
  Text,
  Button,
  StyleSheet,
  Dimensions,
  ActivityIndicator,
} from 'react-native'
import { AdropBanner, type AdropBannerMetadata } from 'adrop-ads-react-native'

interface AdropBannerRef {
  load: () => void
}

const BannerExample = () => {
  const bannerRef = useRef<AdropBannerRef>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [metadata, setMetadata] = useState<AdropBannerMetadata | null>(null)

  const screenWidth = Dimensions.get('window').width

  const loadBanner = () => {
    setLoading(true)
    setError(null)
    bannerRef.current?.load()
  }

  const handleAdReceived = (unitId: string, metadata?: AdropBannerMetadata) => {
    console.log('✅ 배너 광고 수신 성공')
    console.log('유닛 ID:', unitId)
    console.log('메타데이터:', metadata)

    setLoading(false)
    setError(null)
    if (metadata) {
      setMetadata(metadata)
    }
  }

  const handleAdClicked = (unitId: string, metadata?: AdropBannerMetadata) => {
    console.log('👆 배너 광고 클릭')
    console.log('유닛 ID:', unitId)
    console.log('목적지 URL:', metadata?.destinationURL)
  }

  const handleAdImpression = (unitId: string, metadata?: AdropBannerMetadata) => {
    console.log('👁️ 배너 광고 노출')
    console.log('유닛 ID:', unitId)
    console.log('크리에이티브 ID:', metadata?.creativeId)
  }

  const handleAdFailedToReceive = (unitId: string, errorCode?: string) => {
    console.log('❌ 배너 광고 수신 실패')
    console.log('유닛 ID:', unitId)
    console.log('에러 코드:', errorCode)

    setLoading(false)
    setError(errorCode || '알 수 없는 오류')
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>배너 광고 예제</Text>

      <Button title="배너 광고 로드" onPress={loadBanner} />

      <View style={styles.bannerContainer}>
        {loading && (
          <ActivityIndicator
            style={styles.loader}
            size="small"
            color="#666"
          />
        )}

        <AdropBanner
          ref={bannerRef}
          unitId="YOUR_UNIT_ID"
          style={{ width: screenWidth, height: 80 }}
          autoLoad={false}
          onAdReceived={handleAdReceived}
          onAdClicked={handleAdClicked}
          onAdImpression={handleAdImpression}
          onAdFailedToReceive={handleAdFailedToReceive}
        />

        {error && (
          <View style={styles.errorContainer}>
            <Text style={styles.errorText}>에러: {error}</Text>
          </View>
        )}

        {metadata && (
          <View style={styles.metadataContainer}>
            <Text style={styles.metadataTitle}>광고 메타데이터:</Text>
            <Text style={styles.metadataText}>
              크리에이티브 ID: {metadata.creativeId}
            </Text>
            <Text style={styles.metadataText}>
              캠페인 ID: {metadata.campaignId}
            </Text>
            <Text style={styles.metadataText}>
              트랜잭션 ID: {metadata.txId}
            </Text>
          </View>
        )}
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    marginVertical: 50,
    paddingHorizontal: 16,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  bannerContainer: {
    marginTop: 20,
    position: 'relative',
    width: '100%',
  },
  loader: {
    position: 'absolute',
    top: 40,
    left: '50%',
    transform: [{ translateX: -12 }],
    zIndex: 1,
  },
  errorContainer: {
    marginTop: 8,
    padding: 8,
    backgroundColor: '#ffebee',
    borderRadius: 4,
  },
  errorText: {
    color: '#c62828',
    textAlign: 'center',
  },
  metadataContainer: {
    marginTop: 12,
    padding: 12,
    backgroundColor: '#f5f5f5',
    borderRadius: 4,
  },
  metadataTitle: {
    fontSize: 14,
    fontWeight: 'bold',
    marginBottom: 4,
  },
  metadataText: {
    fontSize: 12,
    color: '#666',
    marginTop: 2,
  },
})

export default BannerExample
```

### JavaScript 예제

```javascript theme={null}
import React, { useRef, useState } from 'react'
import {
  View,
  Text,
  Button,
  StyleSheet,
  Dimensions,
  ActivityIndicator,
} from 'react-native'
import { AdropBanner } from 'adrop-ads-react-native'

const BannerExample = () => {
  const bannerRef = useRef(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)

  const screenWidth = Dimensions.get('window').width

  const loadBanner = () => {
    setLoading(true)
    setError(null)
    bannerRef.current?.load()
  }

  const handleAdReceived = (unitId, metadata) => {
    console.log('배너 광고 수신 성공', unitId, metadata)
    setLoading(false)
    setError(null)
  }

  const handleAdFailedToReceive = (unitId, errorCode) => {
    console.log('배너 광고 수신 실패', unitId, errorCode)
    setLoading(false)
    setError(errorCode || '알 수 없는 오류')
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>배너 광고 예제</Text>

      <Button title="배너 광고 로드" onPress={loadBanner} />

      <View style={styles.bannerContainer}>
        {loading && <ActivityIndicator style={styles.loader} />}

        <AdropBanner
          ref={bannerRef}
          unitId="YOUR_UNIT_ID"
          style={{ width: screenWidth, height: 80 }}
          autoLoad={false}
          onAdReceived={handleAdReceived}
          onAdFailedToReceive={handleAdFailedToReceive}
        />

        {error && (
          <Text style={styles.errorText}>에러: {error}</Text>
        )}
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    marginVertical: 50,
    paddingHorizontal: 16,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  bannerContainer: {
    marginTop: 20,
    width: '100%',
  },
  loader: {
    marginVertical: 20,
  },
  errorText: {
    marginTop: 8,
    color: 'red',
    textAlign: 'center',
  },
})

export default BannerExample
```

***

## 백필 광고

<Info>백필 광고를 사용하려면 네이티브 플랫폼(Android/iOS)에 백필 의존성이 추가되어 있어야 합니다.</Info>

백필 광고가 활성화되면 직광고를 사용할 수 없을 때 SDK가 자동으로 백필 광고로 폴백합니다. `onAdFailedToReceive` 콜백에서 백필 관련 에러 코드를 처리할 수 있습니다.

```tsx theme={null}
<AdropBanner
  unitId="YOUR_UNIT_ID"
  onAdReceived={(unitId, metadata) => {
    console.log('광고 로드됨:', metadata?.creativeId)
  }}
  onAdFailedToReceive={(unitId, errorCode) => {
    switch (errorCode) {
      case AdropErrorCode.adNoFill:
        console.log('직광고 없음, 백필 광고 요청 중...')
        break
      case AdropErrorCode.backfillNoFill:
        console.log('백필 광고도 없습니다')
        break
      default:
        console.log('광고 로드 실패:', errorCode)
    }
  }}
/>
```

***

## 다음 단계

<CardGroup cols={2}>
  <Card title="네이티브 광고" href="/ko/sdk/react-native/native">
    UI에 맞게 커스터마이징 가능한 네이티브 광고 구현하기
  </Card>

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

  <Card title="팝업 광고" href="/ko/sdk/react-native/popup">
    작은 팝업 형태로 표시되는 광고 구현하기
  </Card>

  <Card title="레퍼런스" href="/ko/sdk/react-native/reference">
    타입, 메서드, 에러 코드 참고하기
  </Card>
</CardGroup>
