사전캠프/Unity

구글 기반 광고 만들기 - 구글 애드몹

서보훈 2024. 8. 28. 16:26

5주차 강의 내용으로, Unity 에서 제공하는 광고 시스템을 사용해 제작한 게임에 광고를 등록합니다.

 

해당 내용 관련으로, 구글 애드몹을 사용하여 광고를 추가하는법을 정리해보도록 하겠습니다.

이 내용은 모두 모바일 게임에 광고를 삽입하는 방법입니다.

 

먼저, 구글 애드몹을 사용할 수 있도록 플러그인을 추가해줄 필요가 있습니다

아래 깃허브에서 플러그인을 패키지를 받아줍니다.

https://github.com/googleads/googleads-mobile-unity/releases

 

Releases · googleads/googleads-mobile-unity

Official Unity Plugin for the Google Mobile Ads SDK - googleads/googleads-mobile-unity

github.com

GoogleMobileAds 패키지를 광고를 넣을 프로젝트에 설치해줍니다.

 

패키지를 설치하면 에디터 상단의 툴바의 Assets 에 Google Mobile Ads가 추가된것을 확인할 수 있습니다.

Setting을 눌러서 이 게임이 광고를 받을 아이디를 입력해야합니다.

콘솔창의 오류는 IOS 관련 패키지를 받지 않았기 때문에 발생합니다.

만약, 실제 사용이 아닌 공부를 위한경우 이 플러그인에서 제공하는 앱 ID를 사용해주시기 바랍니다

ca-app-pub-3940256099942544~3347511713

 

이 아이디는 구글 애드몹에서 발급받아야 합니다.

구글 자체와 연결되어있기 때문에, 구글계정을 통해 로그인이 가능합니다.

https://admob.google.com/home/

 

Google AdMob: 모바일 앱 수익 창출

인앱 광고를 사용하여 모바일 앱에서 더 많은 수익을 창출하고, 사용이 간편한 도구를 통해 유용한 분석 정보를 얻고 앱을 성장시켜 보세요.

admob.google.com

로그인 후, 애드몹에 광고가 발생할 어플리케이션을 등록해주어야 합니다.

실제 광고를 사용할 예정은 아니기때문에, 임시로 앱 이름을 등록해줍니다.

 

애드몹에 앱이 등록되면, 앱 설정 탭에서 앱ID를 발급받을수 있게됩니다.

이 ID를 Setting을 눌렀을때 나오는 인스펙터창에 입력해줍니다.

또한 플랫폼을 안드로이드로 앱을 등록했기때문에, 안드로이드탭에 입력해주면 됩니다.

 

주의사항은, 해당 앱 ID는 고유 아이디를 사용하지만, 예시로 만드는 이 시점에서는 이 ID를 사용해 진짜 광고를 받아오면 안됩니다.

이 예시어플을 통해 진짜 광고를 받아오고, 테스트를 하면서 계속 광고를 요청할경우 애드몹에서 계정이 블록되는 상황도 발생할 수 있기 때문에 공부를 하거나 테스트를 할 때에는 예시용 광고 ID를 사용해야합니다.

 

각각의 유형의 광고마다 광고 ID를 사용하게 되는데, 여기에 테스트용 광고 ID를 사용해서 수익이 발생하지 않는 가짜 광고를 받아올 수 있습니다.

 

이제 광고를 발생시킬 준비를 하도록 하겠습니다.

광고를 설정할 스크립트, AdManager를 만들어줍니다.

 

해당 스크립트에 사용법은 이 메뉴얼을 참조해서 사용하면 됩니다.

https://developers.google.com/admob/unity/banner?hl=ko

 

배너 광고  |  Unity  |  Google for Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. 배너 광고 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 배너 보기는 화면 안의 한 지점을 차지하는

developers.google.com

 

만약 실제 광고를 추가한다면, 애드몹에서 광고 단위를 생성하여 각 광고에 맞는 광고 ID를 사용해주어야 합니다.

 

예시로 사용할, 전체 코드입니다.

