# Native Ad

## 1. 기본 요건

* [ADX Android SDK](/adx/android/integrate.md#2-adx-android-sdk)를 프로젝트에 추가합니다.
* Native Ad용으로 발급받은 Ad Unit ID를 사용합니다.
* 광고를 요청하기 전에 [SDK 초기화](/adx/android/sdk-integration/initialize.md)를 먼저 진행합니다.
  * **SDK 초기화는 앱 실행 시 한 번만 호출**하여 주시고, **광고 요청은 초기화가 완료된 후**에 이뤄져야 합니다.

## 2. 레이아웃 설정

Native Ad의 경우, 광고에 사용 될 레이아웃을 직접 구성해야 합니다. 필수 구성 요소들은 다음과 같습니다.

* **Title** : `TextView`
* **Main Text** : `TextView`
* **Call-To-Action** : `Button`
* **Icon Image** : `ImageView`
* **Main Image** : `FrameLayout`
* **Privacy Icon** : `FrameLayout`
* **Ad Tag** : `TextView 또는 ImageView`

{% hint style="info" %}
Ad Tag 요소는 "**Ad**" 또는 "**Advertisement**" 문자열을 보여주는 UI 구성 요소를 포함하여, 광고라는 것을 명확하게 사용자에게 인식을 시켜야 합니다. 이 요소가 포함되지 않으면, 일부 광고 네트워크의 광고 송출이 중단될 수 있습니다.
{% endhint %}

이 요소들은 반드시 포함하여 구성하여 주시고, 광고 컨텐츠를 덮는 Layer가 없어야 합니다. 또한 텍스트 변경, 이미지 변경, 터치 시 액션 변경 등 광고 컨텐츠에 관련된 부분을 가공하거나 변경하지 않도록 주의 부탁드립니다.

샘플 소스의 [layout\_adx\_native\_ad.xml](https://github.com/adxcorp/ADXLibrary_Sample_Android_v2/blob/master/app/src/main/res/layout/layout_adx_native_ad.xml)을 참조하실 수 있습니다.

## 3. 구현

Native Ad는 다음 3가지 방법 중 하나로 광고를 로드할 수 있습니다.

### Case 1: 하나의 View로 사용하는 경우

#### MainActivity

{% tabs %}
{% tab title="Java" %}

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    AdxNativeAdFactory.init(this);

    // for Native Ad
    AdxNativeAdFactory.setAdxViewBinder("<NATIVE_AD_UNIT_ID>"), 
                            new AdxViewBinder.Builder(R.layout.layout_media_native_ad)
                .mediaViewContainerId(R.id.mediaContainerId)
                .iconImageId(R.id.adIconId)
                .titleId(R.id.titleId)
                .adChoiceContainerId(R.id.adChoicesContainerId)
                .callToActionId(R.id.callToActionId)
                .build());
            
    AdxNativeAdFactory.preloadAd("<NATIVE_AD_UNIT_ID>");
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_native_ad_factory)

    AdxNativeAdFactory.init(this)

    AdxNativeAdFactory.setAdxViewBinder("<NATIVE_AD_UNIT_ID>", 
            AdxViewBinder.Builder(R.layout.layout_media_native_ad)
            .mediaViewContainerId(R.id.mediaContainerId)
            .iconImageId(R.id.adIconId)
            .titleId(R.id.titleId)
            .adChoiceContainerId(R.id.adChoicesContainerId)
            .callToActionId(R.id.callToActionId)
            .build()
            
    AdxNativeAdFactory.preloadAd("<NATIVE_AD_UNIT_ID>")
}
```

{% endtab %}
{% endtabs %}

#### Activity (or Fragment)

{% tabs %}
{% tab title="Java" %}

```java
private View mAdView;
private com.adxcorp.ads.nativeads.NativeAd mNativeAd;
    
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_native_ad_factory);
    
    AdxNativeAdFactory.addListener(mListener);
    AdxNativeAdFactory.loadAd("<NATIVE_AD_UNIT_ID>");
}
    
