问题描述
我正在 Unity 中开发一个安卓游戏 apk.我已经在我的项目中集成了 Google Admob SDK,并通过引用 https://developers.google.com/admob/unity/rewarded-video.
I'm developing an android game apk in Unity. I've integrated Google Admob SDK in my project and succeeded to show the Google admob reward video ads in my android apk by referring https://developers.google.com/admob/unity/rewarded-video.
但是当重新加载场景以重新开始游戏时回调函数被多次调用.
However when scene is reloaded to restart game callback functions called multiple times.
回调函数示例:
// Called when an ad request has successfully loaded.
rewardBasedVideo.OnAdLoaded += HandleRewardBasedVideoLoaded;
// Called when an ad request failed to load.
rewardBasedVideo.OnAdFailedToLoad += HandleRewardBasedVideoFailedToLoad;
// Called when an ad is shown.
rewardBasedVideo.OnAdOpening += HandleRewardBasedVideoOpened;
// Called when the ad starts to play.
rewardBasedVideo.OnAdStarted += HandleRewardBasedVideoStarted;
// Called when the user should be rewarded for watching a video.
rewardBasedVideo.OnAdRewarded += HandleRewardBasedVideoRewarded;
第一次加载场景:回调函数被调用了 1 次.
scene loaded first time: callback functions are called 1 time.
再次加载场景:回调函数被调用了 2 次.
scene loaded again: callback functions are called 2 times.
再次加载场景:回调函数被调用 3 次.
scene loaded again: callback functions are called 3 times.
...
我认为根本原因是即使重新加载Unity场景也会累积回调函数.
I think the root cause is that callback functions are accumulated even reloading Unity scenes.
如何让这样的回调函数即使改变场景也只调用1次?
How can I make such callback functions be called only 1 time even changing scene?
推荐答案
所以我终于想出了让广告正常工作的解决方案
So I finally figured out the solution to get the ads working properly
首先安装谷歌显示的谷歌广告SDK
First install the google ad SDK as shown by Google
在此处关注 Google 的 admonb unity 集成教程
然后将以下脚本用于横幅广告、插页式广告以及激励视频广告
Then use the following script for Banner,Interstitial as well as Rewarded Video Ads
SaveManager
和相关的是我的函数中使用的一些脚本
SaveManager
and related are some scripts used in my function
忽略它们
在 update
函数中,您必须不断检查布尔值以查看广告是否已加载.我们将使用 Google Admob
提供的回调来更改这个布尔值,因为广告是在其他线程上并行加载的.我不是多线程或并行处理方面的专家,但我发现你不能从这些回调中调用 Unity 函数,而是可以在那里设置一些 bool,然后继续检查 update 函数中的 bool 值代码>
In the update
function you have to check a boolean continuously to see if the ads are loaded or not. We will change this boolean's value using callbacks provided by Google Admob
, as ads are being loaded paralelly on some other thread. I am not an expert in multithreading or parallel processing, but what I have found is you cannot call Unity functions from those callbacks, instead you can set some bool there, and then keep on checking the bool's value in update function
查看插页式广告和激励广告的 onAdFailedToLoad
事件处理程序
See the onAdFailedToLoad
event handlers of interstitial and rewarded ads
using System;
using UnityEngine;
using UnityEngine.UI;
using GoogleMobileAds.Api;
// Example script showing how to invoke the Google Mobile Ads Unity plugin.
public class adMob : MonoBehaviour
{
private BannerView bannerView;
private InterstitialAd interstitial;
private RewardedAd rewardedAd;
private float deltaTime = 0.0f;
private static string outputMessage = string.Empty;
public Text coinValueHolder;
int rewardAmount;
private bool reqInterstitial = true;
private bool reqRewardedAdVideo = true;
public static adMob ins;
public static string OutputMessage
{
set { outputMessage = value; }
}
public void Start()
{
#if UNITY_ANDROID
string appId = "ca-app-pub-3940256099942544~3347511713";
#elif UNITY_IPHONE
string appId = "ca-app-pub-3940256099942544~1458002511";
#else
string appId = "unexpected_platform";
#endif
MobileAds.SetiOSAppPauseOnBackground(true);
// Initialize the Google Mobile Ads SDK.
MobileAds.Initialize(appId);
this.CreateAndLoadRewardedAd();
}
// making the current object a singleton
public void Awake()
{
if (ins == null)
{
ins = this;
DontDestroyOnLoad(gameObject);
}
else if (ins != null)
{
Destroy(gameObject);
}
}
public void Update()
{
// Calculate simple moving average for time to render screen. 0.1 factor used as
smoothing
// value.
this.deltaTime += (Time.deltaTime - this.deltaTime) * 0.1f;
if (rewardAmount > 0)
{
coinValueHolder =
GameObject.FindGameObjectWithTag("coinText").GetComponent<Text>();
SaveManager.coins += 100;
SaveManager.ins.SaveDataFromDataObjects();
coinValueHolder.text = SaveManager.coins.ToString();
rewardAmount = 0;
}
if(reqInterstitial)
{
this.RequestInterstitial();
reqInterstitial = false;
}
if(reqRewardedAdVideo)
{
this.CreateAndLoadRewardedAd();
reqRewardedAdVideo = false;
}
}
// Returns an ad request with custom ad targeting.
public AdRequest CreateAdRequest()
{
return new AdRequest.Builder().Build();
}
public void RequestBanner()
{
// These ad units are configured to always serve test ads.
#if UNITY_EDITOR
string adUnitId = "unused";
#elif UNITY_ANDROID
string adUnitId = "ca-app-pub-3940256099942544/6300978111";
#elif UNITY_IPHONE
string adUnitId = "ca-app-pub-3940256099942544/2934735716";
#else
string adUnitId = "unexpected_platform";
#endif
// Clean up banner ad before creating a new one.
if (this.bannerView != null)
{
this.bannerView.Destroy();
}
// Create a 320x50 banner at the top of the screen.
this.bannerView = new BannerView(adUnitId, AdSize.Banner, AdPosition.Bottom);
// Register for ad events.
this.bannerView.OnAdLoaded += this.HandleAdLoaded;
this.bannerView.OnAdFailedToLoad += this.HandleAdFailedToLoad;
this.bannerView.OnAdOpening += this.HandleAdOpened;
this.bannerView.OnAdClosed += this.HandleAdClosed;
this.bannerView.OnAdLeavingApplication += this.HandleAdLeftApplication;
// Load a banner ad.
this.bannerView.LoadAd(this.CreateAdRequest());
}
public void DestroyBanner()
{
this.bannerView.Destroy();
}
public void RequestInterstitial()
{
// These ad units are configured to always serve test ads.
#if UNITY_EDITOR
string adUnitId = "unused";
#elif UNITY_ANDROID
string adUnitId = "ca-app-pub-3940256099942544/1033173712";
#elif UNITY_IPHONE
string adUnitId = "ca-app-pub-3940256099942544/4411468910";
#else
string adUnitId = "unexpected_platform";
#endif
// Clean up interstitial ad before creating a new one.
if (this.interstitial != null)
{
this.interstitial.Destroy();
}
// Create an interstitial.
this.interstitial = new InterstitialAd(adUnitId);
// Register for ad events.
this.interstitial.OnAdLoaded += this.HandleInterstitialLoaded;
this.interstitial.OnAdFailedToLoad += this.HandleInterstitialFailedToLoad;
this.interstitial.OnAdOpening += this.HandleInterstitialOpened;
this.interstitial.OnAdClosed += this.HandleInterstitialClosed;
this.interstitial.OnAdLeavingApplication +=
this.HandleInterstitialLeftApplication;
// Load an interstitial ad.
this.interstitial.LoadAd(this.CreateAdRequest());
}
public void CreateAndLoadRewardedAd()
{
#if UNITY_EDITOR
string adUnitId = "unused";
#elif UNITY_ANDROID
string adUnitId = "ca-app-pub-3940256099942544/5224354917";
#elif UNITY_IPHONE
string adUnitId = "ca-app-pub-3940256099942544/1712485313";
#else
string adUnitId = "unexpected_platform";
#endif
// Create new rewarded ad instance.
this.rewardedAd = new RewardedAd(adUnitId);
// Called when an ad request has successfully loaded.
this.rewardedAd.OnAdLoaded += HandleRewardedAdLoaded;
// Called when an ad request failed to load.
this.rewardedAd.OnAdFailedToLoad += HandleRewardedAdFailedToLoad;
// Called when an ad is shown.
this.rewardedAd.OnAdOpening += HandleRewardedAdOpening;
// Called when an ad request failed to show.
this.rewardedAd.OnAdFailedToShow += HandleRewardedAdFailedToShow;
// Called when the user should be rewarded for interacting with the ad.
this.rewardedAd.OnUserEarnedReward += HandleUserEarnedReward;
// Called when the ad is closed.
this.rewardedAd.OnAdClosed += HandleRewardedAdClosed;
// Create an empty ad request.
AdRequest request = this.CreateAdRequest();
// Load the rewarded ad with the request.
this.rewardedAd.LoadAd(request);
}
public void ShowInterstitial()
{
if (this.interstitial.IsLoaded())
{
this.interstitial.Show();
}
else
{
MonoBehaviour.print("Interstitial is not ready yet");
}
}
public void ShowRewardedAd()
{
if (this.rewardedAd.IsLoaded())
{
this.rewardedAd.Show();
}
else
{
MonoBehaviour.print("Rewarded ad is not ready yet");
}
}
#region Banner callback handlers
public void HandleAdLoaded(object sender, EventArgs args)
{
MonoBehaviour.print("HandleAdLoaded event received");
}
public void HandleAdFailedToLoad(object sender, AdFailedToLoadEventArgs args)
{
MonoBehaviour.print("HandleFailedToReceiveAd event received with message: " +
args.Message);
}
public void HandleAdOpened(object sender, EventArgs args)
{
MonoBehaviour.print("HandleAdOpened event received");
}
public void HandleAdClosed(object sender, EventArgs args)
{
MonoBehaviour.print("HandleAdClosed event received");
}
public void HandleAdLeftApplication(object sender, EventArgs args)
{
MonoBehaviour.print("HandleAdLeftApplication event received");
}
#endregion
#region Interstitial callback handlers
public void HandleInterstitialLoaded(object sender, EventArgs args)
{
MonoBehaviour.print("HandleInterstitialLoaded event received");
}
public void HandleInterstitialFailedToLoad(object sender, AdFailedToLoadEventArgs args)
{
MonoBehaviour.print(
"HandleInterstitialFailedToLoad event received with message: " + args.Message);
this.reqInterstitial = true;
}
public void HandleInterstitialOpened(object sender, EventArgs args)
{
MonoBehaviour.print("HandleInterstitialOpened event received");
}
public void HandleInterstitialClosed(object sender, EventArgs args)
{
MonoBehaviour.print("HandleInterstitialClosed event received");
this.reqInterstitial = true;
}
public void HandleInterstitialLeftApplication(object sender, EventArgs args)
{
MonoBehaviour.print("HandleInterstitialLeftApplication event received");
}
#endregion
#region RewardedAd callback handlers
public void HandleRewardedAdLoaded(object sender, EventArgs args)
{
MonoBehaviour.print("HandleRewardedAdLoaded event received");
}
public void HandleRewardedAdFailedToLoad(object sender, AdErrorEventArgs args)
{
MonoBehaviour.print(
"HandleRewardedAdFailedToLoad event received with message: " + args.Message);
this.reqRewardedAdVideo = true;
}
public void HandleRewardedAdOpening(object sender, EventArgs args)
{
MonoBehaviour.print("HandleRewardedAdOpening event received");
}
public void HandleRewardedAdFailedToShow(object sender, AdErrorEventArgs args)
{
MonoBehaviour.print(
"HandleRewardedAdFailedToShow event received with message: " + args.Message);
}
public void HandleRewardedAdClosed(object sender, EventArgs args)
{
MonoBehaviour.print("HandleRewardedAdClosed event received");
this.reqRewardedAdVideo = true;
}
public void HandleUserEarnedReward(object sender, Reward args)
{
string type = args.Type;
double amount = args.Amount;
rewardAmount = (int)amount;
MonoBehaviour.print(
"HandleRewardedAdRewarded event received for "
+ amount.ToString() + " " + type);
}
#endregion
}
将上述脚本放在 Hierachy 中的 GameObject 上
Place the above script on a GameObject in Hierachy
调用广告使用
adMob.ins.DestroyBanner();
或任何其他功能(声明静态ins并引用游戏对象称为单例模式,用于声音管理器、场景管理器、添加管理器等管理器)
or any other function ( declaring a static ins and referring the gameobject is known as singleton pattern, which is used in Managers like sound manager, Scene Manager, Add Managers )
adMob.ins._Your-Function-Name_();
你需要在使用后取消订阅事件句柄,否则你会得到意想不到的行为:
You need to unsubscribe handles from events after using it or you will get unexpected behaviours:
void OnDestroy()
{
// Called when an ad request has successfully loaded.
rewardBasedVideo.OnAdLoaded -= HandleRewardBasedVideoLoaded;
// Called when an ad request failed to load.
rewardBasedVideo.OnAdFailedToLoad -= HandleRewardBasedVideoFailedToLoad;
// Called when an ad is shown.
rewardBasedVideo.OnAdOpening -= HandleRewardBasedVideoOpened;
// Called when the ad starts to play.
rewardBasedVideo.OnAdStarted -= HandleRewardBasedVideoStarted;
// Called when the user should be rewarded for watching a video.
rewardBasedVideo.OnAdRewarded -= HandleRewardBasedVideoRewarded;
}
以 OnDestroy 方法为例.
Do it in OnDestroy method, for example.
这篇关于在 Unity 中重新加载场景后多次调用 Google Admob Reward Video 回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!