구현 예시

Ad Placement API는 웹 또는 앱의 HTML5 게임에 전면 광고와 보상형 광고를 게재하는 애드센스 및 AdMob 개발자를 지원하도록 설계되었습니다. 이 예에서는 Ad Placement API를 게임에 통합하고 이를 사용하여 전면 광고를 게재하는 방법을 알아봅니다.

기본 요건

시작하기 전에 다음 사항이 필요합니다.

  • 같은 디렉터리에 빈 파일 두 개를 만듭니다.
    • index.html
    • game.js
  • Python을 로컬 환경에 설치하거나 웹 서버를 사용하여 구현을 테스트합니다.

앱 샘플 코드

AdMob 게시자의 경우 샘플 앱 코드를 다운로드하면 Ad Placement API를 앱 게임에 통합하는 방법을 더 잘 이해할 수 있습니다.

앱 샘플 코드 다운로드

1. 개발 서버 시작하기

Ad Placement API는 로드되는 페이지와 동일한 프로토콜을 통해 종속 항목을 로드하므로 웹 서버를 사용하여 앱을 테스트해야 합니다. Python의 기본 제공 서버를 사용하여 로컬 개발 환경을 만들 수 있습니다.

  1. 터미널을 엽니다.

  2. index.html 파일이 있는 디렉터리로 이동한 후 다음을 실행합니다.

    python -m http.server 8000
    
  3. 웹브라우저에서 localhost:8000으로 이동합니다.

Apache HTTP 서버와 같은 기타 웹 서버도 사용할 수 있습니다.

2. HTML5 게임 만들기

index.html을 수정하여 HTML5 캔버스 요소 및 게임플레이를 트리거하는 버튼을 만듭니다. 그런 다음 필요한 스크립트 태그를 추가하여 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>
    <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>

'재생' 버튼을 클릭하여 동전 던지기 게임을 즐길 수 있도록 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을 열 때 게임 캔버스와 '재생' 버튼이 표시됩니다. 재생을 클릭하면 동전 던지기 게임이 시작됩니다.

3. Ad Placement API 가져오기

다음으로 game.js의 태그 앞 index.html에 스크립트 태그를 삽입해 게임에 Ad Placement API를 추가합니다.

스크립트 태그는 여러 매개변수를 사용할 수 있습니다. 다음 매개변수를 사용하여 애드센스 속성 코드를 지정하고 테스트 모드를 사용 설정합니다.

  • data-ad-client=<AdSense property code> 애드센스 속성 코드입니다. 이는 앱 내에서 실행되는 게임에서도 항상 필요합니다.
  • data-adbreak-test="on" 테스트 모드를 사용 설정합니다. 플레이어에게 제시된 후에는 게임에서 이 속성을 삭제하세요.

애드센스 코드 설정 및 테스트 모드 사용 설정하기

Ad Placement API 기능은 애드센스 코드에 포함되어 있습니다. 이 기능을 사용하려면 먼저 애드센스 코드를 추가하고 두 가지 주요 함수, 즉 adBreak()adConfig()를 초기화하는 작은 스크립트 스니펫을 포함해야 합니다.

index.html(웹)

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

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

모바일 앱 지원

H5 게임은 일반 웹브라우저, 앱 내의 WebView 또는 Chrome 맞춤 탭에서 실행할 수 있습니다. Ad Placement API는 게임이 실행 중인 환경을 감지하고 광고 요청을 적절하게 전달할 수 있습니다. 게임이 일반 웹브라우저에서 실행되는 경우 광고 요청은 일반적인 애드센스 요청으로 간주됩니다. Ad Placement API는 인앱 환경을 감지하면 GMA SDK(있는 경우)와 통신하여 AdMob 광고를 요청하고 표시합니다.

현재 이 기능은 AdMob GMA SDK에 연결된 Android 앱에서 지원됩니다. 이 기능을 사용 설정하려면 GMA SDK로 게임을 표시할 WebView를 등록한 다음 AdMob 광고 단위를 구성하고 이를 애드센스 태그에 추가 매개변수로 전달해야 합니다. 게임이 적절한 앱 내에서 실행되면 Ad Placement API가 이러한 광고 단위를 사용하여 광고를 표시합니다.

모바일 지원을 사용 설정하려면 다음과 같은 추가 태그 매개변수를 지정해야 합니다.

  • data-admob-interstitial-slot=<AdMob slot ID> 이전에 구성한 AdMob 전면 광고 단위 ID입니다.
  • data-admob-rewarded-slot=<AdMob slot ID> AdMob 보상형 광고 단위 ID입니다.

