메인 콘텐츠로 건너뛰기

개요

배너 광고는 화면의 일부 영역에 표시되는 직사각형 광고입니다. XML 레이아웃과 코드 모두에서 사용할 수 있습니다.

주요 특징

  • 화면 상단, 하단 또는 중간에 고정 배치 가능
  • 이미지 및 동영상 광고 지원
  • XML 레이아웃 및 프로그래밍 방식 모두 지원
  • 리스너를 통한 광고 이벤트 처리
개발 환경에서는 테스트 유닛 ID를 사용하세요: PUBLIC_TEST_UNIT_ID_320_100

XML 레이아웃 구현

XML 레이아웃에서 AdropBanner를 정의하고 Activity나 Fragment에서 로드하는 방식입니다.

1. XML 레이아웃 정의

FrameLayout 또는 다른 컨테이너에 AdropBanner를 배치합니다.
activity_main.xml
<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 메인 콘텐츠 -->
    <TextView
        android:id="@+id/content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="메인 콘텐츠"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <!-- 배너 광고 컨테이너 -->
    <FrameLayout
        android:id="@+id/banner_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <io.adrop.ads.banner.AdropBanner
            android:id="@+id/adrop_banner"
            android:layout_width="320dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            app:adrop_unit_id="YOUR_UNIT_ID" />

    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

2. Activity에서 로드

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.adrop.ads.banner.AdropBanner
import io.adrop.ads.banner.AdropBannerListener
import io.adrop.ads.model.AdropErrorCode

class MainActivity : AppCompatActivity() {
    private var banner: AdropBanner? = null

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

        // 1. XML에서 정의한 배너 뷰 찾기
        banner = findViewById(R.id.adrop_banner)

        // 2. 리스너 설정
        banner?.listener = object : AdropBannerListener {
            override fun onAdReceived(banner: AdropBanner) {
                println("배너 광고 수신 성공")
            }

            override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
                println("배너 광고 수신 실패: $errorCode")
            }

            override fun onAdImpression(banner: AdropBanner) {
                println("배너 광고 노출")
            }

            override fun onAdClicked(banner: AdropBanner) {
                println("배너 광고 클릭")
            }
        }

        // 3. 광고 로드
        banner?.load()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 4. 메모리 해제
        banner?.destroy()
        banner = null
    }
}

XML 속성

속성설명필수
app:adrop_unit_id광고 유닛 IDO
android:layout_width배너 너비 (dp)O
android:layout_height배너 높이 (dp)O

프로그래밍 방식 구현

코드에서 직접 AdropBanner 인스턴스를 생성하여 뷰에 추가하는 방식입니다.
import android.os.Bundle
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import io.adrop.ads.banner.AdropBanner
import io.adrop.ads.banner.AdropBannerListener
import io.adrop.ads.model.AdropErrorCode

class MainActivity : AppCompatActivity() {
    private var banner: AdropBanner? = null

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

        // 1. 배너 인스턴스 생성
        banner = AdropBanner(this).apply {
            unitId = "YOUR_UNIT_ID"

            // 2. 리스너 설정
            listener = object : AdropBannerListener {
                override fun onAdReceived(banner: AdropBanner) {
                    println("배너 광고 수신 성공")
                }

                override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
                    println("배너 광고 수신 실패: $errorCode")
                }

                override fun onAdImpression(banner: AdropBanner) {
                    println("배너 광고 노출")
                }

                override fun onAdClicked(banner: AdropBanner) {
                    println("배너 광고 클릭")
                }
            }
        }

        // 3. 뷰 계층에 추가
        val container = findViewById<FrameLayout>(R.id.banner_container)
        val params = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
        )
        container.addView(banner, params)

        // 4. 광고 로드
        banner?.load()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 5. 메모리 해제
        banner?.destroy()
        banner = null
    }
}

AdropBanner 초기화

생성자

context
Context
required
Activity 또는 Application Context
val banner = AdropBanner(context)

유닛 ID 설정

unitId
String
required
애드컨트롤 콘솔에서 생성한 유닛 ID
banner.unitId = "YOUR_UNIT_ID"

광고 로드

배너를 화면에 추가한 후 load() 메서드를 호출하여 광고를 요청합니다.
banner.load()
배너가 화면에 보이는 시점에 load()를 호출하세요. 화면에 보이지 않는 상태에서 로드하면 노출이 정확하게 측정되지 않을 수 있습니다.

리스너 구현

AdropBannerListener 인터페이스는 광고의 생명주기 이벤트를 처리합니다.

onAdReceived (필수)