해당 코드에는 배너광고(앱 상단, 하단등 게임을 플레이 하면서 보이는 광고)

전면광고(게임을 플레이하는중, 모든 화면을 가리며 등장하는 광고)

보상형광고(플레이어가 버튼을 누르면 광고를 보여주고, 광고가 끝나면 보상을 주는 광고)

3가지 유형의 광고를 포함합니다.

 

또한, 여기에 사용된 광고 ID는 매뉴얼에서 볼 수 있는 테스트 광고ID로 수익이 발생하지 않는 가짜 광고입니다.

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GoogleMobileAds.Api;

namespace MyFps.Utility
{
#if AD_MODE
    public class AdManager : PesistentSingleton<AdManager>
    {
        private void Start()
        {
            // Initialize the Google Mobile Ads SDK.
            MobileAds.Initialize(initStatus => { });

            //광고 요청
            RequestBanner();            //배너광고 : 요청 완료되면 광고가 보여진다
            RequestInterstitial();      //전면광고 : 요청 완료되도 광고가 안보여진다
            RequestRewarded();          //보상형광고 : 요청 완료되도 광고가 안보여진다
        }

        #region Variables
        private BannerView _bannerView;             //배너광고
        private InterstitialAd _interstitialAd;     //전면광고
        private RewardedAd _rewardedAd;             //보상형 광고

#if UNITY_ANDROID
        [SerializeField] private string _adBannerUnitId = "ca-app-pub-3940256099942544/6300978111";
        [SerializeField] private string _adInterstitialUnitId = "ca-app-pub-3940256099942544/1033173712";
        [SerializeField] private string _adRewardedUnitId = "ca-app-pub-3940256099942544/5224354917";
#elif UNITY_IPHONE
        [SerializeField] private string _adBannerUnitId = "ca-app-pub-3940256099942544/2934735716";
        [SerializeField] private string _adInterstitialUnitId = "ca-app-pub-3940256099942544/4411468910";
#else
        [SerializeField] private string _adBannerUnitId = "unused";
        [SerializeField] private string _adInterstitialUnitId = "unused";
        [SerializeField] private string _adRewardedUnitId = "unused";
#endif
        #endregion

        #region Ad Banner
        public void RequestBanner()
        {
            // If we already have a banner, destroy the old one.
            if (_bannerView != null)
            {
                DestroyBannerView();
            }

            // Create a 320x50 banner at top of the screen
            //_bannerView = new BannerView(_adBannerUnitId, AdSize.Banner, AdPosition.Top);
            //배너 싸이즈와 위치 조정
            AdSize adaptiveSize = AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(AdSize.FullWidth);
            _bannerView = new BannerView(_adBannerUnitId, adaptiveSize, AdPosition.Top);

            // create our request used to load the ad.
            var adRequest = new AdRequest();

            // send the request to load the ad.
            Debug.Log("Loading banner ad.");
            _bannerView.LoadAd(adRequest);
        }

        public void ShowBanner()
        {
            if(_bannerView != null)
            {
                _bannerView.Show();
            }
        }

        public void HideBanner()
        {
            if (_bannerView != null)
            {
                _bannerView.Hide();
            }
        }

        public void DestroyBannerView()
        {
            if (_bannerView != null)
            {
                _bannerView.Destroy();
                _bannerView = null;
            }
        }
        #endregion

        #region Ad Interstitial
        public void RequestInterstitial()
        {
            // Clean up the old ad before loading a new one.
            if (_interstitialAd != null)
            {
                DestroyInterstitial();
            }

            // create our request used to load the ad.
            var adRequest = new AdRequest();

            // send the request to load the ad.
            InterstitialAd.Load(_adInterstitialUnitId, adRequest,
                (InterstitialAd ad, LoadAdError error) =>
                {
                    // if error is not null, the load request failed.
                    if (error != null || ad == null)
                    {
                        return;
                    }
                    _interstitialAd = ad;
                                        
                    _interstitialAd.OnAdClicked += HandleOnClicked;
                    _interstitialAd.OnAdFullScreenContentClosed += HandleOnAdClosed;
                    _interstitialAd.OnAdFullScreenContentOpened += HandleOnAdOpened;
                    _interstitialAd.OnAdPaid += HandleOnPaid;
                });
        }

