導入事例

Ad Placement API は、ウェブまたはアプリでプレイする HTML5 ベースのゲームでインタースティシャル広告とリワード広告を使用する AdSense と AdMob のデベロッパー向けに設計されています。この例では、Ad Placement API をゲームに統合し、インタースティシャル広告を配置する方法を示します。

前提条件

前提条件は次のとおりです。

  • 同じディレクトリに空のファイルを 2 つ作成します。
    • index.html
    • game.js
  • Python をローカルにインストールするか、ウェブサーバーを使用して実装をテストします。

アプリのサンプルコード

アプリ コードのサンプルをダウンロードすると、API をゲームアプリに組み込む方法を詳細に把握することができます。

アプリのサンプルコードをダウンロード

1. 開発用サーバーを起動する

Ads Placement API は、読み込まれるページと同じプロトコルを介して依存関係を読み込むため、ウェブサーバーを使用してアプリをテストする必要があります。Python の組み込みサーバーを使用して、ローカル開発環境を作成できます。

  1. ターミナルを開きます。

  2. index.html ファイルが格納されているディレクトリに移動して、次のコマンドを実行します。

    python -m http.server 8000
    
  3. ウェブブラウザで localhost:8000 にアクセスします。

Apache HTTP Server などの他のウェブサーバーも使用できます。

2. HTML5 ゲームを作成する

HTML5 キャンバス要素とゲームプレイをトリガーするボタンを作成するように index.html を変更します。次に、必要なスクリプトタグを追加して、game.js ファイルを読み込みます。

index.html

<!doctype html>
<html lang="en">
  <head>
    <title>Ad Placement API HTML5 demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <canvas id="gameContainer" height="300px" width="300px"></canvas>
    <br>
    <button id="playButton">Play</button>
    <button style="display:none" id="headsButton">Heads</button>
    <button style="display:none" id="tailsButton">Tails</button>

    <script src="game.js"></script>
  </body>
</html>

[Play] ボタンがクリックされたときに、coin flip(コイントス)ゲームを開始するように game.js を変更します。

game.js

// Create a coin flip game
class Game {
  constructor() {
    // Define variables
    this.score = 0;
    this.choice = '';

    this.canvas = document.getElementById('gameContainer').getContext('2d');
    this.canvas.font = '24px Arial';

    this.playButton = document.getElementById('playButton');
    this.headsButton = document.getElementById('headsButton');
    this.tailsButton = document.getElementById('tailsButton');

    // On click listeners for the game's buttons.
    this.playButton.addEventListener('click', () => {
      this.erase();
      this.play();
    });

    this.headsButton.addEventListener('click', () => {
      this.choice = 'Heads';
      this.flipCoin();
    });

    this.tailsButton.addEventListener('click', () => {
      this.choice = 'Tails';
      this.flipCoin();
    });

    this.erase();
  }

  // Start the game
  play() {
    this.score = 0;
    this.canvas.fillText('Score: ' + this.score, 8, 26);
    this.canvas.fillText('Heads or Tails?', 66, 150);
    this.playButton.style.display = 'none';
    this.headsButton.style.display = 'inline-block';
    this.tailsButton.style.display = 'inline-block';
  }

  // Flip the coin
  flipCoin() {
    this.headsButton.disabled = true;
    this.tailsButton.disabled = true;
    this.erase();
    this.canvas.fillText('Score: ' + this.score, 8, 26);
    this.canvas.fillText('Flipping coin . . .', 60, 150);

    setTimeout(() => { this.coinLanded() }, 2000);
  }

  // Logic for when the coin lands
  coinLanded() {
    this.headsButton.disabled = false;
    this.tailsButton.disabled = false;
    let sideUp;
    if(Math.random() < 0.5) {
      sideUp = 'Heads';
    } else {
      sideUp = 'Tails';
    }

    if (sideUp === this.choice ) {
      this.win(sideUp);
    } else {
      this.lose(sideUp);
    }
  }