광고 수신이 성공했을 때 호출됩니다.
override fun onAdReceived(banner: AdropBanner) {
    println("배너 광고 수신 성공")
    // 광고 로딩 인디케이터 숨김 등의 처리
}

onAdFailedToReceive (필수)

광고 수신이 실패했을 때 호출됩니다.
override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
    println("배너 광고 수신 실패: $errorCode")
    // 에러 처리 및 대체 콘텐츠 표시
}
errorCode
AdropErrorCode
에러 유형을 나타내는 코드. 자세한 내용은 레퍼런스를 참고하세요.

onAdImpression (선택)

광고가 화면에 노출되었을 때 호출됩니다.
override fun onAdImpression(banner: AdropBanner) {
    println("배너 광고 노출")
    // 노출 분석 로깅 등의 처리
}

onAdClicked (선택)

사용자가 광고를 클릭했을 때 호출됩니다.
override fun onAdClicked(banner: AdropBanner) {
    println("배너 광고 클릭")
    // 클릭 분석 로깅 등의 처리
}

Context ID 설정

문맥 타겟팅을 위해 Context ID를 설정할 수 있습니다.
banner.contextId = "article_123"
Context ID는 광고를 로드하기 전에 설정해야 합니다.

생명주기 관리

destroy()

배너를 더 이상 사용하지 않을 때는 반드시 destroy()를 호출하여 리소스를 해제해야 합니다.
override fun onDestroy() {
    super.onDestroy()
    banner?.destroy()
    banner = null
}
destroy()를 호출하지 않으면 메모리 누수가 발생할 수 있습니다.

광고 크기

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

일반적인 배너 크기

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

XML에서 크기 지정

<io.adrop.ads.banner.AdropBanner
    android:id="@+id/adrop_banner"
    android:layout_width="320dp"
    android:layout_height="100dp"
    app:adrop_unit_id="YOUR_UNIT_ID" />

코드에서 크기 지정

val params = FrameLayout.LayoutParams(
    dpToPx(320), // width
    dpToPx(100)   // height
)
container.addView(banner, params)

// dp를 px로 변환하는 유틸리티 함수
fun dpToPx(dp: Int): Int {
    val density = resources.displayMetrics.density
    return (dp * density).toInt()
}

테스트 유닛 ID

개발 및 테스트 시 아래의 테스트 유닛 ID를 사용하세요.
광고 유형테스트 유닛 ID크기
배너 (320x50)PUBLIC_TEST_UNIT_ID_320_50320 x 50
배너 (320x100)PUBLIC_TEST_UNIT_ID_320_100320 x 100
캐러셀 배너PUBLIC_TEST_UNIT_ID_CAROUSEL가변
배너 비디오 (16:9)PUBLIC_TEST_UNIT_ID_BANNER_VIDEO_16_916:9 비율
배너 비디오 (9:16)PUBLIC_TEST_UNIT_ID_BANNER_VIDEO_9_169:16 비율

사용 예시

import io.adrop.ads.AdropUnitId

val banner = AdropBanner(this).apply {
    unitId = AdropUnitId.PUBLIC_TEST_UNIT_ID_320_100
}

베스트 프랙티스

1. 메모리 관리

Activity나 Fragment가 종료될 때 배너를 반드시 해제하세요.
override fun onDestroy() {
    super.onDestroy()
    banner?.destroy()
    banner = null
}

2. 화면 가시성

배너가 화면에 보일 때 광고를 로드하세요.
override fun onResume() {
    super.onResume()
    banner?.load()
}

3. 에러 처리

광고 로드 실패 시 적절한 에러 처리를 구현하세요.
override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
    when (errorCode) {
        AdropErrorCode.ERROR_CODE_NETWORK_ERROR -> {
            println("네트워크 오류: 연결을 확인하세요")
        }
        AdropErrorCode.ERROR_CODE_NO_FILL -> {
            println("노출 가능한 광고 없음")
        }
        else -> {
            println("광고 로드 실패: $errorCode")
        }
    }
}

4. 리사이클러뷰에서 사용

리사이클러뷰에서 배너를 사용할 때는 뷰홀더에서 적절히 관리하세요.
class BannerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    private val banner: AdropBanner = view.findViewById(R.id.adrop_banner)

    fun bind() {
        banner.listener = object : AdropBannerListener {
            // 리스너 구현
        }
        banner.load()
    }

    fun recycle() {
        banner.destroy()
    }
}

// 어댑터에서
override fun onViewRecycled(holder: BannerViewHolder) {
    holder.recycle()
}

전체 예제

Kotlin 예제

import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ProgressBar
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import io.adrop.ads.banner.AdropBanner
import io.adrop.ads.banner.AdropBannerListener
import io.adrop.ads.model.AdropErrorCode