        public void ShowInterstitialAd()
        {
            if (_interstitialAd != null && _interstitialAd.CanShowAd())
            {
                Debug.Log("Showing interstitial ad.");
                _interstitialAd.Show();
            }
            else
            {
                Debug.LogError("Interstitial ad is not ready yet.");
            }
        }

        public void HandleOnClicked()
        {
            Debug.Log("===========Interstitial ad Click");
        }

        public void HandleOnAdClosed()
        {
            Debug.Log("===========Interstitial ad Closed");

            //광고를 보고 클로즈하면 광고를 다시 요청한다
            RequestInterstitial();
        }

        public void HandleOnAdOpened()
        {
            Debug.Log("===========Interstitial ad Opened");
        }

        public void HandleOnPaid(AdValue adValue)
        {
            Debug.Log("===========Interstitial ad Paid");
        }

        public void DestroyInterstitial()
        {
            if (_interstitialAd != null)
            {
                _interstitialAd.Destroy();
                _interstitialAd = null;
            }
        }
        #endregion

        #region Ad Rewarded
        public void RequestRewarded()
        {
            // Clean up the old ad before loading a new one.
            if (_rewardedAd != null)
            {
                DestroyRewarded();
            }

            Debug.Log("Loading the rewarded ad.");

            // create our request used to load the ad.
            var adRequest = new AdRequest();

            // send the request to load the ad.
            RewardedAd.Load(_adRewardedUnitId, adRequest,
                (RewardedAd ad, LoadAdError error) =>
                {
                    // if error is not null, the load request failed.
                    if (error != null || ad == null)
                    {                        
                        return;
                    }
                    _rewardedAd = ad;

                    _rewardedAd.OnAdClicked += HandleOnRewardedAdClicked;
                    _rewardedAd.OnAdFullScreenContentClosed += HandleOnRewardedAdClosed;
                    _rewardedAd.OnAdPaid += HandleOnRewardedAdPaid;
                    _rewardedAd.OnAdImpressionRecorded += HandelOnRewardedAdImpression;
                });
        }

        public void ShowRewardedAd()
        {
            //const string rewardMsg =
            //    "Rewarded ad rewarded the user. Type: {0}, amount: {1}.";

            if (_rewardedAd != null && _rewardedAd.CanShowAd())
            {
                _rewardedAd.Show((Reward reward) =>
                {
                    // TODO: Reward the user.
                    //Debug.Log(System.String.Format(rewardMsg, reward.Type, reward.Amount));
                });
            }
        }

        public void DestroyRewarded()
        {
            if (_rewardedAd != null)
            {
                _rewardedAd.Destroy();
                _rewardedAd = null;
            }
        }

        public void HandleOnRewardedAdClicked()
        {
            Debug.Log("===========Rewarded Ad Click");
        }

        public void HandleOnRewardedAdClosed()
        {
            Debug.Log("===========Rewarded Ad Closed");

            //광고를 보고 클로즈하면 광고를 다시 요청한다
            RequestRewarded();
        }

        public void HandleOnRewardedAdPaid(AdValue adValue)
        {
            //유저에게 등록된 보상 지급
            //Debug.Log(String.Format("Rewarded ad paid {0} {1}.",
            //    adValue.Value,
            //    adValue.CurrencyCode));
            Debug.Log("===========Rewarded Ad Reward 탄환 10개 지급");

            //등록되지 않은 보상 직접 지급(탄환 10개 지급)
            PlayerStats.Instance.AddAmmo(10);
        }

        public void HandelOnRewardedAdImpression()
        {
            Debug.Log("===========Rewarded Ad Impression Recorded");
        }

        #endregion
    }
#endif
}