@Override
protected void onDestroy() {
    AdxNativeAdFactory.removeListener(mListener);
    
    if(mNativeAd != null) {
        mNativeAd.destroy();
        mNativeAd = null;
    }
    
    super.onDestroy();
}

private final AdxNativeAdFactory.NativeAdListener mListener = new AdxNativeAdFactory.NativeAdListener() {
    @Override
    public void onSuccess(String s, com.adxcorp.ads.nativeads.NativeAd nativeAd) {
        
        if ("<NATIVE_AD_UNIT_ID>".equals(s)) {
            mNativeAd = nativeAd;
            mAdView = AdxNativeAdFactory.getNativeAdView(
                    NativeAdFactoryActivity.this,
                    s,
                    mContentView,
                    new com.adxcorp.ads.nativeads.NativeAd.NativeEventListener() {
                        @Override
                        public void onImpression(View view) {
                        }

                        @Override
                        public void onClick(View view) {
                        }
                    });
            mContentView.addView(mAdView);
        }
    }

    @Override
    public void onFailure(String s) {
    }
};
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
private var mAdView: View? = null
private var mNativeAd: NativeAd? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_native_ad_factory)

    AdxNativeAdFactory.addListener(mListener)
    AdxNativeAdFactory.loadAd("<NATIVE_AD_UNIT_ID>")
}

override fun onDestroy() {
    super.onDestroy()

    AdxNativeAdFactory.removeListener(mListener)

    mNativeAd?.destroy()
    mNativeAd = null
}

private val mListener: AdxNativeAdFactory.NativeAdListener = object : AdxNativeAdFactory.NativeAdListener {
    override fun onSuccess(s: String, nativeAd: NativeAd) {
        if ("<NATIVE_AD_UNIT_ID>" == s) {
            mNativeAd = nativeAd
            mAdView = AdxNativeAdFactory.getNativeAdView(
                this@NativeAdFactoryActivity,
                s,
                mContentView,
                object : NativeAd.NativeEventListener {
                    override fun onImpression(view: View) {
                    }

                    override fun onClick(view: View) {
                    }
                })
            mContentView?.addView(mAdView)
        }
    }

    override fun onFailure(s: String) {
    }
}
```

{% endtab %}
{% endtabs %}

### Case 2: RecyclerView를 사용하는 경우

#### MainActivity

{% tabs %}
{% tab title="Java" %}

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    AdxNativeAdFactory.init(this);

    // for Native Ad
    AdxNativeAdFactory.setAdxViewBinder("<NATIVE_AD_UNIT_ID>"), 
                            new AdxViewBinder.Builder(R.layout.layout_media_native_ad)
                .mediaViewContainerId(R.id.mediaContainerId)
                .iconImageId(R.id.adIconId)
                .titleId(R.id.titleId)
                .adChoiceContainerId(R.id.adChoicesContainerId)
                .callToActionId(R.id.callToActionId)
                .build());
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_native_ad_factory)

    AdxNativeAdFactory.init(this)

    AdxNativeAdFactory.setAdxViewBinder("<NATIVE_AD_UNIT_ID>", 
            AdxViewBinder.Builder(R.layout.layout_media_native_ad)
            .mediaViewContainerId(R.id.mediaContainerId)
            .iconImageId(R.id.adIconId)
            .titleId(R.id.titleId)
            .adChoiceContainerId(R.id.adChoicesContainerId)
            .callToActionId(R.id.callToActionId)
            .build()
}
```

{% endtab %}
{% endtabs %}

#### Acivity (or Fragment)

리스트에서 광고 고정 위치와 반복 위치를 소스 코드에 직접 지정해야 합니다.

{% tabs %}
{% tab title="Java" %}

