[unity] 모듈 제작 : 광고 시스템(Admob, UnityAds) 만들기(2)
Unity에서 사용하는 수익 구조 중 광고(Admob, UnityAds) 모듈을 제작하는 방법 및 사용하는 방법에 대해 알아보자. (2편)
이전 편에 이어서 스크립트 작성 및 테스트 코드를 만들어 보자.
2022.07.08 - [unity3d/Modules] - [unity] 모듈 제작 : 광고 시스템(Admob, UnityAds) 만들기(1)
5. Script 작성 : AdAdmob.cs
이전 편에서 작성했던 Adbase를 상속받는 AdAdmob.cs 스크립트를 만들어 준다.
AdAdmob 클래스는 애드몹의 배너, 동영상 광고, 전면광고의 제어를 담당한다.
Admob 사이트에서 배너, 전면, 보상형 광고 단위를 생성 후 ID를 코드에 입력해준다.
광고 단위 ID는 ca-app-pub- 형태로 시작한다.
스크립트에 아래와 같이 작성해보자.
using System;
using UnityEngine;
using GoogleMobileAds.Api;
namespace Modules.Ads
{
public class AdAdmob : Adbase
{
[SerializeField]
protected string bannerID = "ca-app-pub-**********"; //사용자가 바꿀 부분
[SerializeField]
protected string interstitialID = "ca-app-pub-**********"; //사용자가 바꿀 부분
[SerializeField]
protected string rewardID = "ca-app-pub-**********"; //사용자가 바꿀 부분
protected BannerView bannerAd = null;
protected InterstitialAd interstitialAd = null;
protected RewardedAd rewardAd = null;
protected bool IsRewared { get; set; }
public override void OnInitialize()
{
MobileAds.Initialize((initStatus) =>
{
if (isBannerUse)
{
LoadBanner();
bannerAd.OnAdFailedToLoad += BannerAd_OnAdFailedToLoad;
ShowBanner();
}
if (isInterstitialUse)
{
interstitialAd = new InterstitialAd(interstitialID);
LoadInterstitial();
interstitialAd.OnAdClosed += InterstitialAd_OnAdClosed;
}
if (isRewardUse)
{
rewardAd = new RewardedAd(rewardID);
LoadRewardBasedVideo();
rewardAd.OnAdClosed += HandleRewardBasedVideoClosed;
rewardAd.OnUserEarnedReward += HandleRewardBasedVideoRewarded;
rewardAd.OnAdFailedToLoad += RewardAd_OnAdFailedToLoad;
}
});
}
/// <summary>
/// Destory Event
/// </summary>
public void OnDestroy()
{
if (isBannerUse && bannerAd != null)
{
bannerAd.OnAdFailedToLoad -= BannerAd_OnAdFailedToLoad;
}
if (isInterstitialUse && interstitialAd != null)
{
interstitialAd.OnAdClosed -= InterstitialAd_OnAdClosed;
}
if (isRewardUse && rewardAd != null)
{
rewardAd.OnAdClosed -= HandleRewardBasedVideoClosed;
rewardAd.OnUserEarnedReward -= HandleRewardBasedVideoRewarded;
rewardAd.OnAdFailedToLoad -= RewardAd_OnAdFailedToLoad;
}
}
#region Banner
protected void LoadBanner()
{
bannerAd = new BannerView(bannerID, AdSize.Banner, AdPosition.Bottom);
AdRequest request = new AdRequest.Builder().Build();
bannerAd.LoadAd(request);
}
public void ShowBanner()
{
if (bannerAd != null)
bannerAd.Show();
}
public void HideBanner()
{
if (bannerAd != null)
bannerAd.Hide();
}
private void BannerAd_OnAdFailedToLoad(object sender, AdFailedToLoadEventArgs e)
{
Debug.Log(e.ToString()) ;
}
#endregion
#region Interstitial
protected void LoadInterstitial()
{
if (!interstitialAd.IsLoaded() && !string.IsNullOrEmpty(interstitialID))
{
AdRequest request = new AdRequest.Builder().Build();
this.interstitialAd.LoadAd(request);
}
}
public override void ShowInterstitial()
{
if (interstitialAd.IsLoaded())
interstitialAd.Show();
}
void InterstitialAd_OnAdClosed(object sender, System.EventArgs e)
{
LoadInterstitial();
}
#endregion
#region RewardVideoAds
public override void ShowRewardVideo(System.Action<AdResultType> result)
{
OnRewardResult = result;
ShowRewardVideo();
}
public void ShowRewardVideo()
{
if (rewardAd.IsLoaded())
{
IsRewared = false;
rewardAd.Show();
}
else
{
if (OnRewardResult != null)
{
OnRewardResult(AdResultType.Fail);
OnRewardResult = null;
}
LoadRewardBasedVideo();
}
}
protected void LoadRewardBasedVideo()
{
AdRequest request = new AdRequest.Builder().Build();
rewardAd.LoadAd(request);
}
protected virtual void HandleRewardBasedVideoRewarded(object sender, Reward e)
{
Debug.Log("[동영상광고 보상지급]" + "보상타입 :" + e.Type + " / " + "보상개수 :" + e.Amount);
IsRewared = true;
}
protected void HandleRewardBasedVideoClosed(object sender, EventArgs e)
{
Debug.Log("비디오 종료 : " + e.ToString());
if (OnRewardResult != null)
{
if (IsRewared)
{
OnRewardResult(AdResultType.Sucess);
}
else
{
#if UNITY_EDITOR
OnRewardResult(AdResultType.Sucess);
#else
OnRewardResult(AdResultType.Fail);
#endif
}
OnRewardResult = null;
}
IsRewared = false;
LoadRewardBasedVideo();
}
protected void RewardAd_OnAdFailedToLoad(object sender, AdFailedToLoadEventArgs e)
{
Debug.Log(e.ToString());
}
#endregion
}
}
6. Script 작성 : AdUnity.cs
이전편에서 작성했던 Adbase를 상속받는 AdUnity.cs 스크립트도 만들어 주자.
AdUnity 클래스는 UnityAds의 배너, 동영상 광고, 전면광고의 제어를 담당한다.
Service에서 확인할 수 있는 Unity Ads의 gameID 값을 넣어준다.
using System;
using UnityEngine;
using UnityEngine.Advertisements;
namespace Modules.Ads
{
public class AdUnity : Adbase, IUnityAdsInitializationListener, IUnityAdsLoadListener, IUnityAdsShowListener
{
protected string placement_reward_Id = "rewardedVideo";
[SerializeField]
protected string android_game_id = "*******"; //사용자가 바꿀 부분
[SerializeField]
protected string ios_game_id = "********"; //사용자가 바꿀 부분
private const string BANNER_PLACEMENT = "banner";
private const string VIDEO_PLACEMENT = "video";
private const string REWARDED_VIDEO_PLACEMENT = "rewardedVideo";
private BannerPosition bannerPosition = BannerPosition.BOTTOM_CENTER;
private bool testMode = true;
public override void OnInitialize()
{
#if UNITY_IOS
Advertisement.Initialize(ios_game_id, testMode, this);
#else
Advertisement.Initialize(android_game_id, testMode, this);
#endif
if (isBannerUse)
{
Advertisement.Banner.SetPosition(bannerPosition);
Advertisement.Banner.Show(BANNER_PLACEMENT);
}
if (isInterstitialUse)
{
Advertisement.Load(VIDEO_PLACEMENT, this);
}
if (isRewardUse)
{
Advertisement.Load(REWARDED_VIDEO_PLACEMENT, this);
}
}
#region Interface Implementations
public void OnInitializationComplete()
{
Debug.Log("Init Success");
}
public void OnInitializationFailed(UnityAdsInitializationError error, string message)
{
Debug.Log($"Init Failed: [{error}]: {message}");
}
public void OnUnityAdsAdLoaded(string placementId)
{
Debug.Log($"Load Success: {placementId}");
}
public void OnUnityAdsFailedToLoad(string placementId, UnityAdsLoadError error, string message)
{
Debug.Log($"Load Failed: [{error}:{placementId}] {message}");
}
public void OnUnityAdsShowFailure(string placementId, UnityAdsShowError error, string message)
{
Debug.Log($"OnUnityAdsShowFailure: [{error}]: {message}");
}
public void OnUnityAdsShowStart(string placementId)
{
Debug.Log($"OnUnityAdsShowStart: {placementId}");
}
public void OnUnityAdsShowClick(string placementId)
{
Debug.Log($"OnUnityAdsShowClick: {placementId}");
}
/// <summary>
/// 보상형 광고 콜백함수.
/// </summary>
/// <param name="placementId"></param>
/// <param name="showCompletionState"></param>
public void OnUnityAdsShowComplete(string placementId, UnityAdsShowCompletionState showCompletionState)
{
switch(showCompletionState)
{
case UnityAdsShowCompletionState.COMPLETED:
{
if(OnRewardResult != null)
OnRewardResult(AdResultType.Sucess);
}
break;
case UnityAdsShowCompletionState.SKIPPED:
case UnityAdsShowCompletionState.UNKNOWN:
{
if (OnRewardResult != null)
OnRewardResult(AdResultType.Fail);
}
break;
}
OnRewardResult = null;
}
/// <summary>
/// 보상형 동영상 광고 Show
/// </summary>
/// <param name="result"></param>
public override void ShowRewardVideo(Action<AdResultType> result)
{
OnRewardResult = result;
Advertisement.Show(REWARDED_VIDEO_PLACEMENT, this);
}
public override void ShowInterstitial()
{
Advertisement.Show(VIDEO_PLACEMENT, this);
}
#endregion
}
}
7. Script 작성 : AdManager.cs
우리가 만든 AdBase 항목을 호출할 컨트롤 클래스인 AdManager 클래스를 제작해보자.
AdManager.cs 클래스를 만든 후 아래와 같이 작성해주자.
using System;
using System.Collections;
using System.Collections.Generic;
using GoogleMobileAds.Api;
using UnityEngine;
namespace Modules.Ads
{
/// <summary>
/// 구글 애드몹/UnityAds 사용을 위한 매니저 클래스
/// </summary>
public class AdManager : MonoBehaviour
{
//싱글톤
public static AdManager Instance { get; private set; }
private Dictionary<Advertiser, Adbase> dic_advertiser = new Dictionary<Advertiser, Adbase>();
private void Awake()
{
Instance = this;
Adbase[] ads = FindObjectsOfType<Adbase>();
foreach(Adbase ad in ads)
{
if(!dic_advertiser.ContainsKey(ad.Type))
{
dic_advertiser.Add(ad.Type, ad);
}
}
}
private void Start()
{
OnInitialize();
}
private void OnDestroy()
{
Instance = null;
}
/// <summary>
/// 모든 광고 모듈 초기화
/// </summary>
public void OnInitialize()
{
foreach(KeyValuePair<Advertiser, Adbase> advertiser in dic_advertiser)
{
advertiser.Value.OnInitialize();
}
}
/// <summary>
/// 보상형 동영상 광고 호출
/// </summary>
/// <param name="advertiser"></param>
/// <param name="result"></param>
public void ShowRewardVideo(Advertiser advertiser, System.Action<AdResultType> result)
{
if(dic_advertiser.ContainsKey(advertiser))
dic_advertiser[advertiser].ShowRewardVideo(result);
}
/// <summary>
/// 전면 광고 호출
/// </summary>
/// <param name="advertiser"></param>
public void ShowInterstitialAds(Advertiser advertiser)
{
if (dic_advertiser.ContainsKey(advertiser))
dic_advertiser[advertiser].ShowInterstitial();
}
}
}
매니저 클래스는 ShowRewardVideo() 함수를 통해 보상형 광고를 호출할 수 있는 인터페이스를 제공해주며, ShowInterstitialAds() 함수를 통해 전면광고를 호출할 수 있는 인터페이스를 제공한다.
배너 광고는 각 광고 클래스(AdUnity, AdAdmob)에서 사용 여부에 따라 바로 Show 하기 때문에 매니저 클래스에서 따로 컨트롤하지는 않는다.
8. 호출 테스트
Scene에 GameObject를 만든 후 AdSystem 이라고 이름을 변경 후 AdManager 스크립트를 붙여준다.
AdSystem 밑에 자식으로 AdUnity라고 GameObject를 만든 후 AdUnity 스크립트를 붙여준다.
배너, 전면광고, 리워드 광고 중 사용하려는 광고를 On, Off 해준다.
Game ID를 넣어준다.
AdSystem 밑에 자식으로 AdAdmob이라고 GameObject를 만든 후 AdAdmob 스크립트를 붙여준다.
배너, 전면광고, 리워드 광고 중 사용하려는 광고를 On, Off 해준다.
광고 ID를 넣어준다.
이제 Scene에 TestCall을 위한 GameObject를 하나 만든 후 정상적으로 호출이 되는지 확인해 보자.
using UnityEngine;
namespace Modules.Ads
{
public class AdTester : MonoBehaviour
{
//유니티 전면광고
public void OnClicked_UnityInterstitialAds()
{
AdManager.Instance.ShowInterstitialAds(Advertiser.Unity);
}
//애드몹 전면광고
public void OnClicked_AdmobInterstitialAds()
{
AdManager.Instance.ShowInterstitialAds(Advertiser.Admob);
}
//유니티 보상형 광고
public void OnClicked_UnityReward()
{
AdManager.Instance.ShowRewardVideo(Advertiser.Unity, OnRewardAction);
}
//애드몹 보상형 광고
public void OnClicked_AdmobReward()
{
AdManager.Instance.ShowRewardVideo(Advertiser.Admob, OnRewardAction);
}
//보상 콜백
private void OnRewardAction(AdResultType result)
{
Debug.Log(result);
}
}
}
9. 결과 화면
간단히 UI로 버튼을 만들어 준 후, AdTester 클래스의 함수에 연결해 준다.
Unity 에디터에서 테스트 결과 잘 출력되는 걸 확인할 수 있다.
위 모듈을 사용하면 사용자는 원하는 시점에 유니티 or 구글 애드몹을 선택적으로 호출하여 컨트롤할 수 있다.
참고로 두 개 광고 모듈 사용 시 배너 광고는 둘 중 하나만 사용해야 한다. (하나는 Enable을 꺼주도록 하자 )
유니티 보상형 광고가 하루 제한 개수가 있는 만큼 유니티 보상형 광고 호출 -> 광고 없음 -> 애드몹 보상형 광고 호출 식으로 부족한 광고를 채우는 방법도 고려 가능하다.
댓글