배너형 광고입니다. 해당 클래스가 상속받는 클래스는 싱글톤 클래스로 광고를 관리하는 클래스는 싱글톤화 시켜, 하나만 존재하게 해 주어야 합니다.

 

 

배너형 광고는 Start에서 광고를 요청하고, 광고 요청이 성공하면 즉시 광고를 보여주게 됩니다.

또한 배너형 광고를 보여주기 위해 BannerView변수를 선언해주고, 광고의 ID를 저장할 변수를 선언하여 발급받은 배너광고의 ID를 등록해줍니다.

    public class AdManager : PesistentSingleton<AdManager>
    {
        private void Start()
        {
            // Initialize the Google Mobile Ads SDK.
            MobileAds.Initialize(initStatus => { });

            //광고 요청
            RequestBanner();            //배너광고 : 요청 완료되면 광고가 보여진다
        }

        private BannerView _bannerView;             //배너광고

#if UNITY_ANDROID
        [SerializeField] private string _adBannerUnitId = "ca-app-pub-3940256099942544/6300978111";
#elif UNITY_IPHONE
        [SerializeField] private string _adBannerUnitId = "ca-app-pub-3940256099942544/2934735716";
#else
        [SerializeField] private string _adBannerUnitId = "unused";
#endif
    }

광고를 요청하는 함수 입니다.

배너광고의 크기를 정하고, 애드 몹에서 광고를 받아오는 역할을 하는 함수입니다.

public void RequestBanner()
{
    // If we already have a banner, destroy the old one.
    //이미 배너가 있으면, 이전 배너를 삭제하고 다시 생성
    if (_bannerView != null)
    {
        DestroyBannerView();
    }

    // Create a 320x50 banner at top of the screen
    //_bannerView = new BannerView(_adBannerUnitId, AdSize.Banner, AdPosition.Top);
    //배너 사이즈와 위치 조정
    AdSize adaptiveSize = AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(AdSize.FullWidth);
    _bannerView = new BannerView(_adBannerUnitId, adaptiveSize, AdPosition.Top);

    // create our request used to load the ad.
    //광고 요청
    var adRequest = new AdRequest();

    // send the request to load the ad.
    //요청을 통해 받은 광고를 배너에 적용
    Debug.Log("Loading banner ad.");
    _bannerView.LoadAd(adRequest);
}

배너의 크기를 정하는 부분에서, AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth 라는 이름의 긴 함수를 사용하게 되는데, 해당 함수는 화면의 가로길이에 맞추어 배너크기를 생성해주는 함수입니다.

즉, 여기서는 화면의 가로 길이에 맞추어 배너를 생성해주는 역할을 합니다

 

또한, 이러한 함수가 존재합니다.

//배너를 보여주는 함수
public void ShowBanner()
{
    if(_bannerView != null)
    {
        _bannerView.Show();
    }
}

//배너를 숨기는 함수
public void HideBanner()
{
    if (_bannerView != null)
    {
        _bannerView.Hide();
    }
}

//배너를 삭제하는 함수
public void DestroyBannerView()
{
    if (_bannerView != null)
    {
        _bannerView.Destroy();
        _bannerView = null;
    }
}

이 함수들을 호출하여, 게임중 배너광고를 조작해줄 수 있습니다.

 


전면형 광고를 보여주는 코드입니다.

해당 광고는 게임의 화면을 전환할때 등에 사용하기 좋은 광고 형태로, 게임 중간에 화면 전체에 발생하는 광고입니다.

 

또한 Start에서 광고를 요청하지만 이를 즉시 보여주지 않고 광고 정보를 가지고 있다가, 광고를 보여주는 함수를 사용해야 광고를 보여줍니다.

