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

# 네이티브 광고

> iOS에서 네이티브 광고를 구현하는 방법을 안내합니다.

## 개요

네이티브 광고는 앱의 UI에 자연스럽게 통합되는 광고 포맷입니다. 광고 요소(제목, 이미지, 설명 등)를 앱 디자인에 맞게 자유롭게 커스터마이징할 수 있습니다.

### 주요 특징

* 앱 UI와 완벽하게 통합 가능한 커스텀 디자인
* 광고 요소 개별 접근 및 배치
* 광고주 프로필 정보 표시 옵션
* 추가 커스텀 필드 지원

***

## 구현 방법

네이티브 광고 구현은 다음 단계로 진행됩니다:

1. 광고 로드
2. 커스텀 뷰 생성
3. 뷰 바인딩
4. Delegate 처리

***

## 1. 광고 로드

`AdropNativeAd` 인스턴스를 생성하고 광고를 로드합니다.

<CodeGroup>
  ```swift Swift theme={null}
  import AdropAds

  class MyViewController: UIViewController {
      private var nativeAd: AdropNativeAd?

      override func viewDidLoad() {
          super.viewDidLoad()

          // 네이티브 광고 생성
          nativeAd = AdropNativeAd(unitId: "YOUR_NATIVE_UNIT_ID")
          nativeAd?.delegate = self

          // 광고 로드
          nativeAd?.load()
      }
  }
  ```

  ```objc Objective-C theme={null}
  @import AdropAds;

  @interface MyViewController () <AdropNativeAdDelegate>
  @property (nonatomic, strong) AdropNativeAd *nativeAd;
  @end

  @implementation MyViewController

  - (void)viewDidLoad {
      [super viewDidLoad];

      // 네이티브 광고 생성
      self.nativeAd = [[AdropNativeAd alloc] initWithUnitId:@"YOUR_NATIVE_UNIT_ID"];
      self.nativeAd.delegate = self;

      // 광고 로드
      [self.nativeAd load];
  }

  @end
  ```
</CodeGroup>

### Context ID 설정