  // Guess the flip correctly
  win(sideUp) {
    this.erase();
    this.score += 1;
    this.canvas.fillText('Score: ' + this.score, 8, 26);
    this.canvas.fillText('It was ' + sideUp + '!', 66, 150);
    this.canvas.fillText('Guess again', 70, 200);
  }

  // Guess the flip incorrectly
  lose(sideUp) {
    this.erase();
    this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
    this.canvas.fillText('Your score was ' + this.score, 50, 150);
    this.canvas.fillText('Want to play again?', 45, 200);

    this.playButton.style.display = 'inline-block';
    this.headsButton.style.display = 'none';
    this.tailsButton.style.display = 'none';
  }

  // Erase the canvas
  erase() {
    this.canvas.fillStyle = '#ADD8E6';
    this.canvas.fillRect(0, 0, 300, 300);
    this.canvas.fillStyle = '#000000';
  }
}

const game = new Game();

この手順を完了したら、開発用サーバーを介してブラウザで index.html を開くと、ゲーム キャンバスと「Play」ボタンが表示されるようになります。[Play] をクリックすると、コイントス ゲームが始まります。

3. Ad Placement API をインポートする

index.html で、game.js のタグの前にスクリプトタグを挿入して、ゲームに Ad Placement API を追加します。

スクリプトタグはさまざまなパラメータを取ることができます。次のパラメータを使用して、AdSense のプロパティ コードを指定し、テストモードを有効にします。

  • data-ad-client=<AdSense property code> お客様の AdSense プロパティ コードです。これは、アプリ内で実行されるゲームでも必ず必要です。
  • data-adbreak-test="on" テストモードを有効にします。ゲームがプレーヤーに配信されるようになったら、このパラメータは削除します。

AdSense コードを設定し、テストモードをオンにする

Ad Placement API 機能は、AdSense コードに含まれています。オンにするには、まず AdSense コードを追加し、2 つの主要関数(adBreak()adConfig())を初期化する小さなスクリプト スニペットを追加します。

index.html(ウェブ)

 [...]
    <canvas id="gameContainer" height="300px" width="300px"></canvas>
    <br>
    <button id="playButton">Play</button>
    <button style="display:none" id="headsButton">Heads</button>
    <button style="display:none" id="tailsButton">Tails</button>

    <script async
      data-adbreak-test="on"
      src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
      crossorigin="anonymous">
    </script>
    <script>
      window.adsbygoogle = window.adsbygoogle || [];
      const adBreak = adConfig = function(o) {adsbygoogle.push(o);}
    </script>
    <script src="game.js"></script>
  </body>
</html>

ゲームの埋め込み(省略可)

iframe 内の他のページにゲームを埋め込む場合で、adsbygoogle タグがゲームの HTML ページ内にある場合は、必ず iframe 要素に allow='autoplay' を追加してください。これはベスト プラクティスであり、一部の広告をゲームに配置するための必要条件となります。

<head>
  <!-- The adsbygoogle tag is not here -->
</head>
<body>
  <iframe src="https://www.my-game.com" title="My game" allow="autoplay">
    <!-- The game is loaded here and contains the adsbygoogle tag -->
  </iframe>
</body>

モバイルアプリをサポートする

H5 ゲームは、通常のウェブブラウザ、WebView、またはアプリ内の Chrome カスタムタブで実行できます。Ad Placement API を使用すると、ゲームが動作している環境を検出し、広告リクエストを適切に転送できます。ゲームが通常のウェブブラウザ内で実行されている場合、広告リクエストは通常の AdSense リクエストとして扱われます。Ad Placement API がアプリ内環境を検出すると、Google Mobile Ads SDK と通信し、Google Mobile Ads SDK が存在する場合は、AdMob 広告をリクエストして、表示します。

この機能は Google Mobile Ads SDK にリンクされている Android アプリでサポートされています。有効にするには、Google Mobile Ads SDK でゲームを表示する WebView を登録し、AdMob 広告ユニットを設定して、追加のパラメータとして AdSense タグに渡す必要があります。ゲームが適切なアプリ内で実行された場合、Ad Placement API はこれらの広告ユニットを使用して広告を表示します。