애드센스 속성 코드는 항상 data-ad-client 매개변수를 통해 전달되어야 하며, data-admob-interstitial-slot 또는 data-admob-rewarded-slot 중 하나 이상을 지정해야 합니다. 게임에서 두 형식을 모두 사용하는 경우 두 매개변수를 모두 지정해야 합니다.

중요: 게임이 앱 내에 삽입되도록 설계하고자 할 때 앱을 소유하고 있거나 앱 소유자와 수익 배분 계약을 체결할 때 정책을 준수하면서 실적을 높일 수 있는 유일한 방법은 이 AdMob 지원을 사용하는 것입니다.

먼저 GMA SDK로 게임을 보여 주는 WebView를 등록합니다.

MainActivity.java(앱)

...
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    webView = findViewById(R.id.webview_minigame);

    WebSettings settings = webView.getSettings();
    settings.setJavaScriptEnabled(true);

    h5AdsWebViewClient = new H5AdsWebViewClient(this, webView);
    webView.setWebViewClient(h5AdsWebViewClient);

    h5AdsWebViewClient.setDelegateWebViewClient(pubWebViewClient);

그런 다음 아래와 같이 AdMob 광고 단위(전면 광고용 1개와 보상형 광고용 1개)를 전달합니다.

index.html(앱)

 [...]
    <canvas id="gameContainer" height="300px" width="300px"></canvas>
    <button id="playButton">Play</button>
    <button style="display:none" id="headsButton">Heads</button>
    <button style="display:none" id="tailsButton">Tails</button>
    <script async
      data-ad-client="ca-pub-123456789"
      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">
    </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() 호출은 게임의 현재 구성을 광고 게재위치 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>
    <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-ad-client="ca-pub-123456789"
      data-adbreak-test="on"
      src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js">
    </script>
[...]

5. 게임 종료 시 adBreak() 호출하기

adBreak() 호출은 광고 게재위치를 정의하며, 게임의 해당 지점에서 광고를 게재하는 데 필요한 모든 것을 지정하는 게재위치 구성이라는 객체를 취합니다. 다양한 유형의 광고를 지원하려면 게재위치 구성의 여러 하위 집합을 초기화해야 합니다.

adBreak() 호출은 광고가 게재위치, 즉 광고를 게재할 수 있는 기회를 정의합니다. 광고가 실제로 표시되는지 여부는 다음과 같은 여러 요인에 따라 결정됩니다.

  • 선언한 광고 게재위치의 유형
  • 광고 게재위치 이전에 적절한 사용자 상호작용이 발생했는지 여부
  • 현재 플레이어에게 적합한 광고가 있는지 여부. 예를 들어
    • 플레이어에게 관련성이 있는 광고
    • 플레이어의 데이터 공개 및 동의 설정과 일치하는 광고
  • 사용자가 최근에 본 광고의 개수
  • 다음 형태 중 하나로 게임에 대해 구성한 컨트롤 설정
    • 태그 내 힌트
    • 애드센스 내(참고: 애드센스에서 사용할 수 있는 컨트롤은 시간이 지남에 따라 변경됨)

게임을 다시 시작할 때 표시할 전면 광고에 대한 코드를 추가합니다. 게임이 한 번 실행된 후에만 play() 함수 내에서 adBreak()를 호출합니다.

adBreak()는 사용자 작업(예: '재생' 버튼 클릭) 중 일부로 호출되어야 합니다. 그렇지 않으면 API에서 광고를 요청하고 표시할 수 없습니다.

광고 시점 전후에 호출할 함수를 만들어 adBreak() 게재위치 구성에서 사용합니다. beforeAdafterAd 함수는 적합한 광고가 있는 경우에만 호출된다는 점을 잊지 마세요.

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();

이제 동전 던지기 앱은 광고 게재를 위한 광고 게재위치를 만듭니다.

앱에는 게임이 종료될 때 이외에도 광고를 표시할 적절한 추가 위치가 있을 수 있습니다. 이러한 위치에서 adBreak()를 호출하는 방식도 이 예에 나온 내용과 비슷합니다.

프로덕션 앱 테스트 사용 중지

index.htmldata-adbreak-test="on" 코드는 프로덕션에서 테스트 설정을 활성화하므로 앱 출시 전에 삭제해야 합니다.