Ad Placement API 的設計宗旨,是協助 AdSense 和 AdMob 開發人員在網頁或應用程式的 HTML5 遊戲中,使用中插和獎勵廣告。這個範例示範如何將 Ad Placement API 整合到遊戲中,並使用該 API 放置插頁式廣告。
必要條件
開始之前,請先備妥下列項目:
- 在同一個目錄中建立兩個空白檔案:
- index.html
- game.js
- 在本機安裝 Python,或使用網路伺服器測試實作項目
應用程式程式碼範例
AdMob 發布商可以下載範例應用程式程式碼,進一步瞭解如何將 API 整合至應用程式遊戲。
1. 啟動開發伺服器
由於 Ads Placement API 會透過與載入網頁相同的通訊協定載入依附元件,因此您需要使用網路伺服器測試應用程式。您可以使用 Python 內建的伺服器建立本機開發環境。
開啟終端機。
前往含有 index.html 檔案的目錄,然後執行:
python -m http.server 8000
使用網路瀏覽器前往
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>
<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>
修改 game.js,在點選「Play」按鈕時執行擲硬幣遊戲。
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 程式碼並開啟測試模式
AdSense 程式碼內含 Ad Placement API 功能。如要啟用這項功能,請先加入 AdSense 程式碼,並加入一小段指令碼片段,初始化兩項主要函式: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 內的其他網頁,且遊戲的 HTML 網頁中含有 adsbygoogle
標記,請務必將 allow='autoplay'
新增至 iframe 元素。這是最佳做法,且某些廣告必須符合這項規定,才能在遊戲中放送。
<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 (如有) 通訊,要求並顯示 AdMob 廣告。
這項功能適用於已連結 Google Mobile Ads SDK 的 Android 應用程式。如要啟用這項功能,您需要註冊 WebView
,透過 Google Mobile Ads SDK 顯示遊戲,然後設定 AdMob 廣告單元,並將這些單元做為額外參數傳遞至 AdSense 代碼。當遊戲在合適的應用程式中執行時,廣告刊登位置 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
。如果遊戲同時使用這兩種格式,則應指定這兩個參數。
您也可以選擇指定 data-admob-ads-only=on
代碼參數,表明遊戲應只顯示 AdMob 廣告,且在遊戲於不支援 AdMob 請求的環境 (例如非應用程式環境或未設定 Google Mobile Ads SDK 的應用程式) 中執行時,不應改用 AdSense。
重要事項:如果您將遊戲設計為嵌入應用程式,且本身就是應用程式的擁有者,或即將與應用程式擁有者簽訂收益分潤協議,但希望成效良好且符合政策規定,唯一的方法就是使用這項 AdMob 支援服務。
首先,請使用 Google Mobile Ads SDK 註冊將顯示遊戲的 WebView
:
MainActivity.java (應用程式)
預設 WebView
設定並未針對廣告進行最佳化。使用 WebSettings
API 設定 WebView
,包括:
- JavaScript
- 存取本機儲存空間
自動播放影片
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 接著會使用這項資訊,篩選要求放送的廣告類型,確保廣告適合遊戲 (例如,如果已啟用音效,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()
,這個函式只會在遊戲完整執行一次後執行。
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()
。您可以使用 adViewed
和 adDismissed
回呼,設定使用者觀看/略過獎勵廣告時要執行的動作。
每當有機會顯示獎勵廣告時,都應呼叫新的 adBreak()
。確保先前的廣告過期或無法顯示時,系統會重新整理廣告。
showAdFn()
必須做為使用者直接觀看廣告動作的一部分呼叫,否則廣告可能不會顯示。
建立要在廣告插播前後呼叫的函式,然後在 adBreak()
刊登位置設定中使用這些函式。請注意,只有在找到合適的廣告時,才會呼叫 beforeReward
、adViewed
、adDismissed
、beforeAd
和 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.html
中的 data-adbreak-test="on"
行,因為這段程式碼會啟用正式版中的測試設定。