モバイル サポートを有効にするには、次の追加のタグパラメータを指定する必要があります。

  • data-admob-interstitial-slot=<AdMob slot ID> 設定済みの AdMob インタースティシャル広告ユニット ID。
  • data-admob-rewarded-slot=<AdMob slot ID> AdMob リワード広告ユニット ID。

AdSense のプロパティ コードは常に data-ad-client パラメータとともに渡し、data-admob-interstitial-slot または data-admob-rewarded-slot のうち少なくとも 1 つを指定する必要があります。ゲームで両方のフォーマットを使用する場合は、両方のパラメータを指定する必要があります。

data-admob-ads-only=on タグパラメータを指定すると、ユーザーが AdMob のリクエストに対応していない環境(例: アプリ以外の環境、Google Mobile Ads SDK が設定されていないアプリ)でゲームをプレイする際に、AdMob の広告のみをゲームに表示して、AdSense の広告は表示されないようにすることもできます。

重要: お客様がゲームをアプリに埋め込む形で設計し、そのアプリを所有している場合(またはアプリの所有者と収益分配契約を締結している場合)、ポリシーに準拠しつつ高いパフォーマンスを実現するには、必ずこのモバイルアプリ向け AdMob サポートをご利用ください。

まずは、Google Mobile Ads SDK でゲームを表示する WebView を登録します。

MainActivity.java(アプリ)

Default WebView settings are not optimized for ads. Use the WebSettings APIs to configure your WebView for:

  • JavaScript
  • Access to local storage
  • Automatic video play

Java

import android.webkit.CookieManager;
import android.webkit.WebView;

public class MainActivity extends AppCompatActivity {
  private WebView webView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    webView = findViewById(R.id.webview);

    // Let the web view accept third-party cookies.
    CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
    // Let the web view use JavaScript.
    webView.getSettings().setJavaScriptEnabled(true);
    // Let the web view access local storage.
    webView.getSettings().setDomStorageEnabled(true);
    // Let HTML videos play automatically.
    webView.getSettings().setMediaPlaybackRequiresUserGesture(false);

    // Set the H5AdsWebViewClient.
    h5AdsWebViewClient = new H5AdsWebViewClient(this, webView);
    webView.setWebViewClient(h5AdsWebViewClient);
    h5AdsWebViewClient.setDelegateWebViewClient(pubWebViewClient);

    // Register the web view.
    MobileAds.registerWebView(webView);
  }
}

Kotlin

import android.webkit.CookieManager
import android.webkit.WebView

class MainActivity : AppCompatActivity() {
  lateinit var webView: WebView

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    webView = findViewById(R.id.webview)

    // Let the web view accept third-party cookies.
    CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true)
    // Let the web view use JavaScript.
    webView.settings.javaScriptEnabled = true
    // Let the web view access local storage.
    webView.settings.domStorageEnabled = true
    // Let HTML videos play automatically.
    webView.settings.mediaPlaybackRequiresUserGesture = false

    // Set the H5AdsWebViewClient.
    val h5AdsWebViewClient = H5AdsWebViewClient(this, webView)
    webView.webViewClient = h5AdsWebViewClient
    h5AdsWebViewClient.delegateWebViewClient = pubWebViewClient

    // Register the web view.
    MobileAds.registerWebView(webView)
  }
}

次に、AdMob 広告ユニット(インタースティシャル用とリワード広告用)を次のように渡します。

index.html(アプリ)

 [...]
    <canvas id="gameContainer" height="300px" width="300px"></canvas>
    <br>
    <button id="playButton">Play</button>
    <button style="display:none" id="headsButton">Heads</button>
    <button style="display:none" id="tailsButton">Tails</button>
    <script async
      data-admob-interstitial-slot="ca-app-pub-0987654321/1234567890"
      data-admob-rewarded-slot="ca-app-pub-0987654321/0987654321"
      src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
      crossorigin="anonymous">
    </script>
    <script>
      window.adsbygoogle = window.adsbygoogle || [];
      const adBreak = adConfig = function(o) {adsbygoogle.push(o);}
    </script>
    <script src="game.js"></script>
  </body>