class BannerActivity : AppCompatActivity() {
    private var banner: AdropBanner? = null
    private lateinit var progressBar: ProgressBar

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

        progressBar = findViewById(R.id.progress_bar)
        setupBanner()
    }

    private fun setupBanner() {
        // 1. 배너 인스턴스 생성
        banner = AdropBanner(this).apply {
            unitId = "YOUR_UNIT_ID"

            // Context ID 설정 (선택사항)
            contextId = "article_123"

            // 2. 리스너 설정
            listener = object : AdropBannerListener {
                override fun onAdReceived(banner: AdropBanner) {
                    println("✅ 배너 광고 수신 성공")
                    progressBar.visibility = View.GONE
                }

                override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
                    println("❌ 배너 광고 수신 실패: $errorCode")
                    progressBar.visibility = View.GONE

                    // 에러에 따른 처리
                    when (errorCode) {
                        AdropErrorCode.ERROR_CODE_NETWORK_ERROR -> {
                            showToast("네트워크 연결을 확인하세요")
                        }
                        AdropErrorCode.ERROR_CODE_NO_FILL -> {
                            println("노출 가능한 광고가 없습니다")
                        }
                        else -> {
                            showToast("광고를 불러올 수 없습니다")
                        }
                    }
                }

                override fun onAdImpression(banner: AdropBanner) {
                    println("👁️ 배너 광고 노출")
                }

                override fun onAdClicked(banner: AdropBanner) {
                    println("👆 배너 광고 클릭")
                }
            }
        }

        // 3. 뷰 계층에 추가
        val container = findViewById<FrameLayout>(R.id.banner_container)
        val params = FrameLayout.LayoutParams(
            dpToPx(320),
            dpToPx(100)
        )
        container.addView(banner, params)

        // 4. 광고 로드
        progressBar.visibility = View.VISIBLE
        banner?.load()
    }

    private fun dpToPx(dp: Int): Int {
        val density = resources.displayMetrics.density
        return (dp * density).toInt()
    }

    private fun showToast(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 5. 메모리 해제
        banner?.destroy()
        banner = null
    }
}

Java 예제

import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import io.adrop.ads.banner.AdropBanner;
import io.adrop.ads.banner.AdropBannerListener;
import io.adrop.ads.model.AdropErrorCode;
import org.jetbrains.annotations.NotNull;

public class BannerActivity extends AppCompatActivity {
    private AdropBanner banner;
    private ProgressBar progressBar;

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

        progressBar = findViewById(R.id.progress_bar);
        setupBanner();
    }

    private void setupBanner() {
        // 1. 배너 인스턴스 생성
        banner = new AdropBanner(this);
        banner.setUnitId("YOUR_UNIT_ID");

        // Context ID 설정 (선택사항)
        banner.setContextId("article_123");

        // 2. 리스너 설정
        banner.setListener(new AdropBannerListener() {
            @Override
            public void onAdReceived(@NotNull AdropBanner banner) {
                System.out.println("✅ 배너 광고 수신 성공");
                progressBar.setVisibility(View.GONE);
            }

            @Override
            public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
                System.out.println("❌ 배너 광고 수신 실패: " + errorCode);
                progressBar.setVisibility(View.GONE);

                // 에러에 따른 처리
                if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK_ERROR) {
                    showToast("네트워크 연결을 확인하세요");
                } else if (errorCode == AdropErrorCode.ERROR_CODE_NO_FILL) {
                    System.out.println("노출 가능한 광고가 없습니다");
                } else {
                    showToast("광고를 불러올 수 없습니다");
                }
            }

            @Override
            public void onAdImpression(@NotNull AdropBanner banner) {
                System.out.println("👁️ 배너 광고 노출");
            }

            @Override
            public void onAdClicked(@NotNull AdropBanner banner) {
                System.out.println("👆 배너 광고 클릭");
            }
        });

        // 3. 뷰 계층에 추가
        FrameLayout container = findViewById(R.id.banner_container);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            dpToPx(320),
            dpToPx(100)
        );
        container.addView(banner, params);

        // 4. 광고 로드
        progressBar.setVisibility(View.VISIBLE);
        banner.load();
    }

    private int dpToPx(int dp) {
        float density = getResources().getDisplayMetrics().density;
        return (int) (dp * density);
    }

    private void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 5. 메모리 해제
        if (banner != null) {
            banner.destroy();
            banner = null;
        }
    }
}

XML 레이아웃

activity_banner.xml
<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="배너 광고 예제"
        android:textSize="24sp"
        android:textStyle="bold"
        android:layout_marginTop="32dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <FrameLayout
        android:id="@+id/banner_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

다음 단계