質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

3084閲覧

2つの広告が重なって表示されてしまう。 (ipadで試した場合)

sukiyakigozens

総合スコア28

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2018/04/20 12:35

編集2018/04/22 13:37

やりたい事
Admobのバナー広告が(通信環境により)表示されない場合、
3秒毎に再度広告表示をリクエストして、できるだけ表示させるようにしたい。
(Awakeでバナー広告を一番先に読み込んでおりますが、
広告が表示されない事がある為、
Awakeで読み込めなかった場合に、再度広告表示のリクエストをして表示させたい)

下記のスクリプトで広告が表示されていない場合は、
3秒ごとに表示のリクエストをするようにできました。

問題
2つの広告が重なって表示されてしまう。(ipad mini / iPad airで試した場合)
※バナー広告だけ読み込んでおります。
(Admob側の広告ユニット番号の申請もバナー広告のみしかしておりません)

下の添付写真のように左上の小さい広告と背後にバナー広告が重なって表示されてしまいます。
(常時ではないが、ごくたまに起こります)

イメージ説明

推測ですが、左上の小さい広告も一応、バナー広告扱いのようです。
問題は表示のリフレッシュがうまくいってないようです。

  1. 最初の広告が出力される。
  2. アドモブ側が自動的に次の広告にリフレッシュしようとする時に、

  次の広告のデータを受け取れない。(通信環境により)
そして最初の広告が表示されっぱなしになる。
3. その間、下記スクリプトの3秒ごとの広告表示リクエストが実行されており、(Invoke("RequestBanner",3.0f);)
リクエストが成功した時、2番目の広告が表示されるが、
下の広告が表示されたままで、上に重なってしまっている。

結果的に2番目の広告が小さい場合、後ろ側の通常のサイズのバナー広告が一緒に見えてしまう。

もし次の広告への再リクエストが失敗したとしても、
その時点で、現在表示されている広告を削除するのは避けたいです。
(空欄になるより最初の広告を残しておきたい。)

質問
どうにか、次の広告が表示される時だけ、
元の広告を削除するようにできませんでしょうか?

または、
小さな広告は表示させない、
または
小さな広告を通常バナー広告サイズまで拡大するような
制御はできませんでしょうか?

ご教授よろしくおねがいいたします。

