本指南適用於希望建構出價轉接程式,以便在 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 使用者介面中設定的任何憑證。MediationAdLoadCallback
物件用於在載入成功或失敗時通知 Google Mobile Ads SDK。
SDK 載入廣告後,請呼叫 mediationAdLoadCallback.onSuccess()
。如果事件廣告載入失敗,請使用字串呼叫 mediationAdLoadCallback.onFailure()
,說明發生的錯誤。
mediationAdLoadCallback.onSuccess()
方法要求您傳入符合 Google Mobile Ads SDK 定義的「Ad」介面之一的物件。這些廣告介面會要求您提供廣告相關資訊。
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();
}
}
});
原生廣告曝光追蹤所需的素材資源
Google Mobile Ads SDK 會在廣告顯示 1 個像素時,記錄原生廣告的曝光次數。如果廣告聯播網 SDK 需要顯示特定素材資源,才能呈現有效曝光,出價方可以在出價回應中指出這些必要的原生素材資源。接著,Google Mobile Ads SDK 會驗證是否已顯示必要的原生素材資源,再記錄曝光。
如要進一步瞭解如何在出價回應中指定其他必要的素材資源,請參閱必要的原生素材資源文件說明。
顯示廣告錯誤
針對插頁式廣告和獎勵式廣告等全螢幕格式,您可以在成功載入回呼中提供 MediationInterstitialAd
或 MediationRewardedAd
的實作項目,讓 Google Mobile Ads SDK 要求轉接程顯示廣告。
Google Mobile Ads SDK 預期如果轉接程式成功載入廣告,廣告就會在發布商要求顯示時準備好顯示。也就是說,每個 show 呼叫都應產生曝光。
不過,在某些極端情況下,您可能無法放送廣告。如果您無法顯示廣告,請呼叫 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, ...);
}
}