앱인토스 개발자센터 로고
Skip to content
이 내용이 도움이 되었나요?

Unity 인앱 광고 (AdMob)

Unity 앱인토스 SDK를 사용하면 웹뷰 SDK나 JavaScript 브릿지를 직접 구현하지 않아도,
C# 코드만으로 인앱 광고(AdMob)를 로드하고 표시할 수 있어요.

현재는 전면 광고(Interstitial)보상형 광고(Rewarded) 를 제공해요.


개요

Unity SDK는 내부적으로 다음 작업을 자동으로 처리해요.

  • Unity ↔ WebView ↔ Apps In Toss Web SDK 간 브릿지 구성
  • 광고 로드 / 표시 상태 및 이벤트 전달
  • Web SDK의 Promise 결과를 Unity 콜백 형태로 변환

따라서 JavaScript 코드를 작성하거나 웹뷰 SDK를 직접 다룰 필요 없이, Unity SDK API만 호출하면 됩니다.

csharp
AIT.GoogleAdMobLoadAppsInTossAdMob(...)
AIT.GoogleAdMobShowAppsInTossAdMob(...)

사전 준비

  • Unity 앱인토스 SDK 패키지 설치
  • WebGL 빌드 환경 설정 완료
  • 앱인토스 콘솔에서 AdMob 광고 그룹 생성

테스트용 광고 그룹 ID

테스트 환경에서는 테스트용 광고 그룹 ID를 사용할 수 있어요.

  • 전면형 광고: ait-ad-test-interstitial-id
  • 리워드 광고: ait-ad-test-rewarded-id

인앱 광고는 샌드박스 앱에서 테스트할 수 없어요.
불편하시겠지만 콘솔 내 QR 코드로 테스트를 진행해 주세요.


광고 호출 흐름

인앱 광고는 반드시 아래 순서로 호출해야 해요.

  1. 광고 로드
  2. 광고 표시
  3. (광고 종료 후) 다시 로드

한 번에 하나의 광고만 로드할 수 있어요.

주의하세요

페이지 별로 광고를 미리 로드해 주세요.
광고가 로드되지 않은 상태에서 호출하면 오류가 발생해 fill-rate가 낮아질 수 있어요.


iOS에서 로드가 되지 않나요?
앱 추적 모드가 켜져있을 경우, 광고 로드가 정상적으로 동작하지 않을 수 있어요.
앱 추적 모드를 해제한 뒤 다시 시도해 주세요.


지원 광고 타입

Unity SDK에서는 다음 AdMob 광고 타입을 지원해요.

광고 타입설명
Interstitial화면 전환 시 표시되는 전면 광고
Rewarded광고 시청 후 보상을 지급하는 광고

광고 이벤트 처리

광고 표시 과정에서 아래와 같은 이벤트가 순차적으로 발생할 수 있어요. Unity SDK는 이 이벤트들을 콜백 형태로 전달해요.

이벤트 타입설명
requested광고 표시 요청이 정상적으로 전달됨
show광고 컨텐츠가 화면에 표시됨
impression광고가 실제로 노출됨
clicked사용자가 광고를 클릭함
userEarnedReward보상형 광고 시청 완료 후 보상 지급
dismissed사용자가 광고를 닫음
failedToShow광고를 표시하지 못함

주의사항

  • userEarnedReward 이벤트는 보상형 광고에서만 발생해요.
  • 보상 지급 로직은 userEarnedReward 이벤트 기준으로 처리해주세요.
  • failedToShow 발생 시에는 광고를 다시 로드한 후 재시도해야 해요.

샘플 코드

csharp
using System;
using System.Collections.Generic;
using UnityEngine;
using AppsInToss;

/// <summary>
/// AdMob 광고 테스터 컴포넌트
/// GoogleAdMobLoadAppsInTossAdMob/GoogleAdMobShowAppsInTossAdMob API를 테스트합니다.
/// </summary>
public class AdV2Tester : MonoBehaviour
{
    // 테스트용 광고 ID (CI에서 빌드 시 sed로 치환됨)
    // 문서 참조: https://developers-apps-in-toss.toss.im/bedrock/reference/framework/광고/loadAppsInTossAdMob.html
    private const string TEST_INTERSTITIAL_AD_ID = "ait-ad-test-interstitial-id";
    private const string TEST_REWARDED_AD_ID = "ait-ad-test-rewarded-id";