[문맥 타겟팅](/ko/sdk/ios/targeting#문맥-타겟팅)을 위해 Context ID를 설정할 수 있습니다.

<CodeGroup>
  ```swift Swift theme={null}
  // contextId는 읽기 전용 — 초기화 시 설정
  let nativeAd = AdropNativeAd(unitId: "YOUR_UNIT_ID", contextId: "article_123")
  ```

  ```objc Objective-C theme={null}
  // contextId는 읽기 전용 — 초기화 시 설정
  AdropNativeAd *nativeAd = [[AdropNativeAd alloc] initWithUnitId:@"YOUR_UNIT_ID" contextId:@"article_123"];
  ```
</CodeGroup>

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

***

## 2. 커스텀 뷰 생성

스토리보드 또는 코드로 네이티브 광고 뷰를 구성합니다.

### UIKit (Storyboard/XIB)

스토리보드에서 `AdropNativeAdView`를 생성하고 광고 요소를 IBOutlet으로 연결합니다.

```swift theme={null}
import AdropAds

class NativeAdViewCell: UITableViewCell {
    @IBOutlet weak var nativeAdView: AdropNativeAdView!
    @IBOutlet weak var iconImageView: UIImageView!
    @IBOutlet weak var headlineLabel: UILabel!
    @IBOutlet weak var bodyLabel: UILabel!
    @IBOutlet weak var mediaView: UIView!
    @IBOutlet weak var callToActionButton: UIButton!

    // 광고주 프로필 (선택사항)
    @IBOutlet weak var advertiserLogoImageView: UIImageView!
    @IBOutlet weak var advertiserNameLabel: UILabel!

    func configure(with ad: AdropNativeAd) {
        // 뷰 바인딩 (다음 섹션 참고)
    }
}
```

### UIKit (코드)

```swift theme={null}
import AdropAds

class NativeAdView: UIView {
    let nativeAdView = AdropNativeAdView()
    let iconImageView = UIImageView()
    let headlineLabel = UILabel()
    let bodyLabel = UILabel()
    let mediaView = UIView()
    let callToActionButton = UIButton()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    private func setupViews() {
        addSubview(nativeAdView)
        nativeAdView.addSubview(iconImageView)
        nativeAdView.addSubview(headlineLabel)
        nativeAdView.addSubview(bodyLabel)
        nativeAdView.addSubview(mediaView)
        nativeAdView.addSubview(callToActionButton)

        // Auto Layout 설정
        // ...
    }
}
```

***

## 3. 뷰 바인딩

`AdropNativeAdView`에 광고 요소를 바인딩하여 광고 데이터를 표시합니다.

```swift theme={null}
func configure(with ad: AdropNativeAd) {
    // 각 요소를 AdropNativeAdView에 바인딩
    nativeAdView.setIconView(iconImageView)
    nativeAdView.setHeadLineView(headlineLabel)
    nativeAdView.setBodyView(bodyLabel)
    nativeAdView.setMediaView(mediaView)
    nativeAdView.setCallToActionView(callToActionButton)

    // 광고주 프로필 (선택사항)
    if let advertiserLogoView = advertiserLogoImageView,
       let advertiserNameView = advertiserNameLabel {
        nativeAdView.setProfileLogoView(advertiserLogoView)
        nativeAdView.setProfileNameView(advertiserNameView)
    }

    // 광고 데이터 설정 (자동으로 바인딩된 뷰에 표시됨)
    nativeAdView.setNativeAd(ad)
}
```

### 바인딩 메서드

| 메서드                               | 설명                                                                                                                                                    | 필수 |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -- |
| `setIconView(_:onClick:)`         | 아이콘 이미지 뷰 설정. `onClick: ((AdropNativeAd?, UIView) -> Void)? = nil`                                                                                    | 선택 |
| `setHeadLineView(_:onClick:)`     | 제목 레이블 설정. `onClick: ((AdropNativeAd?, UIView) -> Void)? = nil`                                                                                       | 선택 |
| `setBodyView(_:)`                 | 설명 레이블 설정                                                                                                                                             | 선택 |
| `setMediaView(_:)`                | 메인 이미지/비디오 뷰 설정. **영상 크리에이티브에는 필수** — VTR과 `onAdVideoStart` / `onAdVideoEnd` 콜백은 SDK 미디어 컨테이너가 이 메서드로 바인딩될 때에만 발생합니다. [영상 트래킹과 VTR](#영상-트래킹과-vtr) 참고. | 선택 |
| `setCallToActionView(_:onClick:)` | CTA 버튼 설정. `onClick: ((AdropNativeAd?, UIView) -> Void)? = nil`                                                                                       | 선택 |
| `setAdvertiserView(_:onClick:)`   | 광고주 뷰 설정. `onClick: ((AdropNativeAd?, UIView) -> Void)? = nil`                                                                                        | 선택 |
| `setProfileLogoView(_:onClick:)`  | 광고주 로고 이미지 뷰 설정. `onClick: ((AdropNativeAd?, UIView) -> Void)? = nil`                                                                                 | 선택 |
| `setProfileNameView(_:onClick:)`  | 광고주 이름 레이블 설정. `onClick: ((AdropNativeAd?, UIView) -> Void)? = nil`                                                                                   | 선택 |
| `setNativeAd(_:)`                 | 광고 데이터 설정                                                                                                                                             | 필수 |

<Note>
  `onClick` 클로저는 사용자가 바인딩된 뷰를 탭할 때 호출됩니다. 현재 `AdropNativeAd?` 인스턴스와 탭된 `UIView`를 파라미터로 받습니다. 제공하지 않으면 기본 클릭 동작(목적지 URL 열기)이 사용됩니다.
</Note>

<Note>
  광고주 프로필을 표시하려면 애드컨트롤 콘솔에서 해당 광고 유닛의 <strong>광고주 프로필 표시</strong>를 활성화해야 합니다.
</Note>

***

## 4. Delegate 처리

`AdropNativeAdDelegate`를 구현하여 광고 이벤트를 처리합니다.

<CodeGroup>
  ```swift Swift theme={null}
  extension MyViewController: AdropNativeAdDelegate {
      // 광고 수신 성공
      func onAdReceived(_ nativeAd: AdropNativeAd) {
          print("네이티브 광고 수신 성공")

          // 광고 데이터에 접근
          print("제목: \(nativeAd.headline)")
          print("설명: \(nativeAd.body)")
          print("CTA: \(nativeAd.callToAction)")

          // 뷰에 광고 바인딩
          configureNativeAdView(with: nativeAd)
      }

      // 광고 수신 실패
      func onAdFailedToReceive(_ nativeAd: AdropNativeAd, _ errorCode: AdropErrorCode) {
          print("네이티브 광고 수신 실패: \(errorCode)")
      }

      // 광고 클릭 (선택사항)
      func onAdClicked(_ nativeAd: AdropNativeAd) {
          print("네이티브 광고 클릭")
      }

      // 광고 노출 (선택사항)
      func onAdImpression(_ nativeAd: AdropNativeAd) {
          print("네이티브 광고 노출")
      }
  }
  ```

  ```objc Objective-C theme={null}
  #pragma mark - AdropNativeAdDelegate

  // 광고 수신 성공
  - (void)onAdReceived:(AdropNativeAd *)nativeAd {
      NSLog(@"네이티브 광고 수신 성공");

      // 광고 데이터에 접근
      if (nativeAd.headline) {
          NSLog(@"제목: %@", nativeAd.headline);
      }

      if (nativeAd.body) {
          NSLog(@"설명: %@", nativeAd.body);
      }

      if (nativeAd.callToAction) {
          NSLog(@"CTA: %@", nativeAd.callToAction);
      }

      // 뷰에 광고 바인딩
      [self configureNativeAdViewWith:nativeAd];
  }

  // 광고 수신 실패
  - (void)onAdFailedToReceive:(AdropNativeAd *)nativeAd :(AdropErrorCode)errorCode {
      NSLog(@"네이티브 광고 수신 실패: %ld", (long)errorCode);
  }

  // 광고 클릭 (선택사항)
  - (void)onAdClicked:(AdropNativeAd *)nativeAd {
      NSLog(@"네이티브 광고 클릭");
  }

  // 광고 노출 (선택사항)
  - (void)onAdImpression:(AdropNativeAd *)nativeAd {
      NSLog(@"네이티브 광고 노출");
  }
  ```
</CodeGroup>

### Delegate 메서드

| 메서드                         | 필수 | 설명                    |
| --------------------------- | -- | --------------------- |
| `onAdReceived(_:)`          | 필수 | 광고 로드 성공 시 호출         |
| `onAdFailedToReceive(_:_:)` | 필수 | 광고 로드 실패 시 호출         |
| `onAdClicked(_:)`           | 선택 | 사용자가 광고를 클릭했을 때 호출    |
| `onAdImpression(_:)`        | 선택 | 광고가 노출되었을 때 호출        |
| `onAdVideoStart(_:)`        | 선택 | 동영상 광고 재생이 시작되었을 때 호출 |
| `onAdVideoEnd(_:)`          | 선택 | 동영상 광고 재생이 완료되었을 때 호출 |

***

## 클로저 콜백

Delegate 대신 클로저 기반 콜백을 사용할 수 있습니다.

```swift theme={null}
let nativeAd = AdropNativeAd(unitId: "YOUR_UNIT_ID")

nativeAd.onAdReceived = { ad in
    print("네이티브 광고 수신 성공")
}

nativeAd.onAdFailedToReceive = { ad, errorCode in
    print("네이티브 광고 수신 실패: \(errorCode)")
}

nativeAd.onAdImpression = { ad in
    print("네이티브 광고 노출")
}

nativeAd.onAdClicked = { ad in
    print("네이티브 광고 클릭")
}

nativeAd.onAdVideoStart = { ad in
    print("네이티브 광고 동영상 재생 시작")
}

nativeAd.onAdVideoEnd = { ad in
    print("네이티브 광고 동영상 재생 완료")
}
```

<Note>
  Delegate와 클로저를 동시에 설정하면 두 가지 모두 호출됩니다.
</Note>

***

## 광고 속성

`AdropNativeAd` 객체를 통해 광고 데이터에 접근할 수 있습니다.

### 기본 속성

```swift theme={null}
// 광고 수신 성공 시
func onAdReceived(_ nativeAd: AdropNativeAd) {
    // 제목
    print("제목: \(nativeAd.headline)")

    // 설명
    print("설명: \(nativeAd.body)")

    // CTA 버튼 텍스트
    print("CTA: \(nativeAd.callToAction)")

    // 메인 이미지/비디오
    print("미디어 URL: \(nativeAd.asset)")
}
```

### 광고주 프로필

```swift theme={null}
// 광고주 정보 (profile 및 하위 프로퍼티는 non-optional)
let profile = nativeAd.profile
print("광고주 로고: \(profile.displayLogo)")
print("광고주 이름: \(profile.displayName)")

// 프로필 링크 (선택사항 — 광고주 페이지 링크)
if let link = profile.link {
    print("프로필 링크: \(link)")
}
```

### 커스텀 필드

애드컨트롤 콘솔에서 설정한 추가 텍스트 항목에 접근할 수 있습니다.

```swift theme={null}
// 추가 텍스트 항목 (extra는 non-optional [String: String])
let extra = nativeAd.extra
if !extra.isEmpty {
    // 예: 가격 정보
    if let price = extra["price"] {
        print("가격: \(price)")
    }

    // 예: 할인율
    if let discount = extra["discount"] {
        print("할인율: \(discount)")
    }

    // 예: 평점
    if let rating = extra["rating"] {
        print("평점: \(rating)")
    }
}
```

<Note>
  `extra` 필드는 애드컨트롤 콘솔의 광고 유닛 설정에서 정의한 추가 텍스트 항목 ID를 키로 사용합니다.
</Note>

### 속성 목록

| 속성               | 타입                     | 설명                |
| ---------------- | ---------------------- | ----------------- |
| `unitId`         | `String`               | 광고 유닛 ID          |
| `contextId`      | `String`               | 문맥 타겟팅용 ID        |
| `headline`       | `String`               | 광고 제목             |
| `body`           | `String`               | 광고 설명             |
| `callToAction`   | `String`               | CTA 버튼 텍스트        |
| `icon`           | `String`               | 아이콘 이미지 URL       |
| `cover`          | `String`               | 커버 이미지 URL        |
| `asset`          | `String`               | 메인 이미지/비디오 URL    |
| `creative`       | `String`               | 크리에이티브 HTML 콘텐츠   |
| `creativeSize`   | `CGSize`               | 크리에이티브 콘텐츠 사이즈    |
| `advertiser`     | `String`               | 광고주 이름            |
| `advertiserURL`  | `String`               | 광고주 URL           |
| `profile`        | `AdropNativeAdProfile` | 광고주 프로필 정보        |
| `extra`          | `[String: String]`     | 추가 커스텀 필드         |
| `accountTag`     | `[String: Any]`        | 계정 레벨 태그 데이터      |
| `creativeTag`    | `[String: Any]`        | 크리에이티브 레벨 태그 데이터  |
| `destinationURL` | `String?`              | 광고 목적지 URL        |
| `txId`           | `String`               | 트랜잭션 ID           |
| `campaignId`     | `String`               | 캠페인 ID            |
| `creativeId`     | `String`               | 크리에이티브 ID         |
| `browserTarget`  | `BrowserTarget?`       | 광고 클릭 시 URL 열기 방식 |
| `isLoaded`       | `Bool`                 | 광고 로드 여부          |
| `isBackfilled`   | `Bool`                 | 백필 광고 여부          |

### AdropNativeAdProfile

| 속성            | 타입        | 설명             |
| ------------- | --------- | -------------- |
| `displayLogo` | `String`  | 광고주 로고 이미지 URL |
| `displayName` | `String`  | 광고주 표시 이름      |
| `link`        | `String?` | 광고주 페이지 링크     |

***

## 커스텀 클릭

커스텀 클릭을 사용하면 기본 동작(목적지 URL 열기) 대신 광고 클릭 동작을 직접 처리할 수 있습니다.

### 설정

<CodeGroup>
  ```swift Swift theme={null}
  let nativeAd = AdropNativeAd(unitId: "YOUR_UNIT_ID")
  nativeAd.useCustomClick = true
  ```

  ```objc Objective-C theme={null}
  AdropNativeAd *nativeAd = [[AdropNativeAd alloc] initWithUnitId:@"YOUR_UNIT_ID"];
  nativeAd.useCustomClick = YES;
  ```
</CodeGroup>

### 전체 클릭 영역

`setIsEntireClick(_:)`을 사용하여 `AdropNativeAdView` 전체를 클릭 가능하게 만듭니다.

```swift theme={null}
nativeAdView.setIsEntireClick(true)
```

<Note>
  `useCustomClick`이 `true`인 경우, `setNativeAd(_:)`에서 `setIsEntireClick(true)`가 자동으로 호출됩니다.
</Note>

### 수동 클릭

`performClick()`을 사용하여 수동으로 클릭 이벤트를 트리거합니다.

```swift theme={null}
nativeAdView.performClick()
```

### URL 열기

`open(_:useInAppBrowser:)`를 사용하여 프로그래밍 방식으로 URL을 엽니다.

```swift theme={null}
// 목적지 URL 열기
nativeAd.open(nativeAd.destinationURL)

// 인앱 브라우저로 열기
nativeAd.open(nativeAd.destinationURL, useInAppBrowser: true)
```

***

## 영상 트래킹과 VTR

Adrop은 네이티브 광고의 영상 지표 — VTR(영상 완수율), `onAdVideoStart`, `onAdVideoEnd` — 를 SDK 미디어 컨테이너(`AdropNativeAdView.setMediaView(_:)`로 바인딩된 `UIView`) 안에서 영상이 렌더링될 때에만 수집합니다.

`AdropNativeAd.asset` 프로퍼티는 원본 이미지 또는 영상 파일의 URL을 반환합니다. 이 값은 썸네일 표시나 매체사 자체 분석 등 **부가 메타데이터** 용도로 노출된 것이며, 재생을 직접 처리하기 위한 것이 아닙니다.

<Warning>
  영상 네이티브 광고의 `asset` URL을 자체 영상 플레이어(`AVPlayer`, `AVPlayerViewController` 또는 서드파티 플레이어)에 직접 전달하지 마세요. SDK 미디어 컨테이너를 거치지 않으면 다음 현상이 발생합니다.

  * 해당 지면에서 **VTR(영상 완수율)이 수집되지 않습니다.**
  * `onAdVideoStart` / `onAdVideoEnd` 콜백이 **호출되지 않습니다.**
  * 해당 유닛의 영상 성과 집계가 누락되거나 0으로 보고됩니다.

  클릭(`onAdClicked`)과 노출(`onAdImpression`) 트래킹은 컨테이너 뷰에 연결되어 있으므로 계속 동작하지만, 영상 관련 신호는 손실됩니다.
</Warning>

### 권장 패턴

영상 네이티브 광고에는 항상 SDK 미디어 컨테이너를 바인딩하세요.

<CodeGroup>
  ```swift Swift theme={null}
  nativeAdView.setMediaView(mediaView)    // 영상 트래킹을 위해 필수
  nativeAdView.setNativeAd(ad)
  ```

  ```objc Objective-C theme={null}
  [self.nativeAdView setMediaView:self.mediaView];    // 영상 트래킹을 위해 필수
  [self.nativeAdView setNativeAd:ad];
  ```
</CodeGroup>

<Note>
  특정 지면이 반드시 자체 플레이어를 사용해야 하고 VTR이 측정되지 않는 것을 수용한다면, 광고를 `AdropNativeAdView`에 바인딩한 채로 유지해 클릭과 노출 어트리뷰션은 계속 확보할 수 있습니다. 다만 해당 지면을 내부 리포트에서 **비-VTR 인벤토리**로 분류하고 SDK가 측정한 영상 성과와 섞지 마세요.
</Note>

***

## 모범 사례

### 에러 처리

광고 로드 실패 시 대체 UI를 표시하여 사용자 경험을 유지하세요.

```swift theme={null}
func onAdFailedToReceive(_ nativeAd: AdropNativeAd, _ errorCode: AdropErrorCode) {
    print("네이티브 광고 수신 실패: \(errorCode)")

    // 광고 영역 숨기기
    nativeAdContainerView.isHidden = true

    // 또는 대체 콘텐츠 표시
    showFallbackContent()
}
```

***

## 테스트 유닛 ID

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

| 광고 타입           | 테스트 유닛 ID                               |
| --------------- | --------------------------------------- |
| 네이티브 (이미지)      | `PUBLIC_TEST_UNIT_ID_NATIVE`            |
| 네이티브 비디오 (16:9) | `PUBLIC_TEST_UNIT_ID_NATIVE_VIDEO_16_9` |
| 네이티브 비디오 (9:16) | `PUBLIC_TEST_UNIT_ID_NATIVE_VIDEO_9_16` |

```swift theme={null}
// 테스트 광고 로드
nativeAd = AdropNativeAd(unitId: AdropUnitId.PUBLIC_TEST_UNIT_ID_NATIVE)
```

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

***

## 일괄 로드 (loads)

`AdropNativeAd.loads(...)`를 사용하면 한 번의 호출로 여러 네이티브 광고를 요청할 수 있습니다. 피드·캐러셀·페이지네이션 리스트에 삽입할 광고 풀을 프리페칭하는 데 유용합니다.

### 시그니처

<CodeGroup>
  ```swift Swift theme={null}
  AdropNativeAd.loads(
      unitId: String,
      contextId: String = "",
      delegate: AdropNativeAdDelegate
  )
  ```

  ```objc Objective-C theme={null}
  [AdropNativeAd loadsWithUnitId:@"YOUR_UNIT_ID"
                       contextId:@""
                        delegate:delegate];
  ```
</CodeGroup>

### 사용 방법

<CodeGroup>
  ```swift Swift theme={null}
  class ViewController: UIViewController {
      private var ads: [AdropNativeAd] = []

      override func viewDidLoad() {
          super.viewDidLoad()
          AdropNativeAd.loads(unitId: "YOUR_UNIT_ID", delegate: self)
      }
  }

  extension ViewController: AdropNativeAdDelegate {
      // 단건 콜백 — 배치 경로에서는 사용되지 않습니다.
      func onAdReceived(_ ad: AdropNativeAd) { /* batch path */ }
      func onAdFailedToReceive(_ ad: AdropNativeAd, _ errorCode: AdropErrorCode) {}

      // 배치 성공 — 각 광고는 렌더링이 완료된 상태로 전달됩니다.
      func onAdsReceived(_ ads: [AdropNativeAd]) {
          self.ads = ads
          ads.forEach { ad in
              bind(ad)  // AdropNativeAdView에 바인딩
          }
      }

      // 배치 실패
      func onAdsFailedToReceive(_ errorCode: AdropErrorCode) {
          print("배치 로드 실패: \(errorCode)")
      }

      // 클릭/노출/비디오 콜백은 각 인스턴스에 대해 정상 호출됩니다.
      func onAdClicked(_ ad: AdropNativeAd) {
          print("네이티브 클릭")
      }

      func onAdImpression(_ ad: AdropNativeAd) {
          print("네이티브 노출")
      }
  }
  ```

  ```objc Objective-C theme={null}
  @interface ViewController () <AdropNativeAdDelegate>
  @property (nonatomic, strong) NSArray<AdropNativeAd *> *ads;
  @end

  @implementation ViewController

  - (void)viewDidLoad {
      [super viewDidLoad];
      [AdropNativeAd loadsWithUnitId:@"YOUR_UNIT_ID" contextId:@"" delegate:self];
  }

  #pragma mark - AdropNativeAdDelegate

  - (void)onAdReceived:(AdropNativeAd *)ad { /* batch path */ }
  - (void)onAdFailedToReceive:(AdropNativeAd *)ad :(AdropErrorCode)errorCode {}

  - (void)onAdsReceived:(NSArray<AdropNativeAd *> *)ads {
      self.ads = ads;
      for (AdropNativeAd *ad in ads) {
          [self bindNativeAd:ad];
      }
  }

  - (void)onAdsFailedToReceive:(AdropErrorCode)errorCode {
      NSLog(@"배치 로드 실패: %ld", (long)errorCode);
  }

  - (void)onAdClicked:(AdropNativeAd *)ad {
      NSLog(@"네이티브 클릭");
  }

  - (void)onAdImpression:(AdropNativeAd *)ad {
      NSLog(@"네이티브 노출");
  }

  @end
  ```
</CodeGroup>

### 델리게이트 메서드

| 메서드                                                                  | 호출 시점                                                        |
| -------------------------------------------------------------------- | ------------------------------------------------------------ |
| `onAdsReceived(_:)`                                                  | 배치 전달 완료. **모든 광고가 완전히 렌더링된 상태**로 전달됩니다.                     |
| `onAdsFailedToReceive(_:)`                                           | 요청 거부, 네트워크 실패 또는 표시 가능한 광고가 없는 경우(`ERROR_CODE_AD_NO_FILL`). |
| `onAdClicked` / `onAdImpression` / `onAdVideoStart` / `onAdVideoEnd` | 단건 `load()`와 동일하게 각 광고별로 호출됩니다.                              |

<Warning>
  단건 `onAdReceived(_:)` / `onAdFailedToReceive(_:_:)` 콜백은 `loads` 경로에서 **호출되지 않습니다**. 배치 결과는 반드시 `onAdsReceived(_:)` / `onAdsFailedToReceive(_:)`로만 수신하세요.
</Warning>

### 상수

<ParamField body="AdropNativeAd.maxLoadsBatch" type="Int" default="5">
  단일 `loads(...)` 호출에서 반환되는 광고의 최대 개수.
</ParamField>

### 제약 사항

* **호출당 최대 5개.** 서버가 그 이상을 반환하더라도 앞의 5개만 전달됩니다.
* **백필은 적용되지 않습니다.** 직광고 채움이 없으면 백필 설정과 무관하게 `onAdsFailedToReceive`가 `ERROR_CODE_AD_NO_FILL`로 호출됩니다.
* `AdropBanner.loads(...)`와 달리, 네이티브 배치는 **모든 광고의 렌더링이 끝날 때까지 기다린 후** `onAdsReceived(_:)`를 호출합니다. 전달 시점에 각 인스턴스는 완전히 렌더링된 상태입니다.
* 반환된 광고에 대해 강한 참조를 유지하세요. `AdropNativeAdView`에 바인딩되기 전에 해제되면 조용히 드롭됩니다.

***

## 백필 광고

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

<CodeGroup>
  ```swift Swift theme={null}
  class ViewController: UIViewController, AdropNativeAdDelegate {
      private var nativeAd: AdropNativeAd?

      func onAdReceived(_ nativeAd: AdropNativeAd) {
          if nativeAd.isBackfilled {
              print("백필 광고가 로드되었습니다")
          } else {
              print("직광고가 로드되었습니다")
          }
      }

      func onAdFailedToReceive(_ nativeAd: AdropNativeAd, _ errorCode: AdropErrorCode) {
          switch errorCode {
          case .ERROR_CODE_AD_NO_FILL:
              print("직광고 없음, 백필 광고 요청 중...")
          case .ERROR_CODE_AD_BACKFILL_NO_FILL:
              print("백필 광고도 없습니다")
              // 광고 영역 숨김 처리
          default:
              print("광고 로드 실패: \(errorCode)")
          }
      }
  }
  ```

  ```objc Objective-C theme={null}
  @interface ViewController () <AdropNativeAdDelegate>
  @property (nonatomic, strong) AdropNativeAd *nativeAd;
  @end

  @implementation ViewController

  - (void)onAdReceived:(AdropNativeAd *)nativeAd {
      if (nativeAd.isBackfilled) {
          NSLog(@"백필 광고가 로드되었습니다");
      } else {
          NSLog(@"직광고가 로드되었습니다");
      }
  }

  - (void)onAdFailedToReceive:(AdropNativeAd *)nativeAd :(AdropErrorCode)errorCode {
      if (errorCode == AdropErrorCodeAdNoFill) {
          NSLog(@"직광고 없음, 백필 광고 요청 중...");
      } else if (errorCode == AdropErrorCodeBackfillNoFill) {
          NSLog(@"백필 광고도 없습니다");
          // 광고 영역 숨김 처리
      } else {
          NSLog(@"광고 로드 실패: %ld", (long)errorCode);
      }
  }

  @end
  ```
</CodeGroup>

### AdChoices 위치 조정

백필 네이티브 광고에서 AdChoices 마크가 표시될 코너를 지정할 수 있습니다. `load()` 호출 전에 `AdropNativeAd` 인스턴스의 `preferredAdChoicesPosition`을 설정하세요.

<CodeGroup>
  ```swift Swift theme={null}
  import AdropAds

  let nativeAd = AdropNativeAd(unitId: "YOUR_UNIT_ID")
  nativeAd.preferredAdChoicesPosition = .bottomRight
  nativeAd.load()
  ```

  ```objc Objective-C theme={null}
  @import AdropAds;

  AdropNativeAd *nativeAd = [[AdropNativeAd alloc] initWithUnitId:@"YOUR_UNIT_ID"];
  nativeAd.preferredAdChoicesPosition = AdropAdChoicesPositionBottomRight;
  [nativeAd load];
  ```
</CodeGroup>

| 값              | 설명          |
| -------------- | ----------- |
| `.topLeft`     | 좌측 상단       |
| `.topRight`    | 우측 상단 (기본값) |
| `.bottomLeft`  | 좌측 하단       |
| `.bottomRight` | 우측 하단       |

<Note>
  이 설정은 백필 네트워크에 전달되는 선호 위치 힌트로, 백필 네이티브 광고에만 적용됩니다 — 직광고에는 영향이 없습니다. 반드시 `load()` 호출 전에 설정해야 하며, 백필 네트워크가 정책상 다른 위치로 표시할 수 있습니다.
</Note>

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

***

## 관련 문서

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

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

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

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