메인 콘텐츠로 건너뛰기

개요

보상형 광고는 사용자가 동영상 광고를 끝까지 시청하면 게임 내 재화, 생명, 힌트 등의 보상을 제공하는 전면 동영상 광고입니다.

주요 특징

  • 전면 화면을 차지하는 동영상 광고
  • 사용자가 광고를 완전히 시청한 경우에만 보상 제공
  • 사용자가 직접 광고 시청을 선택 (예: “동영상 보고 생명 받기” 버튼)
  • 보상 타입과 수량을 설정 가능
개발 환경에서는 테스트 유닛 ID를 사용하세요: PUBLIC_TEST_UNIT_ID_REWARDED

구현 방법

보상형 광고는 다음과 같은 단계로 구현합니다:
  1. AdropRewardedAd 인스턴스 생성 - 유닛 ID로 광고 객체 생성
  2. Listener 설정 - 광고 이벤트 처리를 위한 리스너 지정
  3. 광고 로드 - load() 메서드로 광고 요청
  4. 광고 표시 - show() 메서드로 광고 표시 및 보상 처리

기본 구현

Kotlin 예제

import io.adrop.ads.rewardedAd.AdropRewardedAd
import io.adrop.ads.rewardedAd.AdropRewardedAdListener
import io.adrop.ads.model.AdropErrorCode

class RewardedActivity : AppCompatActivity() {
    private var rewardedAd: AdropRewardedAd? = null

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

        // 1. AdropRewardedAd 인스턴스 생성
        rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")

        // 2. Listener 설정
        rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
            // 필수: 광고 수신 성공
            override fun onAdReceived(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 수신 완료")
                // 광고 시청 버튼 활성화 등
            }

            // 필수: 광고 수신 실패
            override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "광고 수신 실패: $errorCode")
                // 광고 시청 버튼 비활성화 유지 등
            }

            // 선택: 광고 노출
            override fun onAdImpression(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 노출됨")
            }

            // 선택: 광고 클릭
            override fun onAdClicked(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 클릭됨")
            }

            // 선택: 광고 화면 표시 직전
            override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 표시 예정")
                // 배경 음악 일시정지 등
            }

            // 선택: 광고 화면 표시 완료
            override fun onAdDidPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 표시 완료")
            }

            // 선택: 광고 화면 닫기 직전
            override fun onAdWillDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 닫기 예정")
            }

            // 선택: 광고 화면 닫기 완료
            override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 닫힘")
                // 배경 음악 재개 등

                // 다음 광고 미리 로드
                rewardedAd?.load()
            }

            // 선택: 광고 표시 실패
            override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "광고 표시 실패: $errorCode")
            }
        }

        // 3. 광고 로드
        rewardedAd?.load()

        // 광고 시청 버튼 클릭 처리
        findViewById<Button>(R.id.btnShowRewardedAd).setOnClickListener {
            showRewardedAd()
        }
    }

    private fun showRewardedAd() {
        // 광고가 로드되었는지 확인
        if (rewardedAd?.isLoaded != true) {
            Log.d(TAG, "광고가 아직 로드되지 않았습니다")
            return
        }

        // 4. 광고 표시 및 보상 처리
        rewardedAd?.show(this) { type, amount ->
            // 보상 지급 처리
            Log.d(TAG, "보상 획득 - 타입: $type, 수량: $amount")
            grantReward(type, amount)
        }
    }

    private fun grantReward(type: Int, amount: Int) {
        // 사용자에게 보상 지급
        // 예: 게임 재화 추가, 생명 회복 등

        // ⚠️ 중요: 서버에서 보상을 검증하는 것을 권장합니다
        // 클라이언트에서만 보상을 처리하면 부정행위가 가능합니다
    }

    override fun onDestroy() {
        super.onDestroy()
        rewardedAd?.destroy()
        rewardedAd = null
    }

    companion object {
        private const val TAG = "RewardedActivity"
    }
}

Java 예제

import io.adrop.ads.rewardedAd.AdropRewardedAd;
import io.adrop.ads.rewardedAd.AdropRewardedAdListener;
import io.adrop.ads.model.AdropErrorCode;

public class RewardedActivity extends AppCompatActivity {
    private static final String TAG = "RewardedActivity";
    private AdropRewardedAd rewardedAd;

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

        // 1. AdropRewardedAd 인스턴스 생성
        rewardedAd = new AdropRewardedAd(this, "YOUR_UNIT_ID");