    // 광고 상태
    private string adStatus = "";
    private bool isAdLoaded = false;
    private string selectedAdType = "interstitial"; // interstitial 또는 rewarded
    private List<string> adEventLog = new List<string>();

    /// <summary>
    /// 마지막 작업 상태 메시지
    /// </summary>
    public string Status => adStatus;

    /// <summary>
    /// AdMob 테스터 UI를 렌더링합니다.
    /// </summary>
    public void DrawUI(
        GUIStyle boxStyle,
        GUIStyle groupHeaderStyle,
        GUIStyle labelStyle,
        GUIStyle buttonStyle,
        GUIStyle textFieldStyle,
        GUIStyle fieldLabelStyle,
        GUIStyle callbackLabelStyle)
    {
        GUILayout.BeginVertical(boxStyle);

        // 섹션 헤더
        GUILayout.Label("AdMob Tester", groupHeaderStyle);
        GUILayout.Label("loadAppsInTossAdMob/showAppsInTossAdMob API를 테스트합니다.", labelStyle);
        GUILayout.Label("Load → Show 순서로 호출해야 합니다.", labelStyle);

        GUILayout.Space(10);

        // 상태 표시
        string loadStatus = isAdLoaded ? "Loaded" : "Not Loaded";
        GUILayout.Label($"Status: {loadStatus}", labelStyle);
        if (!string.IsNullOrEmpty(adStatus))
        {
            GUILayout.Label($"  {adStatus}", callbackLabelStyle);
        }

        // 이벤트 로그 표시 (최근 5개)
        if (adEventLog.Count > 0)
        {
            GUILayout.Label("Event Log:", labelStyle);
            int startIndex = Math.Max(0, adEventLog.Count - 5);
            for (int i = startIndex; i < adEventLog.Count; i++)
            {
                GUILayout.Label($"  {adEventLog[i]}", callbackLabelStyle);
            }
        }

        GUILayout.Space(10);

        // 광고 타입 선택
        GUILayout.Label("Ad Type:", fieldLabelStyle);
        GUILayout.BeginHorizontal();
        if (GUILayout.Button(
            selectedAdType == "interstitial" ? "[Interstitial]" : "Interstitial",
            buttonStyle, GUILayout.Height(36), GUILayout.ExpandWidth(true)))
        {
            selectedAdType = "interstitial";
        }
        if (GUILayout.Button(
            selectedAdType == "rewarded" ? "[Rewarded]" : "Rewarded",
            buttonStyle, GUILayout.Height(36), GUILayout.ExpandWidth(true)))
        {
            selectedAdType = "rewarded";
        }
        GUILayout.EndHorizontal();

        // 현재 선택된 광고 ID 표시
        string currentAdId = selectedAdType == "interstitial" ? TEST_INTERSTITIAL_AD_ID : TEST_REWARDED_AD_ID;
        GUILayout.Label($"Ad ID: {currentAdId}", callbackLabelStyle);

        GUILayout.Space(10);

        // Step 1: 광고 로드
        GUILayout.Label("Step 1: Load Ad", fieldLabelStyle);
        if (GUILayout.Button("loadAppsInTossAdMob(...)", buttonStyle, GUILayout.Height(40)))
        {
            ExecuteLoadAd();
        }

        GUILayout.Space(10);

        // Step 2: 광고 표시
        GUILayout.Label("Step 2: Show Ad", fieldLabelStyle);
        GUI.enabled = isAdLoaded;
        if (GUILayout.Button("showAppsInTossAdMob(...)", buttonStyle, GUILayout.Height(40)))
        {
            ExecuteShowAd();
        }
        GUI.enabled = true;

        if (!isAdLoaded)
        {
            GUILayout.Label("(광고를 먼저 로드해주세요)", callbackLabelStyle);
        }

        GUILayout.Space(10);

        // 로그 초기화
        if (adEventLog.Count > 0)
        {
            if (GUILayout.Button("Clear Log", buttonStyle, GUILayout.Height(32)))
            {
                adEventLog.Clear();
                adStatus = "";
            }
        }

        GUILayout.EndVertical();
    }