```java
private AdxRecyclerAdapter mRecyclerAdapter;
private RecyclerView mRecyclerView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_native_ad_recyclerview);

    mRecyclerView = (RecyclerView) findViewById(R.id.native_recycler_view);

    final RecyclerView.Adapter originalAdapter = new DemoRecyclerAdapter();

    // 광고 고정 및 반복 위치 지정  
    NativeAdPosition.ClientPosition clientPosition = new NativeAdPosition.ClientPosition();
    clientPosition.addFixedPosition(2);
    clientPosition.enableRepeatingPositions(5);

    mRecyclerAdapter = AdxNativeAdFactory.getAdxRecyclerAdapter(this, originalAdapter, "<Insert_ADX_AdUnitId>", clientPosition);

    mRecyclerView.setAdapter(mRecyclerAdapter);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mRecyclerAdapter.loadAds("<NATIVE_AD_UNIT_ID>");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mRecyclerAdapter.destroy();
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
private var mRecyclerAdapter: AdxRecyclerAdapter? = null
private var mRecyclerView: RecyclerView? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_native_ad_recyclerview)

    mRecyclerView = findViewById<View>(R.id.native_recycler_view) as RecyclerView

    val originalAdapter: RecyclerView.Adapter<*> = DemoRecyclerAdapter()

    // 광고 고정 및 반복 위치 지정
    val clientPosition = NativeAdPosition.ClientPosition()
    clientPosition.addFixedPosition(2)
    clientPosition.enableRepeatingPositions(5)

    mRecyclerAdapter = AdxNativeAdFactory.getAdxRecyclerAdapter(this, originalAdapter, "<Insert_ADX_AdUnitId>", clientPosition)
    mRecyclerView?.adapter = mRecyclerAdapter
    mRecyclerView?.layoutManager = LinearLayoutManager(this)

    mRecyclerAdapter?.loadAds("<Insert_ADX_AdUnitId>")
}

override fun onDestroy() {
    super.onDestroy()

    mRecyclerAdapter?.destroy()
}

```

{% endtab %}
{% endtabs %}

### Case 3: Closed Native Ad 사용 시

담당 매니저와 협의 후, Close Native Ad 용으로 발급 된 AdUnit ID를 사용하여 아래와 같이 구현합니다.

{% tabs %}
{% tab title="Java" %}

```java
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_app_wall);

    AdxCloseAdFactory.init(this, "<NATIVE_AD_UNIT_ID>", "Exit Message");
    AdxCloseAdFactory.preloadAd();
}

@Override
public void onBackPressed() {
    AdxCloseAdFactory.showCloseAd(this, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            finish();
        }
    }, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
        }
    });
}

@Override
protected void onDestroy() {
    AdxCloseAdFactory.destroy();

    super.onDestroy();
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    AdxCloseAdFactory.init(this, "<NATIVE_AD_UNIT_ID>", "Exit Message")
    AdxCloseAdFactory.preloadAd()
}

override fun onBackPressed() {
    AdxCloseAdFactory.showCloseAd(this, { _, _ ->
        finish()
    }) {}
}

override fun onDestroy() {
    AdxCloseAdFactory.destroy()

    super.onDestroy()
}
```

{% endtab %}
{% endtabs %}

## 4. Ad Revenue (OnPaidEvent)