        // 2. Listener 설정
        rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
            // 필수: 광고 수신 성공
            @Override
            public void onAdReceived(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 수신 완료");
                // 광고 시청 버튼 활성화 등
            }

            // 필수: 광고 수신 실패
            @Override
            public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                Log.d(TAG, "광고 수신 실패: " + errorCode);
                // 광고 시청 버튼 비활성화 유지 등
            }

            // 선택: 광고 노출
            @Override
            public void onAdImpression(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 노출됨");
            }

            // 선택: 광고 클릭
            @Override
            public void onAdClicked(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 클릭됨");
            }

            // 선택: 광고 화면 표시 직전
            @Override
            public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 화면 표시 예정");
                // 배경 음악 일시정지 등
            }

            // 선택: 광고 화면 표시 완료
            @Override
            public void onAdDidPresentFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 화면 표시 완료");
            }

            // 선택: 광고 화면 닫기 직전
            @Override
            public void onAdWillDismissFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 화면 닫기 예정");
            }

            // 선택: 광고 화면 닫기 완료
            @Override
            public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "광고 화면 닫힘");
                // 배경 음악 재개 등

                // 다음 광고 미리 로드
                rewardedAd.load();
            }

            // 선택: 광고 표시 실패
            @Override
            public void onAdFailedToShowFullScreen(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                Log.d(TAG, "광고 표시 실패: " + errorCode);
            }
        });

        // 3. 광고 로드
        rewardedAd.load();

        // 광고 시청 버튼 클릭 처리
        findViewById(R.id.btnShowRewardedAd).setOnClickListener(v -> showRewardedAd());
    }

    private void showRewardedAd() {
        // 광고가 로드되었는지 확인
        if (!rewardedAd.isLoaded()) {
            Log.d(TAG, "광고가 아직 로드되지 않았습니다");
            return;
        }

        // 4. 광고 표시 및 보상 처리
        rewardedAd.show(this, (type, amount) -> {
            // 보상 지급 처리
            Log.d(TAG, "보상 획득 - 타입: " + type + ", 수량: " + amount);
            grantReward(type, amount);
        });
    }

    private void grantReward(int type, int amount) {
        // 사용자에게 보상 지급
        // 예: 게임 재화 추가, 생명 회복 등

        // ⚠️ 중요: 서버에서 보상을 검증하는 것을 권장합니다
        // 클라이언트에서만 보상을 처리하면 부정행위가 가능합니다
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (rewardedAd != null) {
            rewardedAd.destroy();
            rewardedAd = null;
        }
    }
}

AdropRewardedAd 클래스

생성자

AdropRewardedAd(context: Context, unitId: String)
context
Context
Activity 또는 Application의 Context
unitId
String
애드컨트롤 콘솔에서 발급받은 광고 유닛 ID

속성

unitId
String
광고 유닛 ID (읽기 전용)
isLoaded
Boolean
광고가 로드되어 표시 가능한 상태인지 여부 (읽기 전용)
creativeId
String
로드된 광고의 크리에이티브 ID (읽기 전용)
txId
String
광고 트랜잭션 ID (읽기 전용)
campaignId
String
광고 캠페인 ID (읽기 전용)
isBackfilled
Boolean
백필 광고 여부 (읽기 전용)
rewardedAdListener
AdropRewardedAdListener?
광고 이벤트를 수신할 리스너

메서드

load()
Unit
광고를 요청합니다. 광고 로드 결과는 리스너의 onAdReceived 또는 onAdFailedToReceive로 전달됩니다.
show(activity, userDidEarnRewardHandler)
Unit
광고를 표시합니다.
  • activity: 광고를 표시할 Activity
  • userDidEarnRewardHandler: 보상 지급 콜백 (type: Int, amount: Int) -> Unit
destroy()
Unit
광고 리소스를 해제합니다. Activity의 onDestroy()에서 호출해야 합니다.

AdropRewardedAdListener 인터페이스

필수 메서드

onAdReceived(ad: AdropRewardedAd)
void
광고 수신에 성공했을 때 호출됩니다. 이 시점부터 show() 메서드로 광고를 표시할 수 있습니다.
onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode)
void
광고 수신에 실패했을 때 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

선택 메서드