    private Action _loadUnsubscribe;

    private void ExecuteLoadAd()
    {
        string adId = selectedAdType == "interstitial" ? TEST_INTERSTITIAL_AD_ID : TEST_REWARDED_AD_ID;
        adStatus = $"Loading {selectedAdType} ad...";
        adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] loadAppsInTossAdMob(adGroupId: {adId})");

        // 기존 구독 해제
        _loadUnsubscribe?.Invoke();

        // GoogleAdMobLoadAppsInTossAdMob API 호출
#pragma warning disable CS0618 // Obsolete 경고 무시
        _loadUnsubscribe = AIT.GoogleAdMobLoadAppsInTossAdMob(
            options: new LoadAdMobOptions { AdGroupId = adId },
            onEvent: (result) =>
            {
                adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] Load event: {result.Type}");
                if (result.Type == "loaded")
                {
                    isAdLoaded = true;
                    adStatus = $"{selectedAdType} ad loaded";
                    if (result.Data != null)
                    {
                        adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] AdGroupId: {result.Data.AdGroupId}, AdUnitId: {result.Data.AdUnitId}");
                    }
                }
            },
            onError: (error) =>
            {
                isAdLoaded = false;
                adStatus = $"Error: {error.Message}";
                adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] Error: {error.ErrorCode} - {error.Message}");
            }
        );
#pragma warning restore CS0618
    }

    private Action _showUnsubscribe;

    private void ExecuteShowAd()
    {
        if (!isAdLoaded)
        {
            adStatus = "Please load ad first";
            return;
        }

        string adId = selectedAdType == "interstitial" ? TEST_INTERSTITIAL_AD_ID : TEST_REWARDED_AD_ID;
        adStatus = $"Showing {selectedAdType} ad...";
        adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] showAppsInTossAdMob(adGroupId: {adId})");

        // 기존 구독 해제
        _showUnsubscribe?.Invoke();

        // GoogleAdMobShowAppsInTossAdMob API 호출
#pragma warning disable CS0618 // Obsolete 경고 무시
        _showUnsubscribe = AIT.GoogleAdMobShowAppsInTossAdMob(
            options: new ShowAdMobOptions { AdGroupId = adId },
            onEvent: (result) =>
            {
                adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] Show event: {result.Type}");
                if (result.Type == "dismissed")
                {
                    // 광고 표시 후 다시 로드 필요 (한 번에 1개만 로드 가능)
                    isAdLoaded = false;
                    adStatus = $"{selectedAdType} ad shown (reload required for next ad)";
                    adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] Success: Ad dismissed");
                }
                else if (result.Type == "userEarnedReward" && result.Data != null)
                {
                    adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] Reward: {result.Data.UnitAmount} {result.Data.UnitType}");
                }
            },
            onError: (error) =>
            {
                adStatus = $"Error: {error.Message}";
                adEventLog.Add($"[{DateTime.Now:HH:mm:ss}] Error: {error.ErrorCode} - {error.Message}");
            }
        );
#pragma warning restore CS0618
    }

    private void OnDestroy()
    {
        // 컴포넌트 제거 시 구독 해제
        _loadUnsubscribe?.Invoke();
        _showUnsubscribe?.Invoke();
    }
}

주의사항

TIP

  • 광고는 반드시 Load → Show 순서로 호출해야 해요.
  • 광고를 한 번 표시하면 다시 로드해야 다음 광고를 표시할 수 있어요.
  • 한 번에 하나의 광고만 로드할 수 있어요.
  • 보상형 광고의 보상 지급은 userEarnedReward 이벤트 기준으로 처리해주세요.
  • 인앱 광고는 샌드박스 앱에서 테스트할 수 없어요.
    인앱 광고 테스트는 QR 코드를 통해 토스 앱에서 실행한 경우에만 가능해요.