배너와 마찬가지로, 전면형 광고 또한 본인의 광고 ID를 가지고 있으며, 전면형 광고 클래스 변수를 선언해주어야 합니다.

    public class AdManager : PesistentSingleton<AdManager>
    {
        private void Start()
        {
            // Initialize the Google Mobile Ads SDK.
            MobileAds.Initialize(initStatus => { });

            //광고 요청
            RequestInterstitial();      //전면광고 : 요청 완료되도 광고가 안보여진다
        }
        
        private InterstitialAd _interstitialAd;     //전면광고

#if UNITY_ANDROID
        [SerializeField] private string _adInterstitialUnitId = "ca-app-pub-3940256099942544/1033173712";
#elif UNITY_IPHONE
        [SerializeField] private string _adInterstitialUnitId = "ca-app-pub-3940256099942544/4411468910";
#else
        [SerializeField] private string _adInterstitialUnitId = "unused";
#endif

 

광고를 요청하는 함수 입니다.

마찬가지로, 이미 등록된 전면광고가 있을경우 해당 광고를 삭제하고 새로운 광고를 받아옵니다.

또한 유니티 이벤트를 사용하여 해당 광고에 상호작용을 하였을때 호출할 함수를 등록하게 됩니다.

public void RequestInterstitial()
{
    // Clean up the old ad before loading a new one.
    if (_interstitialAd != null)
    {
        DestroyInterstitial();
    }

    // create our request used to load the ad.
    var adRequest = new AdRequest();

    // send the request to load the ad.
    InterstitialAd.Load(_adInterstitialUnitId, adRequest,
        (InterstitialAd ad, LoadAdError error) =>
        {
        
            // if error is not null, the load request failed.
            if (error != null || ad == null)
            {
                return;
            }
            _interstitialAd = ad;
                                      
            _interstitialAd.OnAdClicked += HandleOnClicked;
            _interstitialAd.OnAdFullScreenContentClosed += HandleOnAdClosed;
            _interstitialAd.OnAdFullScreenContentOpened += HandleOnAdOpened;
            _interstitialAd.OnAdPaid += HandleOnPaid;
        });
}

 

전면광고를 보여주는 함수입니다.

전면광고를 보여주고 싶은 시점에 이 함수를 호출하여 광고를 보여주게됩니다.

만약 광고를 불러오지 못한 상태일경우, else문이 작동해 광고를 보여주지 않습니다.

public void ShowInterstitialAd()
{
    if (_interstitialAd != null && _interstitialAd.CanShowAd())
    {
        Debug.Log("Showing interstitial ad.");
        _interstitialAd.Show();
    }
    else
    {
        Debug.LogError("Interstitial ad is not ready yet.");
    }
}

 

이외의 함수들 입니다.

이 함수들은 유니티 이벤트 형태로 등록되어 전면광고 창에서의 상호작용에 따라 이 함수들이 호출되게 됩니다.

또한, 전면광고의 경우 하나의 광고를 본 후에는 다음 광고를 보여주어야하기 때문에, 광고를 닫은 후 다음 광고를 요청하게 됩니다.

public void HandleOnClicked()
{
    Debug.Log("===========Interstitial ad Click");
}

public void HandleOnAdClosed()
{
    Debug.Log("===========Interstitial ad Closed");

    //광고를 보고 클로즈하면 광고를 다시 요청한다
    RequestInterstitial();
}

public void HandleOnAdOpened()
{
    Debug.Log("===========Interstitial ad Opened");
}

public void HandleOnPaid(AdValue adValue)
{
    Debug.Log("===========Interstitial ad Paid");
}

public void DestroyInterstitial()
{
    if (_interstitialAd != null)
    {
        _interstitialAd.Destroy();
        _interstitialAd = null;
    }
}

 


보상형 광고 입니다.

해당 광고 유형은 광고를 보고 난 후, 플레이어에게 광고를 본 보상을 지급하는 형태의 광고입니다.

 

전면광고와 마찬가지로, 미리 광고를 요청해둔 후, 광고를 보여주는 함수를 호출하면 그 때 광고를 보여주게 됩니다.

    public class AdManager : PesistentSingleton<AdManager>
    {
        private void Start()
        {
            // Initialize the Google Mobile Ads SDK.
            MobileAds.Initialize(initStatus => { });

            //광고 요청
            RequestRewarded();          //보상형광고 : 요청 완료되도 광고가 안보여진다
        }

        private RewardedAd _rewardedAd;             //보상형 광고

#if UNITY_ANDROID
        [SerializeField] private string _adRewardedUnitId = "ca-app-pub-3940256099942544/5224354917";
#elif UNITY_IPHONE
#else
        [SerializeField] private string _adRewardedUnitId = "unused";
#endif

 

광고를 요청하는 함수 입니다.

마찬가지로 이미 등록된 광고가 있을경우, 기존 광고를 지우고 새로운 광고를 받게 됩니다.

또한 추가적인 함수가 이벤트 함수로 등록되어, 보상형 광고 내에서 상호작용시 상황에 맞는 함수가 작동되게 됩니다.

public void RequestRewarded()
{
    // Clean up the old ad before loading a new one.
    if (_rewardedAd != null)
    {
        DestroyRewarded();
    }

    Debug.Log("Loading the rewarded ad.");

    // create our request used to load the ad.
    var adRequest = new AdRequest();

    // send the request to load the ad.
    RewardedAd.Load(_adRewardedUnitId, adRequest,
        (RewardedAd ad, LoadAdError error) =>
        {
            // if error is not null, the load request failed.
            if (error != null || ad == null)
            {                        
                return;
            }
            _rewardedAd = ad;

            _rewardedAd.OnAdClicked += HandleOnRewardedAdClicked;
            _rewardedAd.OnAdFullScreenContentClosed += HandleOnRewardedAdClosed;
            _rewardedAd.OnAdPaid += HandleOnRewardedAdPaid;
            _rewardedAd.OnAdImpressionRecorded += HandelOnRewardedAdImpression;
        });
}

 

이외의 함수들 입니다.

전면광고와 마찬가지로 광고를 닫을때 새로운 광고를 요청해줍니다.

public void ShowRewardedAd()
{
    //const string rewardMsg =
    //    "Rewarded ad rewarded the user. Type: {0}, amount: {1}.";

    if (_rewardedAd != null && _rewardedAd.CanShowAd())
    {
        _rewardedAd.Show((Reward reward) =>
        {
            // TODO: Reward the user.
            //Debug.Log(System.String.Format(rewardMsg, reward.Type, reward.Amount));
        });
    }
}

public void DestroyRewarded()
{
    if (_rewardedAd != null)
    {
        _rewardedAd.Destroy();
        _rewardedAd = null;
    }
}

public void HandleOnRewardedAdClicked()
{
    Debug.Log("===========Rewarded Ad Click");
}

public void HandleOnRewardedAdClosed()
{
    Debug.Log("===========Rewarded Ad Closed");

    //광고를 보고 클로즈하면 광고를 다시 요청한다
    RequestRewarded();
}

public void HandelOnRewardedAdImpression()
{
    Debug.Log("===========Rewarded Ad Impression Recorded");
}

 

보상 지급 조건이 만족되었을경우, 보상을 지급하는 함수입니다.

만약 보상이 광고 자체에 등록되어있을경우 광고를 통해 지급하게 되며

광고에 보상이 등록되어있지 않은경우 추가로 보상을 입력하여 유저에게 보상을 지급하게 됩니다.

public void HandleOnRewardedAdPaid(AdValue adValue)
{
    //유저에게 등록된 보상 지급
    //Debug.Log(String.Format("Rewarded ad paid {0} {1}.",
    //    adValue.Value,
    //    adValue.CurrencyCode));
    Debug.Log("===========Rewarded Ad Reward 탄환 10개 지급");

    //등록되지 않은 보상 직접 지급(탄환 10개 지급)
    PlayerStats.Instance.AddAmmo(10);
}

 

'사전캠프 > Unity' 카테고리의 다른 글

유니티 기능 - TextMeshPro  (0) 2024.09.04
C# 기능 - Linq  (0) 2024.09.03
유니티 기능 - #region, #if  (0) 2024.08.26
4주차 과제 - 30초가 지나면 게임 끝내기  (0) 2024.08.26
Unity 기능 - Input System  (0) 2024.08.22