onAdImpression(ad: AdropRewardedAd)
void
광고가 노출되어 노출 기록이 전송되었을 때 호출됩니다.
onAdClicked(ad: AdropRewardedAd)
void
사용자가 광고를 클릭했을 때 호출됩니다.
onAdWillPresentFullScreen(ad: AdropRewardedAd)
void
광고 화면이 표시되기 직전에 호출됩니다. 배경 음악을 일시정지하는 등의 처리를 할 수 있습니다.
onAdDidPresentFullScreen(ad: AdropRewardedAd)
void
광고 화면이 완전히 표시된 후 호출됩니다.
onAdWillDismissFullScreen(ad: AdropRewardedAd)
void
광고 화면이 닫히기 직전에 호출됩니다.
onAdDidDismissFullScreen(ad: AdropRewardedAd)
void
광고 화면이 완전히 닫힌 후 호출됩니다. 배경 음악을 재개하거나 다음 광고를 미리 로드할 수 있습니다.
onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode)
void
광고 표시에 실패했을 때 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.

보상 처리

보상 콜백

show() 메서드의 userDidEarnRewardHandler 파라미터로 보상 콜백을 전달합니다.
rewardedAd?.show(this) { type, amount ->
    // type: 보상 타입 (Int)
    // amount: 보상 수량 (Int)
    Log.d(TAG, "보상 획득 - 타입: $type, 수량: $amount")
    grantReward(type, amount)
}

보상 타입과 수량

  • type: 애드컨트롤 콘솔에서 설정한 보상 타입 (정수 값)
  • amount: 애드컨트롤 콘솔에서 설정한 보상 수량 (정수 값)

Best Practices

1. 광고 미리 로드하기

사용자 경험을 위해 광고를 미리 로드해두는 것이 좋습니다.
class GameActivity : AppCompatActivity() {
    private var rewardedAd: AdropRewardedAd? = null

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

        // 화면 진입 시 광고 미리 로드
        loadRewardedAd()
    }

    private fun loadRewardedAd() {
        rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")
        rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
            override fun onAdReceived(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 준비 완료")
            }

            override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "광고 로드 실패: $errorCode")
            }

            override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                // 광고가 닫힌 후 다음 광고 미리 로드
                loadRewardedAd()
            }
        }
        rewardedAd?.load()
    }

    private fun showRewardedAd() {
        rewardedAd?.show(this) { type, amount ->
            grantReward(type, amount)
        }
    }
}

2. 광고 준비 상태 확인

광고가 로드되었는지 확인하고 UI를 업데이트합니다.
class GameActivity : AppCompatActivity() {
    private var rewardedAd: AdropRewardedAd? = null
    private var isAdReady = false

    private fun updateButtonState() {
        findViewById<Button>(R.id.btnWatchAd).apply {
            isEnabled = isAdReady
            alpha = if (isAdReady) 1.0f else 0.5f
            text = if (isAdReady) "동영상 보고 생명 받기" else "광고 로딩중..."
        }
    }

    private val adListener = object : AdropRewardedAdListener {
        override fun onAdReceived(ad: AdropRewardedAd) {
            isAdReady = true
            updateButtonState()
        }

        override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
            isAdReady = false
            updateButtonState()
        }

        override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
            isAdReady = false
            updateButtonState()

            // 다음 광고 로드
            rewardedAd?.load()
        }
    }
}

3. 배경 음악 처리

광고 표시 전후로 배경 음악을 적절히 제어합니다.
private val adListener = object : AdropRewardedAdListener {
    override fun onAdReceived(ad: AdropRewardedAd) {
        // 필수 구현
    }

    override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
        // 필수 구현
    }

    override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
        // 광고 표시 직전 배경 음악 일시정지
        AudioManager.pauseBackgroundMusic()
    }

    override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
        // 광고 종료 후 배경 음악 재개
        AudioManager.resumeBackgroundMusic()
    }
}

4. 에러 처리

광고 로드 실패 시 재시도 로직을 구현합니다.
private val adListener = object : AdropRewardedAdListener {
    override fun onAdReceived(ad: AdropRewardedAd) {
        Log.d(TAG, "광고 로드 성공")
    }

    override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
        Log.d(TAG, "광고 로드 실패: $errorCode")

        // 네트워크 에러인 경우 재시도
        if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
            Handler(Looper.getMainLooper()).postDelayed({
                rewardedAd?.load()
            }, 3000)
        }
    }

    override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
        Log.d(TAG, "광고 표시 실패: $errorCode")

        // 사용자에게 알림
        Toast.makeText(
            this@GameActivity,
            "광고를 표시할 수 없습니다. 나중에 다시 시도해주세요.",
            Toast.LENGTH_SHORT
        ).show()
    }
}

5. 생명주기 관리

Activity 종료 시 광고 리소스를 정리합니다.
class GameActivity : AppCompatActivity() {
    private var rewardedAd: AdropRewardedAd? = null

