本指南適用於想建立出價轉接程式的廣告聯播網,以便參與 Google 中介服務的即時出價 (RTB)。如果您是發布商,請參閱發布商中介服務操作說明。
出價轉接程式是整合的用戶端部分。介面卡可讓廣告聯播網 SDK 與 Google Mobile Ads SDK 通訊,載入出價者放送的廣告。
如要讓出價功能正常運作,您的轉接程式必須處理初始化、收集信號、載入廣告,以及轉送廣告生命週期事件。本指南將逐步說明如何實作轉接程式,以處理這些作業。
出價轉接程式的工作流程
初始化
以下詳細說明介面卡的整個要求-回應-算繪生命週期流程:
轉接程式負責工作流程的下列部分:
步驟 4 至 7:初始化轉接器,並在初始化完成後回呼 Google Mobile Ads SDK。
步驟 10 至 13:從廣告聯播網 SDK 收集信號,傳送至出價工具,參與 RTB 請求,然後轉送至 Google Mobile Ads SDK。
步驟 18 至 21:如果出價工具傳回勝出的出價,請根據出價工具的回應載入廣告。載入完成後,請通知 Google Mobile Ads SDK 廣告已載入。
步驟 23 和後續步驟:廣告顯示時,請將曝光和點擊事件,以及廣告顯示生命週期內發生的其他廣告事件,通知 Google Mobile Ads SDK。
導入出價轉接程式
如要為 Google Mobile Ads SDK 建立出價轉接程式,您必須擴充 RtbAdapter
抽象類別。以下各節將說明 RtbAdapter
中的每個抽象方法。
getSDKVersionInfo()
您應在此傳回 SDK 的版本。這個版本會連同 OpenRTB 要求一併傳送給出價方。
這個方法需要傳回 VersionInfo
。以下範例說明如何將 SDK 的字串版本轉換為 VersionInfo.
@Override
public VersionInfo getSDKVersionInfo() {
// Get your SDK's version as a string. E.g. "1.2.3"
// String versionString = YourSdk.getVersion();
String splits[] = versionString.split("\\.");
if (splits.length >= 3) {
int major = Integer.parseInt(splits[0]);
int minor = Integer.parseInt(splits[1]);
int micro = Integer.parseInt(splits[2]);
return new VersionInfo(major, minor, micro);
}
String logMessage = String.format("Unexpected SDK version format: %s." +
"Returning 0.0.0 for SDK version.", sdkVersion);
Log.w(TAG, logMessage);
return new VersionInfo(0, 0, 0);
}
getVersionInfo()
您應該在此傳回介面卡的版本。這個版本會連同 OpenRTB 要求一併傳送給出價方。
Google 的開放原始碼和版本化轉接頭使用 4 位數的轉接頭版本配置,但 VersionInfo
只允許 3 位數。如要解決這個問題,建議將最後兩位數合併為修補程式版本,如下所示。
@Override
public VersionInfo getVersionInfo() {
// Get your adapters's version as a string. E.g. "1.2.3.0"
String versionString = BuildConfig.VERSION_NAME;
String splits[] = versionString.split("\\.");
if (splits.length >= 4) {
int major = Integer.parseInt(splits[0]);
int minor = Integer.parseInt(splits[1]);
int micro = Integer.parseInt(splits[2]) * 100 + Integer.parseInt(splits[3]);
return new VersionInfo(major, minor, micro);
}
String logMessage = String.format("Unexpected adapter version format: %s." +
"Returning 0.0.0 for adapter version.", versionString);
Log.w(TAG, logMessage);
return new VersionInfo(0, 0, 0);
}
initialize()
逾時:30 秒
initialize()
方法是轉換器中呼叫的第一個方法。每個工作階段只會呼叫一次。這個方法會提供 MediationConfiguration
物件清單,代表這個應用程式中為廣告聯播網設定的完整刊登位置清單;您可以逐一檢查這個清單,剖析每個刊登位置的憑證,並將相關資料傳遞至 SDK 以進行初始化。
初始化 SDK 並準備好接收廣告請求後,請叫用 InitializationCompleteCallback
的 onInitializationSucceeded()
方法。這項回呼會轉送給應用程式發布商,讓他們知道可以開始載入廣告。
@Override
public void initialize(Context context,
InitializationCompleteCallback initializationCompleteCallback,
List<MediationConfiguration> mediationConfigurations) {
// Initialize your ad network's SDK.
...
// Invoke the InitializationCompleteCallback once initialization completes.
initializationCompleteCallback.onInitializationSucceeded();
}
collectSignals()
逾時:1 秒
發布商每次要求廣告時,系統都會建立 RtbAdapter
的新例項,並呼叫 collectSignals()
方法。這個 RtbAdapter
例項會用於該廣告的廣告請求、回應和算繪生命週期。collectSignals()
方法可讓您的轉接程式提供裝置信號,並在 OpenRTB 要求中傳送至出價工具。
collectSignals()
會在背景執行緒上呼叫。Google Mobile Ads SDK 會同時向所有參與出價的轉接程式要求信號。請尊重這段時間,並限制對 UI 執行緒的呼叫。轉接程式或 SDK 收集信號時需要執行的任何繁重工作,都應在 initialize()
方法中完成並快取。
準備好信號後,請使用編碼信號呼叫 onSuccess()
回呼。
以下是實作範例:
@Override
public void collectSignals(RtbSignalData rtbSignalData,
SignalCallbacks signalCallbacks) {
String signals = YourSdk.getSignals();
signalCallbacks.onSuccess(signals);
}
如果介面卡無法收集信號,請呼叫 signalCallbacks.onFailure()
,並提供說明發生錯誤的字串。
實作廣告載入方法
逾時:10 秒
如果出價方傳回最高出價,Google Mobile Ads SDK 會呼叫您的轉接程式來載入最高出價的廣告,並傳遞 SDK 載入該廣告所需的任何資料。
系統呼叫的確切載入方法,取決於這項要求所屬的廣告格式:
廣告格式 | 載入方法 |
---|---|
橫幅 | loadBannerAd()
|
插頁式 | loadInterstitialAd()
|
獎勵 | loadRewardedAd()
|
針對介面卡支援的廣告格式實作這些方法。
系統會在 UI 執行緒上呼叫載入方法,並使用您提供信號的相同介面卡執行個體。這個方法會提供下列參數:
MediationAdConfiguration
,其中包含 SDK 載入得標出價廣告所需的參數,例如出價回應,以及發布者在 AdMob 使用者介面中設定的任何憑證。用於在載入成功或失敗時通知 Google Mobile Ads SDK 的
MediationAdLoadCallback
物件。
SDK 載入廣告後,請呼叫 mediationAdLoadCallback.onSuccess()
。如果事件廣告載入失敗,請呼叫 mediationAdLoadCallback.onFailure()
,並提供說明發生錯誤的字串。
mediationAdLoadCallback.onSuccess()
方法需要傳遞物件,確認符合 Google Mobile Ads SDK 定義的其中一個「廣告」介面。這些廣告介面會要求您提供廣告相關資訊。
MediationAdConfiguration
也有 getWatermark()
方法,可傳回代表 PNG 圖片的 Base64 編碼字串。這張圖片應以透明疊加方式,在廣告中以平鋪方式顯示。如需浮水印的算繪方式,請洽詢 Google。其中包含所顯示廣告的中繼資料,發布商可藉此判斷所顯示廣告的來源。
如果是橫幅,系統會要求您提供橫幅檢視畫面。如果是插頁式廣告和獎勵廣告,系統會要求您實作 show()
方法,以便在稍後顯示廣告。根據最佳做法,我們建議您讓負責載入廣告的類別,同時負責實作這些廣告方法。
以下是 loadBannerAd()
的實作範例。請注意,由於您的轉接程式是與不同的 SDK 整合,因此轉接程式的實作方式會有所不同。
public final class SampleRtbAdapter extends RtbAdapter {
...
@Override
public void loadBannerAd(
MediationBannerAdConfiguration adConfiguration,
MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback> callback) {
SampleBannerRenderer bannerRenderer =
new SampleBannerRenderer(adConfiguration, callback);
bannerRenderer.render();
}
}
// Renders a banner ad, and forwards callbacks to the Google Mobile Ads SDK.
public class SampleBannerRenderer implements MediationBannerAd {
private MediationBannerAdConfiguration adConfiguration;
private final MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback> adLoadCallback;
private AdView adView;
private MediationBannerAdCallback callback;
public SampleRtbBannerRenderer(
MediationBannerAdConfiguration adConfiguration,
MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback> adLoadCallback) {
this.adConfiguration = adConfiguration;
this.adLoadCallback = adLoadCallback;
}
public void render() {
adView = new AdView(adConfiguration.getContext());
adView.setAdSize(adConfiguration.getAdSize());
// serverParameters are the parameters entered in the AdMob UI for your network.
adView.setAdUnitId(adConfiguration.getServerParameters().getString("adUnitId"));
// Map the callbacks from your SDK to Google's SDK.
adView.setAdListener(new AdListener() {
// See the next step for more information on callback mapping.
// ...
});
// Get the bid response and watermark from the ad configuration and
// pass the relevant information to your SDK.
String ad = adConfiguration.getBidResponse();
String watermark = adConfiguration.getWatermark();
Bundle extras = new Bundle();
extras.putString("bid", ad);
extras.putString("watermark", watermark);
AdRequest request = new AdRequest.Builder()
.addNetworkExtrasBundle(AdMobAdapter.class, extras)
.build();
adView.loadAd(request);
}
// MediationBannerAd implementation
@NonNull
@Override
public View getView() {
return adView;
}
}
轉送廣告呈現生命週期事件
介面卡的最終責任是將任何顯示生命週期事件通知 Google Mobile Ads SDK,以便轉送給發布商。無論哪個廣告聯播網放送廣告,發布商都會在特定時間收到這些回呼,因此請務必盡可能在正確時間叫用這些回呼,讓 Google Mobile Ads SDK 將回呼轉送給發布商。
在適當情況下,轉接程式應叫用下列事件:
所有格式皆適用 | |
---|---|
方法 | 何時撥打電話 |
reportAdClicked()
|
廣告獲得點擊。 |
reportAdImpression()
|
廣告已算入曝光次數。 |
onAdOpened()
|
廣告以全螢幕顯示。 |
onAdClosed()
|
廣告的全螢幕檢視畫面已關閉。 |
onAdLeftApplication()
|
廣告導致使用者離開應用程式。 |
獎勵廣告 | |
onRewarded()
|
系統會授予使用者獎勵。 |
影片回呼 (獎勵和原生廣告) | |
onVideoStarted()
|
廣告影片開始播放。 |
onVideoCompleted()
|
廣告影片已播完。 |
呼叫 mediationAdLoadCallback.onSuccess()
時,介面卡會取得 MediationAdLoadCallback<MediationAdT, MediationAdCallbackT>
物件。轉接程式應保留這個物件,並用來叫用廣告上發生的顯示事件。
通常,這些事件大多是由廣告聯播網的 SDK 觸發。介面卡的用途很簡單,就是將廣告聯播網 SDK 的回呼對應至 Google Mobile Ads SDK。
以下範例說明如何將 SDK 廣告監聽器的回呼轉送至 Google Mobile Ads SDK:
adView.setAdListener(new AdListener() {
public void onAdLoaded() {
callback = adLoadCallback.onSuccess(SampleBannerRenderer.this);
}
public void onAdImpression() {
if (callback != null) {
callback.reportAdImpression();
}
}
public void onAdFailedToLoad(LoadAdError adError) {
adLoadCallback.onFailure("Error: " + adError.toString());
}
public void onAdClosed() {
if (callback != null) {
callback.onAdClosed();
}
}
public void onAdOpened() {
if (callback != null) {
callback.onAdOpened();
callback.reportAdClicked();
}
}
public void onAdLeftApplication() {
if (callback != null) {
callback.onAdLeftApplication();
}
}
});
追蹤原生廣告曝光次數所需的素材資源
當原生廣告有 1 像素可見時,Google Mobile Ads SDK 就會記錄曝光。如果廣告聯播網 SDK 必須顯示特定素材資源,才能算入有效曝光,出價者可以在出價回應中指出這些必要原生素材資源。接著,Google Mobile Ads SDK 會驗證必要原生素材資源是否已顯示,再記錄曝光。
如要進一步瞭解如何在競價回應中指定其他必要素材資源,請參閱原生必要素材資源文件。
顯示廣告錯誤
如果是插頁式和獎勵廣告等全螢幕格式,您會在成功載入回呼中提供 MediationInterstitialAd
或 MediationRewardedAd
的實作項目,讓 Google Mobile Ads SDK 要求您的轉接程式顯示廣告。
Google Mobile Ads SDK 預期,如果介面卡成功載入廣告,發布商要求顯示廣告時,廣告應已準備就緒。也就是說,每次顯示呼叫都應產生曝光。
不過,在某些特殊情況下,您可能無法顯示廣告。如果無法顯示廣告,請呼叫 onAdFailedToShow()
回呼來取消曝光。
下表說明顯示回呼如何影響全螢幕廣告格式的曝光記錄:
回撥電話 | 結果 |
---|---|
onAdOpened() | Impression recorded
|
onAdFailedToShow() | Impression failure1
|
以上皆非,持續幾秒鐘 | Impression recorded
|
1 如果曝光失敗,廣告聯播網不會為該次曝光付費,但這會影響可計費事件率調整。詳情請參閱「出價要求信號」。
下列模擬範例示範載入/顯示生命週期,其中廣告顯示呼叫可能會失敗。
final class SampleRtbAdapter extends RtbAdapter implements MediationRewardedAd {
private MediationRewardedAdCallback callback;
private RewardedAd rewardedAd;
...
@Override
public void loadRewardedAd(
MediationRewardedAdConfiguration adConfiguration,
final MediationAdLoadCallback<MediationRewardedAd, MediationRewardedAdCallback> loadCallback) {
// Load an ad. This mock example uses Google's SDK, but in practice
// your adapter will load the ad using your ad network's SDK.
RewardedAd.load(adConfiguration.getContext(),
"ca-app-pub-3940256099942544/5224354917",
new AdRequest.Builder().build(),
new RewardedAdLoadCallback() {
@Override
public void onAdLoaded(@NonNull RewardedAd rewardedAd) {
// When the ad loads, invoke the load success callback.
callback = loadCallback.onSuccess(SampleRtbAdapter.this);
}
});
}
@Override
public void showAd(Context context) {
// In this mock example, your ad network requires an activity context, but
// didn't receive one, making you unable to show the ad.
if (!(context instanceof Activity)) {
AdError error = new AdError(1, "Context must be an activity",
"com.google.ads.mediation.sample");
callback.onAdFailedToShow(error);
}
// This example shows Google SDK's callbacks, but it's likely your SDK
// has similar presentation callbacks.
rewardedAd.setFullScreenContentCallback(new FullScreenContentCallback() {
@Override
public void onAdShowedFullScreenContent() {
// Your ad network SDK successfully showed the ad. Call onAdOpened().
callback.onAdOpened();
}
@Override
public void onAdFailedToShowFullScreenContent(AdError adError) {
// Your ad network SDK failed to show the ad, invoke onAdFailedToShow.
// In practice, you will map your SDK's error to an AdError.
AdError error = new AdError(adError.getCode(), adError.getMessage(),
adError.getDomain());
callback.onAdFailedToShow(adError);
}
});
rewardedAd.show((Activity) context, ...);
}
}