using UnityEngine; using System.Collections; using GoogleMobileAds; using GoogleMobileAds.Api; using System; public class AdScript : MonoBehaviour { void Awake() { // イニシャライズ #if UNITY_ANDROID MobileAds.Initialize("ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"); #endif // #if UNITY_IOS MobileAds.Initialize("ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"); #endif // DontDestroyOnLoad (this); // バナー広告を表示 RequestBanner (); } private void RequestBanner() { // string adUnitId = "INSERT_ANDROID_BANNER_AD_UNIT_ID_HERE"; #if UNITY_ANDROID string adUnitId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; // string adUnitId = "INSERT_IOS_BANNER_AD_UNIT_ID_HERE"; #elif UNITY_IOS string adUnitId = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; // #else string adUnitId = "unexpected_platform"; #endif // Create a smart banner at the bottom of the screen. BannerView bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Bottom); // BannerView bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Bottom); // Create an empty ad request. AdRequest request = new AdRequest.Builder().Build(); // Load the banner with the request. bannerView.LoadAd(request); // Called when an ad request has successfully loaded. bannerView.OnAdLoaded += HandleOnAdLoaded; // Called when an ad request failed to load. bannerView.OnAdFailedToLoad += HandleOnAdFailedToLoad; } //広告が表示されてない場合 public void HandleOnAdFailedToLoad(object sender, AdFailedToLoadEventArgs args)   { Invoke ("RequestBanner", 3.0f);//3秒送らせて再度バナー表示トライ Debug.Log ("広告表示なし 再トライ"); } //広告が表示された場合 public void HandleOnAdLoaded(object sender, EventArgs args) { Debug.Log ("広告が表示されました"); } }

[追記]いただいた回答を元に修正して書き換えてみました。
広告が表示されてない場合の処理(HandleOnAdFailedToLoad)に追記しました。

using UnityEngine; using System.Collections; using GoogleMobileAds; using GoogleMobileAds.Api; using System; /// /// public class AdScript : MonoBehaviour { // RequestBannerを呼ぶまでの待機時間 public static readonly float REQUEST_INTERVAL = 3; BannerView bannerView; bool IsLoaded; float WaitingForRequestTime; string APP_ID { get { #if UNITY_ANDROID return "ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx"; #elif UNITY_IOS return "ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx"; #endif } } string BANNER_ID { get { #if UNITY_ANDROID return "ca-app-pub-xxxxxxxxxxxxxxxx/xxxxxxxxxx"; #elif UNITY_IOS return "ca-app-pub-xxxxxxxxxxxxxxxx/xxxxxxxxxx"; #endif } } void Awake() { // イニシャライズ MobileAds.Initialize(APP_ID); DontDestroyOnLoad(this); // バナー広告を表示 RequestBanner(); } void Update() { //「広告が読み込み完了していない」且つ「RequestBannerを呼ぶまでの待機時間」が0以上なら処理開始 if(!IsLoaded && WaitingForRequestTime > 0) // 3、2、1の間だけupdadeが実行される { //WaitingForRequestTimeが0になるまでTime.deltaTimeで引き続ける WaitingForRequestTime -= Time.deltaTime; // 3から1づつ引いていく //0になったらRequestBannerを呼ぶ if(WaitingForRequestTime <= 0) RequestBanner(); // 0で実行 } } private void RequestBanner() { IsLoaded = false; //※すでに存在すれば一度破棄する if(bannerView != null) bannerView.Destroy(); // Create a smart banner at the bottom of the screen. bannerView = new BannerView(BANNER_ID, AdSize.SmartBanner, AdPosition.Bottom); // Create an empty ad request. AdRequest request = new AdRequest.Builder().Build(); // Load the banner with the request. bannerView.LoadAd(request); // // // Called when an ad request has successfully loaded. bannerView.OnAdLoaded += HandleOnAdLoaded; // Called when an ad request failed to load. bannerView.OnAdFailedToLoad += HandleOnAdFailedToLoad; } //広告が表示されてない場合 public void HandleOnAdFailedToLoad(object sender, AdFailedToLoadEventArgs args) { // WaitingForRequestTime = REQUEST_INTERVAL;//初期値3にもどす // Debug.Log("広告表示なし 再トライ"); IsLoaded = false; // ネットワークにアクセス可能かどうかを取得する switch (Application.internetReachability) { //再トライなし case NetworkReachability.NotReachable: Debug.Log( "ネットワークが使えない 広告表示なし 再トライなし" ); break; case NetworkReachability.ReachableViaCarrierDataNetwork: Debug.Log( "キャリアネットワークでアクセス可能 再トライ" ); WaitingForRequestTime = REQUEST_INTERVAL;//初期値3にもどす break; case NetworkReachability.ReachableViaLocalAreaNetwork: Debug.Log( "WiFi でアクセス可能 再トライ" ); WaitingForRequestTime = REQUEST_INTERVAL;//初期値3にもどす break; } } //広告が表示された場合 public void HandleOnAdLoaded(object sender, EventArgs args) { IsLoaded = true; Debug.Log("広告が表示されました"); } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

[追記]回答が間違っていたので変更します。

申し訳ありません。Invokeをループ処理と勘違いしておりましたので回答を大幅に変更させていただきます。

今の問題は、Invokeが呼ばれた後にバナー広告が読み込み完了してもInvokeは止まらず別のバナーを生成してしまうということが問題かと思います。それを防ぐのは簡単ですがInvokeを使うことは避けた方が良いのでUpdateでチェックすると良いと思います。処理は下記のようになります。

  1. 広告リクエストが失敗して3秒後にRequestBannerを呼ぶ
  2. 待機時間の3秒以内に広告が呼ばれた場合終了する
  3. 更に失敗した場合1からやり直す

C#

1using UnityEngine; 2using GoogleMobileAds; 3using GoogleMobileAds.Api; 4using System; 5 6public class AdScript : MonoBehaviour 7{ 8 string APP_ID 9 { 10 get 11 { 12 #if UNITY_ANDROID 13 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 14 #elif UNITY_IOS 15 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 16 #endif 17 } 18 } 19 20 string BANNER_ID 21 { 22 get 23 { 24 #if UNITY_ANDROID 25 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 26 #elif UNITY_IOS 27 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 28 #endif 29 } 30 } 31 32 /// <summary> 33 /// RequestBannerを呼ぶまでの待機時間 34 /// </summary> 35 public static readonly float REQUEST_INTERVAL = 3; 36 37 BannerView bannerView; 38 bool IsLoaded; 39 float WaitingForRequestTime; 40 41 void Awake() 42 { 43 // イニシャライズ 44 MobileAds.Initialize(APP_ID); 45 DontDestroyOnLoad(this); 46 // バナー広告を表示 47 RequestBanner(); 48 } 49 50 void Update() 51 { 52 //「広告が読み込み完了していない」且つ「RequestBannerを呼ぶまでの待機時間」が0以上なら処理開始 53 if(!IsLoaded && WaitingForRequestTime > 0) 54 { 55 //WaitingForRequestTimeが0になるまでTime.deltaTimeで引き続ける 56 WaitingForRequestTime -= Time.deltaTime; 57 //0になったらRequestBannerを呼ぶ 58 if(WaitingForRequestTime <= 0) RequestBanner(); 59 } 60 } 61 62 void RequestBanner() 63 { 64 IsLoaded = false; 65 66 //※すでに存在すれば一度破棄する 67 if (bannerView != null) bannerView.Destroy(); 68 69 // Create a smart banner at the bottom of the screen. 70 bannerView = new BannerView(BANNER_ID, AdSize.SmartBanner, AdPosition.Bottom); 71 // BannerView bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Bottom); 72 73 // Create an empty ad request. 74 AdRequest request = new AdRequest.Builder().Build(); 75 76 // Load the banner with the request. 77 bannerView.LoadAd(request); 78 79 // Called when an ad request has successfully loaded. 80 bannerView.OnAdLoaded += HandleOnAdLoaded; 81 // Called when an ad request failed to load. 82 bannerView.OnAdFailedToLoad += HandleOnAdFailedToLoad; 83 } 84 85 //広告が表示されてない場合 86 public void HandleOnAdFailedToLoad(object sender, AdFailedToLoadEventArgs args) 87 { 88 IsLoaded = false; 89 WaitingForRequestTime = REQUEST_INTERVAL; 90 Debug.Log("広告表示なし 再トライ"); 91 } 92 93 //広告が表示された場合 94 public void HandleOnAdLoaded(object sender, EventArgs args) 95 { 96 IsLoaded = true; 97 Debug.Log("広告が表示されました"); 98 } 99}

[追記]以下は過去の間違った回答です。

申し訳ないですが今の実装はやめた方がよいと思います。理由は2点あります。

  1. Admobは広告の表示回数を考慮して報酬を支払うので複数回取得する事で偽装だと認識されてしまった場合最悪垢バンされる。
  2. 垢バンされなかったとしても、表示数に対してクリック数が低いと収益が下がる可能性がある。ちなみに誤クリックしやすい位置でも収益は下がる。

といった理由から今の実装はやめた方がよいと思います。
1の「複数回取得する事で偽装」というのは完全に予想ですが何度も取得するということはサーバーの負荷にも繋がりAdmobにとって良いことは無いので何かしら対策を打ってくるのではと思います。

表示されなければ取得し直すだけで留めていた方が無難かと思います。

C#

1using UnityEngine; 2using System.Collections; 3using GoogleMobileAds; 4using GoogleMobileAds.Api; 5using System; 6 7public class AdScript : MonoBehaviour 8{ 9 string APP_ID 10 { 11 get 12 { 13 #if UNITY_ANDROID 14 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 15 #elif UNITY_IOS 16 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 17 #endif 18 } 19 } 20 21 string BANNER_ID 22 { 23 get 24 { 25 #if UNITY_ANDROID 26 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 27 #elif UNITY_IOS 28 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 29 #endif 30 } 31 } 32 33 BannerView bannerView; 34 35 void Awake() 36 { 37 // イニシャライズ 38 MobileAds.Initialize(APP_ID); 39 40 DontDestroyOnLoad(this); 41 // バナー広告を表示 42 RequestBanner(); 43 } 44 45 void RequestBanner() 46 { 47 //※すでに存在すれば一度破棄する 48 if(bannerView != null) bannerView.Destroy(); 49 50 // Create a smart banner at the bottom of the screen. 51 bannerView = new BannerView(BANNER_ID, AdSize.SmartBanner, AdPosition.Bottom); 52 // BannerView bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Bottom); 53 54 // Create an empty ad request. 55 AdRequest request = new AdRequest.Builder().Build(); 56 57 // Load the banner with the request. 58 bannerView.LoadAd(request); 59 60 // Called when an ad request has successfully loaded. 61 bannerView.OnAdLoaded += HandleOnAdLoaded; 62 // Called when an ad request failed to load. 63 bannerView.OnAdFailedToLoad += HandleOnAdFailedToLoad; 64 } 65 66 //広告が表示されてない場合 67 public void HandleOnAdFailedToLoad(object sender, AdFailedToLoadEventArgs args) 68 { 69 RequestBanner(); 70 Debug.Log("広告表示なし 再トライ"); 71 } 72 73 //広告が表示された場合 74 public void HandleOnAdLoaded(object sender, EventArgs args) 75 { 76 Debug.Log("広告が表示されました"); 77 } 78}

ゲーム画面表示と同時にバナー広告を表示したい場合

画面表示と広告表示のタイミングを合わせたいのでしたらロード画面を挟むのが簡単ですしユーザーにも優しいと思います。

今回は、見やすく一つのコードに押し込みましたがシーンのロードと広告のスクリプトは別けた方が良いです。そして、コードは未検証です。ゲーム起動時にロード画面を読み込むようにし完了後遷移させる形です。

C#

1using UnityEngine; 2using System.Collections; 3using GoogleMobileAds; 4using GoogleMobileAds.Api; 5using System; 6using UnityEngine.SceneManagement; 7 8public class LoadBannerScene : MonoBehaviour 9{ 10 string APP_ID 11 { 12 get 13 { 14 #if UNITY_ANDROID 15 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 16 #elif UNITY_IOS 17 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 18 #endif 19 } 20 } 21 22 string BANNER_ID 23 { 24 get 25 { 26 #if UNITY_ANDROID 27 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 28 #elif UNITY_IOS 29 return "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX"; 30 #endif 31 } 32 } 33 34 /// <summary> 35 /// 広告がロードされないとアプリが立ち上がらないので最大待ち時間を設定しておく 36 /// 待っても表示されなければ諦めるスタイルです。 37 /// </summary> 38 static readonly float WAITING_FOR_LOAD_TIME_LIMIT = 10; 39 40 BannerView bannerView; 41 bool BannerIsLoaded; 42 float WaitingForLoadTime; 43 44 void Awake() 45 { 46 // イニシャライズ 47 MobileAds.Initialize(APP_ID); 48 49 DontDestroyOnLoad(this); 50 // バナー広告を表示 51 RequestBanner(); 52 } 53 54 IEnumerator Start() 55 { 56 //シーンを非同期で読込 57 AsyncOperation async = SceneManager.LoadSceneAsync(NEXT_SCENE); 58 async.allowSceneActivation = false; 59 60 //制限時間の間バナーの表示を待つ 61 while(!BannerIsLoaded && WaitingForLoadTime < WAITING_FOR_LOAD_TIME_LIMIT) 62 { 63 //現在のロード進捗を表示することもできます。 64 //var progressStg = string.Format("ロード中... {0}%", async.progress * 100); 65 66 WaitingForLoadTime += Time.deltaTime; 67 yield return null; 68 } 69 70 //シーンのロードを待つ 71 while(async.progress < 0.9f) yield return null; 72 73 //バナー表示 74 bannerView.Show(); 75 76 async.allowSceneActivation = true; 77 } 78 79 void RequestBanner() 80 { 81 //※すでに存在すれば一度破棄する 82 if(bannerView != null) bannerView.Destroy(); 83 84 // Create a smart banner at the bottom of the screen. 85 bannerView = new BannerView(BANNER_ID, AdSize.SmartBanner, AdPosition.Bottom); 86 // BannerView bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Bottom); 87 88 // Create an empty ad request. 89 AdRequest request = new AdRequest.Builder().Build(); 90 91 // Load the banner with the request. 92 bannerView.LoadAd(request); 93 94 //※ローディング中に表示しないように一度隠しておく 95 bannerView.Hide(); 96 97 // Called when an ad request has successfully loaded. 98 bannerView.OnAdLoaded += HandleOnAdLoaded; 99 // Called when an ad request failed to load. 100 bannerView.OnAdFailedToLoad += HandleOnAdFailedToLoad; 101 } 102 103 //広告が表示されてない場合 104 public void HandleOnAdFailedToLoad(object sender, AdFailedToLoadEventArgs args) 105 { 106 RequestBanner(); 107 Debug.Log("広告表示なし 再トライ"); 108 } 109 110 //広告が表示された場合 111 public void HandleOnAdLoaded(object sender, EventArgs args) 112 { 113 BannerIsLoaded = true; 114 Debug.Log("広告が表示されました"); 115 } 116}

最後に

ご存知かと思いますがAdmobのオブジェクトはシーン遷移で消えてほしくないのでシングルトンにしておくと良いと思います。

投稿2018/04/21 08:18

編集2018/04/21 18:47
IShix

総合スコア1724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sukiyakigozens

2018/04/21 10:48

ご返答、大変ありがとうございます。 「一度破棄する」の追加により、広告が重なることはなくなりました。 すいませんが、質問させてください。 仮に通信環境がない場所でアプリを開いた場合、(本当は望ましくないですが) 広告が表示されないので 早いサイクルで「RequestBanner();」が呼ばれてしまうので、 (メモリが圧迫されてしまうので) Invoke ("RequestBanner", 5.0f);として 間隔を開けて呼ばれるようにしても問題ないでしょうか? すいませんが、よろしくおねがいいたします。
IShix

2018/04/21 13:48 編集

申し訳ありません。間違った回答をしてしまいました。 追記しましたのでごらんください。
IShix

2018/04/21 13:33 編集

Invokeは使わない方が良いAPIの代表なものです。 理由は文字列で指定する為、動かすまでエラーが発見しにくくバグに繋がりやすいからです。今回の新しい回答ではシンプルなのでUpdateで実装しましたが複雑な場合はCoroutineを使うと良いと思います。 Coroutineの使い方はこちらの記事が大変参考になります。 http://tsubakit1.hateblo.jp/entry/2015/04/06/060608
sukiyakigozens

2018/04/21 15:08

ご回答大変ありがとうございます。 上部に追記してみました。 広告が表示されてない場合の処理内に(HandleOnAdFailedToLoad) IsLoaded = false; を加えました。 一度広告を受け取って、IsLoaded = true; になりますが、 通信が不安定な場所の場合、広告を受け取れたり受け取れなかったりする場合があると思います。 IsLoaded = true; のままでは update(再リクエスト) が実行されないので、 falseを追加しました。 もし何か問題ありましたら、お知らせいただけないでしょうか? すいませんが、よろしくおねがいいたします。
IShix

2018/04/21 18:46

失礼しました。そのタイミングでもIsLoaded = false; していた方が良いとおもいます。
sukiyakigozens

2018/04/21 19:11

何度もご返答、ありがとうございました。 大変感謝しております。
sukiyakigozens

2018/04/22 04:42 編集

すいません、今きづきましたが、 仮に一度広告を取得できれば、(広告が1度表示されれば) Admobの自動のリフレッシュ機能が働いてくれるので、(たぶん60秒後) スクリプト側で広告を再リクエストはする必要はないようです。 仮に途中で通信が途切れたとしても、通信が再開されたら、 既存広告がリフレッシュされて更新されるようです。 (スクリプトで広告を削除してしまったら、更新はされないと思われます) しかしながら、 通信できない場所でアプリを立ち上げ、 (広告表示されない) その後通信可能な場所に移動した場合は、 広告が出てないので、Admobの自動のリフレッシュ機能が効かないので、 再リクエストしないと、いつまで待っても広告は表示されません。 従ってスクリプト側で再リクエストをする意味はあると思います。 問題は再リクエストの間隔で1秒以内などあまり短くすると スマホのメモリが圧迫されると思われます。 以上、推測も入っております。
sukiyakigozens

2018/04/22 09:25 編集

すいません、追記させてください。 上記の通信できない場所でアプリを立ち上げた場合ですが、 後から通信可能な場所へ移動したとしても、 今回のスクリプトでは広告は読まれませんでした。 失礼しました。 結果的に今回のスクリプトは 広告の配信が遅い場合に再リクエストするには意味があると思われますが、 広告配信が問題なく流れていれば再リクエストする意味は あまりないかもしれません。 (普通のやり方の Awake で1回だけの表示リクエストするのと、あまりか差がないかもしれません)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問