    override fun onDestroy() {
        super.onDestroy()
        rewardedAd?.destroy()
        rewardedAd = null
    }
}

완전한 예제

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import io.adrop.ads.rewardedAd.AdropRewardedAd
import io.adrop.ads.rewardedAd.AdropRewardedAdListener
import io.adrop.ads.model.AdropErrorCode

class GameActivity : AppCompatActivity() {
    private var rewardedAd: AdropRewardedAd? = null
    private var isAdReady = false
    private lateinit var btnWatchAd: Button

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

        btnWatchAd = findViewById(R.id.btnWatchAd)
        btnWatchAd.setOnClickListener {
            showRewardedAd()
        }

        // 광고 미리 로드
        loadRewardedAd()
    }

    private fun loadRewardedAd() {
        rewardedAd = AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED")
        rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
            override fun onAdReceived(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 수신 완료")
                isAdReady = true
                updateButtonState()
            }

            override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "광고 수신 실패: $errorCode")
                isAdReady = false
                updateButtonState()

                // 네트워크 에러인 경우 3초 후 재시도
                if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
                    Handler(Looper.getMainLooper()).postDelayed({
                        rewardedAd?.load()
                    }, 3000)
                }
            }

            override fun onAdImpression(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 노출됨")
            }

            override fun onAdClicked(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 클릭됨")
            }

            override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 표시 예정")
                // 배경 음악 일시정지
                pauseBackgroundMusic()
            }

            override fun onAdDidPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 표시 완료")
            }

            override fun onAdWillDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 닫기 예정")
            }

            override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "광고 화면 닫힘")
                isAdReady = false
                updateButtonState()

                // 배경 음악 재개
                resumeBackgroundMusic()

                // 다음 광고 미리 로드
                loadRewardedAd()
            }

            override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "광고 표시 실패: $errorCode")
                Toast.makeText(
                    this@GameActivity,
                    "광고를 표시할 수 없습니다. 나중에 다시 시도해주세요.",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
        rewardedAd?.load()
    }

    private fun showRewardedAd() {
        if (!isAdReady) {
            Toast.makeText(this, "광고가 아직 로드되지 않았습니다", Toast.LENGTH_SHORT).show()
            return
        }

        rewardedAd?.show(this) { type, amount ->
            Log.d(TAG, "보상 획득 - 타입: $type, 수량: $amount")
            grantReward(type, amount)
        }
    }

    private fun grantReward(type: Int, amount: Int) {
        // 사용자에게 보상 지급
        runOnUiThread {
            Toast.makeText(
                this,
                "보상 획득! 타입: $type, 수량: $amount",
                Toast.LENGTH_LONG
            ).show()
        }

        // 실제 보상 지급 로직 구현
        // 예: 게임 재화 추가, 생명 회복 등
    }

    private fun updateButtonState() {
        btnWatchAd.isEnabled = isAdReady
        btnWatchAd.alpha = if (isAdReady) 1.0f else 0.5f
        btnWatchAd.text = if (isAdReady) "동영상 보고 생명 받기" else "광고 로딩중..."
    }

    private fun pauseBackgroundMusic() {
        // 배경 음악 일시정지 로직
    }

    private fun resumeBackgroundMusic() {
        // 배경 음악 재개 로직
    }

    override fun onDestroy() {
        super.onDestroy()
        rewardedAd?.destroy()
        rewardedAd = null
    }

    companion object {
        private const val TAG = "GameActivity"
    }
}

테스트

테스트 유닛 ID

개발 중에는 항상 테스트 유닛 ID를 사용하세요.
// 개발 환경
val rewardedAd = AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED")

// 프로덕션 환경
val rewardedAd = AdropRewardedAd(this, "YOUR_PRODUCTION_UNIT_ID")
실제 유닛 ID로 테스트하면 무효 트래픽으로 간주되어 계정이 정지될 수 있습니다. 반드시 테스트 유닛 ID를 사용하세요.

환경별 유닛 ID 관리

빌드 타입에 따라 자동으로 유닛 ID를 변경하는 방법입니다.
object AdUnitID {
    val REWARDED: String
        get() = if (BuildConfig.DEBUG) {
            "PUBLIC_TEST_UNIT_ID_REWARDED"
        } else {
            "YOUR_PRODUCTION_UNIT_ID"
        }
}

// 사용
val rewardedAd = AdropRewardedAd(this, AdUnitID.REWARDED)

관련 문서