</html>

4.adConfig() を呼び出す

adConfig() の呼び出しにより、ゲームの現在の設定が Ad Placement API に伝えられます。API はこの情報を使用して、リクエストする広告の種類をフィルタし、ゲームに適したもの(音声が有効であれば、音声が必要な動画広告など)を選別します。

adConfig() の呼び出しは、ゲームアプリが初期化された場合や、設定が変更された場合(ユーザーがゲームをミュートまたはミュート解除したときなど)に、必ず行う必要があります。具体的には、ゲームのコンストラクタで adConfig() を呼び出してから、広告をミュート / ミュート解除するボタンを追加し、そのボタンの動作の中でさらに adConfig() を呼び出します。

game.js

class Game {
  constructor() {
    // Define variables
    this.score = 0;
    this.choice = '';
    this.muted = false;

    this.canvas = document.getElementById('gameContainer').getContext('2d');
    this.canvas.font = '24px Arial';

    this.playButton = document.getElementById('playButton');
    this.headsButton = document.getElementById('headsButton');
    this.tailsButton = document.getElementById('tailsButton');
    this.muteButton = document.getElementById('muteButton');

    adConfig({
      sound: 'on',
    });

    // On click listeners for the game's buttons.
    this.playButton.addEventListener('click', () => {
      this.erase();
      this.play();
    });

    this.headsButton.addEventListener('click', () => {
      this.choice = 'Heads';
      this.flipCoin();
    });

    this.tailsButton.addEventListener('click', () => {
      this.choice = 'Tails';
      this.flipCoin();
    });

    this.muteButton.addEventListener('click', () => {
      var soundString = this.muted ? 'on' : 'off';
      this.muteButton.innerHTML = this.muted ? 'Mute sound' : 'Un-mute sound';
      this.muted = !this.muted;
      adConfig({
        sound: soundString,
      });
    });

    this.erase();
  [...]

ミュートボタンを HTML ファイルに追加します。

index.html

[...]
    <canvas id="gameContainer" height="300px" width="300px"></canvas>
    <br>
    <button id="playButton">Play</button>
    <button style="display:none" id="headsButton">Heads</button>
    <button style="display:none" id="tailsButton">Tails</button>
    <button id="muteButton">Mute sound</button>

    <script async
      data-adbreak-test="on"
      src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
      crossorigin="anonymous">
    </script>
[...]

5. ゲームの終了時に adBreak() を呼び出す

adBreak() 呼び出しは広告プレースメントを定義し、プレースメント設定と呼ばれるオブジェクトを受け取ります。このオブジェクトにより、その時点でゲームに広告を表示するために必要な要素がすべて指定されます。さまざまなタイプの広告に対応するには、プレースメント設定のさまざまなサブセットを初期化する必要があります。

adBreak() 呼び出しは、広告を表示できる可能性のあるプレースメント、つまり広告を表示する機会を定義します。広告が実際に表示されるかどうかは、次のさまざまな要素によって決まります。

  • 宣言した広告プレースメントのタイプ。
  • この広告プレースメントの前に適切なユーザー インタラクションがあったかどうか。
  • 現在のプレーヤーに適した広告が存在するかどうか。適した広告とは次のような広告のことです。
    • ユーザーに関係がある。
    • データのプライバシーと同意に関するユーザー設定と一致している。
  • ユーザーに最近表示された広告の数。
  • このゲームに設定したコントロール設定。次のいずれかです。
    • タグ内のヒント。
    • AdSense(注: AdSense で利用可能なコントロールは今後さらに改良が加えられます)

ゲームの再起動時に表示するインタースティシャル広告のコードを追加します。このコードでは、play() 関数内で adBreak() を呼び出します。この関数は、ゲームが 1 回プレイされた後のみ実行されます。

adBreak() は、「プレイ」ボタンのクリックなど、ユーザー アクションの一部として呼び出す必要があります。そうでない場合、API は広告をリクエストし表示することができません。

広告ブレークの前後に呼び出す関数を作成します。この関数は、adBreak() プレースメント設定で使用します。beforeAd 関数と afterAd 関数は、適切な広告が見つかった場合にのみ呼び出されることに留意してください。

game.js

class Game {
  constructor() {
    // Define variables
    this.score = 0;
    this.choice = '';
    this.muted = false;
    this.shouldShowAdOnPlay = false;

  [...]

  // Start the game
  play() {
    if (this.shouldShowAdOnPlay) {
      this.shouldShowAdOnPlay = false;

      adBreak({
        type: 'next',  // ad shows at start of next level
        name: 'restart-game',
        beforeAd: () => { this.disableButtons(); },  // You may also want to mute the game's sound.
        afterAd: () => { this.enableButtons(); },    // resume the game flow.
      });
    }

    this.score = 0;
    this.canvas.fillText('Score: ' + this.score, 8, 26);
    this.canvas.fillText('Heads or Tails?', 66, 150);
    this.playButton.style.display = 'none'
    this.headsButton.style.display = 'inline-block'
    this.tailsButton.style.display = 'inline-block'
  }

  [...]

  // Guess the flip incorrectly
  lose(sideUp) {
    this.erase()
    this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
    this.canvas.fillText('Your score was ' + this.score, 50, 150);
    this.canvas.fillText('Want to play again?', 45, 200);

    this.playButton.style.display = 'inline-block'
    this.headsButton.style.display = 'none'
    this.tailsButton.style.display = 'none'
    this.shouldShowAdOnPlay = true;
  }

  [...]

  // Erase the canvas
  erase() {
    this.canvas.fillStyle = '#ADD8E6';
    this.canvas.fillRect(0, 0, 300, 300);
    this.canvas.fillStyle = '#000000';
  }

  enableButtons() {
    this.playButton.disabled = false;
    this.headsButton.disabled = false;
    this.tailsButton.disabled = false;
  }

  disableButtons() {
    this.playButton.disabled = true;
    this.headsButton.disabled = true;
    this.tailsButton.disabled = true;
  }
}

const game = new Game();

6. リワード広告を表示するために adBreak() を呼び出す

ゲームの終了時に表示するリワード広告のコードを追加します(リワード広告は、ゲームエンド後にユーザーが一からのスタートではなく、既存のスコアでの復活を望む場合に表示できます)。lose() 関数内の adBreak() を呼び出し、リワード広告が利用可能かどうか確認します。利用できる場合は、報酬(このゲームの場合は「復活」)を獲得したいかどうか尋ねるメッセージをユーザーに表示します。ユーザーが広告の視聴に同意する場合は、該当する showAdFn() を呼び出します。adViewedadDismissed コールバックを使用して、ユーザーがリワード広告を視聴 / スキップする場合の動作を設定できます。

リワード広告を表示する場合は、毎回新たに adBreak() を呼び出します。これにより、前の広告の有効期限が切れていたり、利用できなかったりする場合でも、更新された広告を表示できます。

showAdFn() は、広告を再生する直接的なユーザー アクションの一部として呼び出す必要があります。そうでない場合、広告は表示されません。

広告ブレークの前後に呼び出す関数を作成します。この関数は、adBreak() プレースメント設定で使用します。beforeRewardadViewedadDismissedbeforeAd、および afterAd 関数は、適切な広告が見つかった場合にのみ呼び出されることに留意してください。

game.js

class Game {
  constructor() {
    // Define variables
    this.score = 0;
    this.choice = '';
    this.muted = false;
    this.shouldShowAdOnPlay = false;
    this.showRewardedAdFn = null;

    this.canvas = document.getElementById('gameContainer').getContext('2d');
    this.canvas.font = '24px Arial';

    this.playButton = document.getElementById('playButton');
    this.headsButton = document.getElementById('headsButton');
    this.tailsButton = document.getElementById('tailsButton');
    this.muteButton = document.getElementById('muteButton');
    this.continueButton = document.getElementById('continueButton');

    adConfig({
      sound: 'on',
    });

    // On click listeners for the game's buttons.
    this.playButton.addEventListener('click', () => {
      this.erase();
      this.play();
    });

    this.headsButton.addEventListener('click', () => {
      this.choice = 'Heads';
      this.flipCoin();
    });

    this.tailsButton.addEventListener('click', () => {
      this.choice = 'Tails';
      this.flipCoin();
    });

    this.muteButton.addEventListener('click', () => {
      var soundString = this.muted ? 'on' : 'off';
      this.muteButton.innerHTML = this.muted ? 'Mute sound' : 'Un-mute sound';
      this.muted = !this.muted;
      adConfig({
        sound: soundString,
      });
    });

    this.continueButton.addEventListener('click', () => {
      if (this.showRewardedAdFn) {
        this.showRewardedAdFn();
      }
    });

    this.erase();
  }

  // Start the game
  play() {
    if (this.shouldShowAdOnPlay) {
      this.shouldShowAdOnPlay = false;

      adBreak({
        type: 'next',  // ad shows at start of next level
        name: 'restart-game',
        beforeAd: () => { this.disableButtons(); },  // You may also want to mute the game's sound.
        afterAd: () => { this.enableButtons(); },    // resume the game flow.
      });
    }

    this.score = 0;
    this.canvas.fillText('Score: ' + this.score, 8, 26);
    this.canvas.fillText('Heads or Tails?', 66, 150);
    this.playButton.style.display = 'none';
    this.continueButton.style.display = 'none';
    this.headsButton.style.display = 'inline-block';
    this.tailsButton.style.display = 'inline-block';
  }

  [...]

  // Guess the flip incorrectly
  lose(sideUp) {
    this.erase()
    this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
    this.canvas.fillText('Your score was ' + this.score, 50, 150);
    this.canvas.fillText('Want to play again?', 45, 200);

    this.playButton.style.display = 'inline-block'
    this.headsButton.style.display = 'none'
    this.tailsButton.style.display = 'none'
    this.shouldShowAdOnPlay = true;

    adBreak({
      type: 'reward',  // rewarded ad
      name: 'reward-continue',
      beforeReward: (showAdFn) => {
        this.showRewardedAdFn = () => { showAdFn(); };
        // Rewarded ad available - prompt user for a rewarded ad
        this.continueButton.style.display = 'inline-block';
      },
      beforeAd: () => { this.disableButtons(); },     // You may also want to mute the game's sound.
      adDismissed: () => {
        this.continueButton.style.display = 'none';   // Hide the reward button and continue lose flow.
      },
      adViewed: () => { this.continueGame(); },       // Reward granted - continue game at current score.
      afterAd: () => { this.enableButtons(); },       // Resume the game flow.
    });
  }

  // Continue gameplay at current score
  continueGame() {
    this.erase();
    this.canvas.fillText('Score: ' + this.score, 8, 26);
    this.canvas.fillText('Heads or Tails?', 66, 150);
    this.playButton.style.display = 'none';
    this.continueButton.style.display = 'none';
    this.headsButton.style.display = 'inline-block';
    this.tailsButton.style.display = 'inline-block';
  }
  [...]
}

const game = new Game();

「続行」ボタンを HTML ファイルに追加します。

index.html

[...]
    <canvas id="gameContainer" height="300px" width="300px"></canvas>
    <br>
    <button id="playButton">Play</button>
    <button style="display:none" id="headsButton">Heads</button>
    <button style="display:none" id="tailsButton">Tails</button>
    <button style="display:none" id="continueButton">Watch Ad to continue?</button>
    <button id="muteButton">Mute sound</button>

    <script async
      data-adbreak-test="on"
      src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
      crossorigin="anonymous">
    </script>
[...]

これで、コイントス アプリで広告が表示されるプレースメントが作成されます。

ゲームの終了時以外にも、広告が表示される適切な場所が追加されることがありますが、これらの場所で adBreak() を呼び出す方法は、上記の例のようになります。

製品版アプリのテストを無効にする

アプリのリリース前に、index.htmldata-adbreak-test="on" の行を削除またはコメントアウトしてください。このコードにより、本番環境のテスト設定がオンになります。