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

# 네이티브 광고

> DARO를 통해 네이티브 광고를 구현하는 방법을 알아봅니다.

## 네이티브 광고 포맷 소개

* 광고 뷰를 SDK가 자체적으로 구현해주는 타 광고 포맷와 달리 네이티브 광고 포맷는 구성 요소들을 전달받아 앱에서 직접 광고 뷰를 구현합니다.
* UI/UX 기반으로 레이아웃을 직접 구현하므로써 위화감을 적게 만들 수 있다는 것이 가장 큰 특징입니다. 단, 유저가 광고가 아닌 컨텐츠로써 착각하는 경우를 방지하기 위해 광고 표시와 함께 최소한의 차별성은 부여해야합니다.

<img src="https://mintcdn.com/delightroom-5a71a6a8/dxU0bpsPoPvkYh_g/sdk-integration/common-img/ad-formats/native-example-elements-ko.png?fit=max&auto=format&n=dxU0bpsPoPvkYh_g&q=85&s=3f2c4b8e38bff2137e0bac37c1254931" alt="Native Example Elements Ko Pn" width="1968" height="2888" data-path="sdk-integration/common-img/ad-formats/native-example-elements-ko.png" />

<Info>
  **네이티브 광고 필수 요소 4가지**

  네이티브 광고는 앱 UI에 맞게 자유롭게 디자인할 수 있지만, 아래의 **4가지 필수 요소는 반드시 포함**해야 합니다. 이는 사용자가 광고임을 명확히 인지하도록 하고, 광고주가 기대하는 최소한의 광고 효과를 보장하기 위한 광고 정책입니다.

  1. 광고 표기 : 사용자가 광고임을 명확히 인지할 수 있도록 광고 영역에 "AD", "광고" 등의 표기를 추가해 주세요.
  2. AdChoices 아이콘 : AdChoices 아이콘은 사용자가 광고를 식별하고 제어할 수 있도록 제공되는 아이콘으로, 일반적으로 'ⓘ' 모양으로 표시됩니다. 해당 아이콘은 DARO SDK에서 자동으로 삽입되므로 별도 구현은 필요하지 않습니다. 광고 뷰의 4개 모서리(좌상단/우상단/우하단/좌하단) 중 한 곳에 배치되며, 기본 위치는 우하단입니다. Manual Implementation(XML)에서는 `DaroNativeAdBinder.Builder.setAdChoicePlacement()`로 원하는 모서리를 선택할 수 있으니 (자세한 내용은 아래 [AdChoices 표시 위치](#adchoices-표시-위치) 섹션 참고), 해당 위치가 다른 UI 요소와 겹치거나 가려지지 않도록 광고 뷰를 구성해 주세요. 광고 디맨드에 따라 아이콘의 형태나 동작이 다를 수 있습니다.
  3. 광고 제목 (타이틀) : 광고의 제목을 표시해야 합니다.
  4. 클릭 유도 문안(CTA) : "설치", "열기", "다운로드" 등의 CTA(Call to Action) 버튼을 반드시 포함해 주세요. 버튼의 크기나 형태는 자유롭게 구성할 수 있으며, 상황에 따라 텍스트 필드로 대체 가능합니다. 광고 디맨드에서 CTA 문구를 제공하므로, 특정 문구를 고정할 필요는 없습니다.
</Info>

***

## 광고 연동하기

[시작하기](/ko/sdk-integration-v2/android/get-started)에 따라 SDK를 먼저 초기화하세요. 아래 예제의 `YOUR_AD_UNIT_ID`를 대시보드에서 확인한 해당 포맷의 Ad Unit Key로 바꾸세요.

<Tabs>
  <Tab title="Xml">
    <Steps>
      <Step title="adBinder 생성">
        * native 광고를 render하는데 필요한 adBinder를 생성합니다.

        <Tabs>
          <Tab title="Manual implementation(xml)">
            <CodeGroup>
              ```kotlin xml theme={null}
              val adBinder = DaroNativeAdBinder.Builder(context, ${layoutId})
                .setIconViewId(${iconViewId})
                .setBodyTextViewId(${bodyViewId})
                .setCallToActionViewId(${callToActionViewId})
                .setMediaViewGroupId(${mediaViewGroupId})
                .setTitleViewId(${titleViewId})
                .setAdChoicePlacement(DaroNativeAdChoicePlacement.BOTTOM_RIGHT) // optional, 기본값 BOTTOM_RIGHT
                .build()
              ```

              ```kotlin programmatic theme={null}
              val view = View()

              val adBinder = DaroNativeAdBinder.Builder(view)
                .setIconViewId(${iconViewId})
                .setBodyTextViewId(${bodyViewId})
                .setCallToActionViewId(${callToActionViewId})
                .setMediaViewGroupId(${mediaViewGroupId})
                .setTitleViewId(${titleViewId})
                .build()
              ```
            </CodeGroup>

            <Expandable title="Example">
              <img src="https://mintcdn.com/delightroom-5a71a6a8/zubkjN5vMaM7lt41/sdk-integration/android/ad-formats/img/native-banner-example.png?fit=max&auto=format&n=zubkjN5vMaM7lt41&q=85&s=a178e2c367e51b7a032ee3ce384965aa" alt="template-line" width="80%" data-path="sdk-integration/android/ad-formats/img/native-banner-example.png" />

              ```xml layout_native.xml expandable theme={null}
              <?xml version="1.0" encoding="utf-8"?>
              <androidx.constraintlayout.widget.ConstraintLayout
                xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingStart="24dp"
                android:paddingTop="16dp"
                android:paddingEnd="24dp"
                android:paddingBottom="12dp">

                <ImageView
                  android:id="@+id/view_icon"
                  android:layout_width="48dp"
                  android:layout_height="48dp"
                  android:layout_marginEnd="8dp"
                  app:layout_constraintBottom_toBottomOf="@id/view_body"
                  app:layout_constraintEnd_toStartOf="@id/view_title"
                  app:layout_constraintStart_toStartOf="parent"
                  app:layout_constraintTop_toTopOf="@id/view_title" />

                <TextView
                  android:id="@+id/view_title"
                  android:layout_width="0dp"
                  android:layout_height="wrap_content"
                  android:ellipsize="end"
                  android:maxLines="1"
                  app:layout_constraintEnd_toEndOf="parent"
                  app:layout_constraintStart_toEndOf="@id/view_icon"
                  app:layout_constraintTop_toTopOf="parent"
                  tools:text="Title은 최대 1줄까지입니다." />

                <TextView
                  android:id="@+id/view_body"
                  android:layout_width="0dp"
                  android:layout_height="wrap_content"
                  android:layout_marginTop="4dp"
                  android:ellipsize="end"
                  android:lines="2"
                  app:layout_constraintEnd_toEndOf="parent"
                  app:layout_constraintStart_toStartOf="@id/view_title"
                  app:layout_constraintTop_toBottomOf="@id/view_title"
                  tools:text="설명도 2줄까지만 노출합니다. 2줄 넘을.." />

                <TextView
                  android:id="@+id/button_cta"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:gravity="center"
                  android:paddingStart="8dp"
                  android:paddingTop="4dp"
                  android:paddingEnd="8dp"
                  android:paddingBottom="4dp"
                  app:layout_constraintBottom_toTopOf="@+id/view_media"
                  app:layout_constraintEnd_toEndOf="parent"
                  tools:text="Open" />

                <FrameLayout
                  android:id="@+id/view_media"
                  android:layout_width="match_parent"
                  android:layout_height="100dp"
                  android:layout_marginTop="20dp"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintTop_toBottomOf="@id/view_body" />
              </androidx.constraintlayout.widget.ConstraintLayout>
              ```

              앱에 추가한 `layout_native.xml`과 뷰 ID를 참조하도록 앱 모듈의 `R`을 사용하세요.

              ```kotlin MainActivity.kt theme={null}
              val adBinder = DaroNativeAdBinder.Builder(this, R.layout.layout_native)
                .setIconViewId(R.id.view_icon)
                .setBodyTextViewId(R.id.view_body)
                .setCallToActionViewId(R.id.button_cta)
                .setMediaViewGroupId(R.id.view_media)
                .setTitleViewId(R.id.view_title)
                .build()
              ```
            </Expandable>
          </Tab>

          <Tab title="Use Template">
            ```kotlin theme={null}
            val adBinder = DaroNativeAdBinder.fromTemplate(
                context,
                DaroNativeAdTemplate.Banner(
                  ...
                )
              )
            ```
          </Tab>
        </Tabs>
      </Step>

      <Step title="adUnit 생성">
        ```kotlin theme={null}
          val adUnit = DaroNativeAdUnit(
            key = "YOUR_AD_UNIT_ID",
          )
        ```
      </Step>

      <Step title="adView 생성 및 뷰에 추가">
        ```kotlin theme={null}
        val adView = DaroNativeAdView(
          context = context,
          adUnit = adUnit
        )

        binding.adViewContainer.addView(adView)
        ```
      </Step>

      <Step title="adView 뷰에 adBinder 설정">
        ```kotlin theme={null}
        adView.setAdBinder(adBinder)
        ```
      </Step>

      <Step title="리스너 설정">
        ```kotlin theme={null}
        adView.setListener(object : DaroAdViewListener {
          override fun onAdImpression(adInfo: DaroAdInfo) {}
          override fun onAdClicked(adInfo: DaroAdInfo) {}
          override fun onAdLoadSuccess(ad: DaroViewAd, adInfo: DaroAdInfo) {}
          override fun onAdLoadFail(err: DaroError) {}
        })
        ```
      </Step>

      <Step title="광고 로드">
        ```kotlin theme={null}
        adView.loadAd()
        ```

        <Warning>
          `loadAd()` 호출 전에 반드시 `adBinder`를 설정해야 합니다.
        </Warning>
      </Step>
    </Steps>

    <Tip>
      * 뷰를 선언하면 자체적으로 화면에 맞는 라이프사이클을 찾아 동작을 관리합니다. 따로 `resume`, `pause`, `destroy`를 호출하지 않아도 됩니다.
      * `autoDetectLifecycle` 값을 false(default: true)로 설정하는 경우, `resume`, `pause`, `destroy`를 직접 호출해주셔야 합니다.
    </Tip>
  </Tab>

  <Tab title="Compose">
    * `DaroNative`는 `daro-sdk`에서 제공합니다. 별도의 `daro-compose-util` 의존성은 필요하지 않습니다.
    * Compose 환경과 기존 의존성 전환 방법은 [시작하기](/ko/sdk-integration-v2/android/get-started)에서 확인하세요.

    <CodeGroup>
      ```kotlin Manual implementation(Compose) theme={null}
      DaroNative(
        adUnit = DaroNativeAdUnit(
          key = "YOUR_AD_UNIT_ID",
        ),
        listener = object : DaroAdViewListener {
          override fun onAdImpression(adInfo: DaroAdInfo) {}
          override fun onAdClicked(adInfo: DaroAdInfo) {}
          override fun onAdLoadSuccess(ad: DaroViewAd, adInfo: DaroAdInfo) {}
          override fun onAdLoadFail(err: DaroError) {}
        },
        modifier = Modifier
      ) {
        DaroNativeAdTitle { title -> Text(title) } // for title
        DaroNativeAdBody { body -> Text(body) } // for body
        DaroNativeCallToAction { callToAction -> Text(callToAction) } // for callToAction
        DaroNativeIcon(modifier = Modifier.size(40.dp)) // for ImageView
        DaroNativeMedia(modifier = Modifier.size(100.dp)) // for MedaiView
      }
      ```

      ```kotlin Use Template theme={null}
      DaroNative(
        adUnit = DaroNativeAdUnit(
          key = "YOUR_AD_UNIT_ID",
        ),
        modifier = Modifier,
        listener = object : DaroAdViewListener {
          override fun onAdImpression(adInfo: DaroAdInfo) {}
          override fun onAdClicked(adInfo: DaroAdInfo) {}
          override fun onAdLoadSuccess(ad: DaroViewAd, adInfo: DaroAdInfo) {}
          override fun onAdLoadFail(err: DaroError) {}
        },
        template = DaroNativeAdTemplate.Line(
          ...
        )
      )
      ```
    </CodeGroup>
  </Tab>
</Tabs>

***

## AdChoices 표시 위치

* `DaroNativeAdBinder.Builder.setAdChoicePlacement()`로 AdChoices 아이콘 위치를 지정할 수 있습니다.
* 기본값으로 우하단(`BOTTOM_RIGHT`) 이 사용됩니다.
* 지원 값: `TOP_LEFT`, `TOP_RIGHT`, `BOTTOM_LEFT`, `BOTTOM_RIGHT`.

Manual Implementation(XML)에서 원하는 위치를 설정할 수 있습니다. Template은 기본 위치를 사용합니다.

<Note>
  실제 광고에 따라 아이콘 위치가 다르게 표시될 수 있습니다. 광고 표시가 다른 UI 요소에 가려지지 않도록 네 모서리에 충분한 여백을 확보하세요.
</Note>

***

## Template

* DARO SDK에서는 다음과 같은 template을 제공합니다.

<Expandable title="Line">
  <img src="https://mintcdn.com/delightroom-5a71a6a8/zubkjN5vMaM7lt41/sdk-integration/android/ad-formats/img/native-template-line.png?fit=max&auto=format&n=zubkjN5vMaM7lt41&q=85&s=cd5d01cad05270bb33463ddd1c519a6d" alt="template-line" width="80%" data-path="sdk-integration/android/ad-formats/img/native-template-line.png" />

  <ResponseField name="backgroundColor" type="Int">
    전체 배경색
  </ResponseField>

  <ResponseField name="contentColor" type="Int">
    콘텐츠 텍스트 색상
  </ResponseField>

  <ResponseField name="adMarkLabelBackgroundColor" type="Int">
    광고 마크 배경색
  </ResponseField>

  <ResponseField name="adMarkLabelTextColor" type="Int">
    광고 마크 텍스트 색상
  </ResponseField>
</Expandable>

<Expandable title="LineCenter">
  <img src="https://mintcdn.com/delightroom-5a71a6a8/zubkjN5vMaM7lt41/sdk-integration/android/ad-formats/img/native-template-line-center.png?fit=max&auto=format&n=zubkjN5vMaM7lt41&q=85&s=9896214d551b78c8a63612585d40fbae" alt="template-line" width="80%" data-path="sdk-integration/android/ad-formats/img/native-template-line-center.png" />

  <ResponseField name="backgroundColor" type="Int">
    전체 배경색
  </ResponseField>

  <ResponseField name="contentColor" type="Int">
    콘텐츠 텍스트 색상
  </ResponseField>

  <ResponseField name="adMarkLabelBackgroundColor" type="Int">
    광고 마크 배경색
  </ResponseField>

  <ResponseField name="adMarkLabelTextColor" type="Int">
    광고 마크 텍스트 색상
  </ResponseField>
</Expandable>

<Expandable title="Banner">
  <img src="https://mintcdn.com/delightroom-5a71a6a8/zubkjN5vMaM7lt41/sdk-integration/android/ad-formats/img/native-template-banner.png?fit=max&auto=format&n=zubkjN5vMaM7lt41&q=85&s=a6f1f5de901d65fb65265a85b9219918" alt="template-line" width="80%" data-path="sdk-integration/android/ad-formats/img/native-template-banner.png" />

  <ResponseField name="backgroundColor" type="Int">
    전체 배경색
  </ResponseField>

  <ResponseField name="titleColor" type="Int">
    타이틀 텍스트 색상
  </ResponseField>

  <ResponseField name="descriptionColor" type="Int">
    설명 텍스트 색상
  </ResponseField>

  <ResponseField name="ctaBackgroundColor" type="Int">
    CTA(버튼) 배경색
  </ResponseField>

  <ResponseField name="ctaTextColor" type="Int">
    CTA(버튼) 텍스트 색상
  </ResponseField>

  <ResponseField name="adMarkLabelTextColor" type="Int">
    하단 광고 마크 텍스트 색상
  </ResponseField>
</Expandable>

## 광고주명 표시하기

광고주명을 표시하려면 커스텀 네이티브 광고 레이아웃에 `TextView`를 추가하고, `DaroNativeAdBinder.Builder`에서 `.setAdvertiserViewId(R.id.view_advertiser)`로 연결하세요. `R.id.view_advertiser`는 앱 레이아웃에 선언한 뷰 ID로 바꾸세요. 광고주명이 없는 광고는 SDK가 해당 뷰를 숨깁니다. 기존 연동에서 이 뷰를 추가할 필요는 없습니다.

## 에셋 수신 여부로 UI 분기하기

* `DaroAdLoadListener`의 `onNativeAdAssetLoaded`를 override 하여 특정 에셋이 존재하지 않을 경우를 대응할 수 있습니다.

| 값 | 의미 |
| - | - |
| `TITLE` | 광고 제목 |
| `BODY` | 광고 본문 |
| `ICON` | 광고 아이콘 |
| `MEDIA` | 광고 이미지 또는 동영상 |
| `CALL_TO_ACTION` | 행동 유도 버튼 문구 ( 예: 설치하기 ) |
| `ADVERTISER` | 광고주명 (광고에서 제공하는 경우) |

```kotlin theme={null}
import android.view.View
import droom.daro.core.model.NativeAdAssetType

override fun onNativeAdAssetLoaded(assetTypes: Set<NativeAdAssetType>) {
    mediaContainer.visibility =
        if (assetTypes.contains(NativeAdAssetType.MEDIA)) View.VISIBLE else View.GONE
    iconView.visibility =
        if (assetTypes.contains(NativeAdAssetType.ICON)) View.VISIBLE else View.GONE
}
```

* AD 표시와 AdChoices는 이 에셋 목록을 근거로 숨기지 마세요.