* 광고 노출이 발생동안 예상되는 광고 수익을 받아볼 수 있습니다.
* 이는 미디에이션 설정 과정에서 수동적으로 설정한 값과 정확한 값이 섞여 있어서 예상 값으로 사용하시는 것을 권장드립니다.
* ecpm의 currency는 **USD**입니다.
* 아래와 같이 <mark style="color:red;">`OnPaidEvent`</mark> 콜백을 등록하여 사용하시면 됩니다.
* 광고 매출 데이터를 MMP와 연동할 수 있습니다. 자세한 사항은 아래 SDK 연동 가이드를 참조해 주십시오.
  * [애드저스트(Adjust)의 AD(X) SDK 연동 가이드](https://dev.adjust.com/ko/sdk/android/integrations/adx)
  * [에어브릿지(Airbridge)의 AD(X) SDK 연동 가이드](https://help.airbridge.io/ko/developers/ad-x-ad-revenue-integration#sdk-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0-android)
* [#case-1-view](#case-1-view "mention")에만 지원됩니다.

{% tabs %}
{% tab title="Java" %}

```java
private final AdxNativeAdFactory.NativeAdListener mListener = new AdxNativeAdFactory.NativeAdListener() {
    @Override
    public void onSuccess(String s, com.adxcorp.ads.nativeads.NativeAd nativeAd) {

        if (mAdxUnitId.equals(s)) {
            mNativeAd = nativeAd;
            mNativeAd.setOnPaidEventListener(new OnPaidEventListener() {
                @Override
                public void onPaidEvent(double ecpm) {
                    /// Firebase Analytics 샘플
                    double revenue = ecpm / 1000;
                    
                    mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
                    Bundle params = new Bundle();
                    params.putString(FirebaseAnalytics.Param.AD_PLATFORM, "AD(X)");
                    params.putString(FirebaseAnalytics.Param.AD_FORMAT, "NativeAd");
                    params.putString(FirebaseAnalytics.Param.AD_UNIT_NAME, "ADX Native Ad");
                    params.putDouble(FirebaseAnalytics.Param.VALUE, revenue);
                    params.putString(FirebaseAnalytics.Param.CURRENCY, "USD");
                    mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.AD_IMPRESSION, params);
                    
                    /// AppsFlyer 샘플
                    double revenue = ecpm / 1000;
                    
                    Map<String, String> customParams = new HashMap<>();
                    customParams.put(Scheme.AD_TYPE, "NativeAd");
                    customParams.put("ad_unit_name", "ADX Native Ad");
                    
                    AppsFlyerAdRevenue.logAdRevenue(
                          "AD(X)",
                          MediationNetwork.customMediation,
                          Currency.getInstance(Locale.US),
                          revenue,
                          customParams
                    );
                }
            });
        }
    }

    @Override
    public void onFailure(String s) {
    }
};
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
private val mListener: AdxNativeAdFactory.NativeAdListener = object : AdxNativeAdFactory.NativeAdListener {
    override fun onSuccess(s: String, nativeAd: NativeAd) {
	    mNativeAd = nativeAd
	    mNativeAd.setOnPaidEventListener(object : OnPaidEventListener() {
		    fun onPaidEvent(ecpm: Double) {
		        /// Firebase Analytics 샘플
		        val revenue: Double = ecpm / 1000
		
		        firebaseAnalytics = Firebase.analytics
		        firebaseAnalytics.logEvent(FirebaseAnalytics.Event.AD_IMPRESSION) {
		            param(FirebaseAnalytics.Param.AD_PLATFORM, "AD(X)")
		            param(FirebaseAnalytics.Param.AD_UNIT_NAME, "ADX Native Ad")
		            param(FirebaseAnalytics.Param.AD_FORMAT, "NativeAd")
		            param(FirebaseAnalytics.Param.VALUE, revenue)
		            param(FirebaseAnalytics.Param.CURRENCY, "USD")
		        }
		        
		        // AppsFlyer 샘플
		        val revenue: Double = ecpm / 1000
		
		        val customParams: MutableMap<String, String> = HashMap()
		        customParams[Scheme.AD_TYPE] = "NativeAd"
		        customParams["ad_unit_name"] = "ADX Native Ad"
		        
		        AppsFlyerAdRevenue.logAdRevenue(
		            "AD(X)",
		            MediationNetwork.customMediation,
		            Currency.getInstance(Locale.US),
		            revenue,
		            customParams
		        )
		    }
		})
    }

    override fun onFailure(s: String) {
    }
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://platform-business.gitbook.io/adx/android/sdk-integration/ad-formats/native-ad.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
