Android + iOS Integration
Dynamic Price is a set of utilities and helper methods for including the Nimbus auction in an existing Google Ad Manager implementation.
Build Setup
Follow the example below to include the Nimbus SDK Google extension which contains the helper methods for Dynamic Price. You should have already completed the Android or iOS Integration guide to initialize the SDK before proceeding.
dependencies {
implementation("com.adsbynimbus.android:extension-google:2.+")
}
CocoaPods
# Include the NimbusSDK and the following subspecs
pod 'NimbusSDK', subspecs: [
'NimbusKit',
'NimbusRenderStaticKit',
'NimbusRenderVideoKit',
'NimbusGAMKit',
]
Swift Package Manager - https://github.com/adsbynimbus/nimbus-ios-sdk
Include the following libraries in your application target
Implementation
Nimbus Dynamic Price integrates with the Google Mobile Ads SDK by appending key-value parameters from a Nimbus ad to the Ad Manager request and listening for a win notification from the Google ad object to render the Nimbus ad.
Define a LinearPriceMapping
The LinearPriceMapping tells Nimbus how to map winning bid values to line items that have been setup in the Ad Manager account. The mapping is a collection of ordered LinearPriceGranularity objects which define how to bucket the bids for each part of the bid range. The following code implementation matches the Ad Manager Setup Price Granularities.
Please consult your Ad Ops team or your Nimbus Account Manager to obtain the correct values for your setup.
val priceMapping = LinearPriceMapping(
// $0.00 - $5.00, 1 cent increments
LinearPriceGranularity(0, 500, 1),
// $5.00 - $10.00, 10 cent increments
LinearPriceGranularity(500, 1000, 10),
// $10.00 - $50.00, 50 cent increments
LinearPriceGranularity(1000, 5000, 50),
)
let priceMapping = NimbusGAMLinearPriceMapping(granularities: [
// $0.00 - $5.00, 1 cent increments
NimbusGAMLinearPriceGranularity(min: 0, max: 500, step: 1),
// $5.00 - $10.00, 10 cent increments
NimbusGAMLinearPriceGranularity(min: 500, max: 1000, step: 10),
// $10.00 - $50.00, 50 cent increments
NimbusGAMLinearPriceGranularity(min: 1000, max: 5000, step: 50),
])
Add the handleEventForNimbus method to an AppEventListener/Delegate
Dynamic Price uses the App Event functionality provided by the Google Ads SDK to receive a notification if the Nimbus ad should be served. Using the extension methods provided on the Banner or Interstitial objects, call handleEventForNimbus(name, info)
in the app event callback to notify the Nimbus SDK of the event and determine if Nimbus should render.
handleEventForNimbus should be the first method called in the app event callback and can be added to an existing listener / delegate; it will return true if the Nimbus ad was selected to be rendered.
Request a Nimbus Ad and applyDynamicPrice
The NimbusAd.applyDynamicPrice
method will setup the Nimbus ad to be served using Ad Manager as the mediation. To request an ad from Nimbus follow the steps below; additional information on ad requests can be found in the Requesting section (Android / iOS). Code examples can be found at the end of this page.
The first parameter of each NimbusRequest helper method identifies where in the application the ad is being served and is visible on the Nimbus dashboard for reporting. It must not contain any auto-incrementing or randomly generated values.
Create a NimbusRequest using one of the provided helper methods. The request to Nimbus should match the type of Ad Manager ad that it will be loaded into.
forBannerAd
-> AdManagerAdView / GAMBannerView / AdLoaderforInterstitialAd
-> AdManagerInterstitialAd / GAMInterstitialAdforRewardedVideoAd
-> RewardedAd / GADRewardedAd
Send the request to Nimbus using the NimbusAdManager or NimbusRequestManager objects and wait for the success or failure callback.
If an ad is returned from Nimbus, call
applyDynamicPrice
with the AdManagerAdRequest.Builder / GAMRequest object to setup Dynamic Price using the LinearPriceMapping defined earlier. This will append the required key-values to the Google request.
As a reminder, if implementing Dynamic Price alongside other Ad Networks, it is required that all requests to each network are called at the same time. Responses from all networks including Nimbus must be received prior to appending the key-value pairs from each response into the GAM request.
Proceed with Google Load
Once the Nimbus auction has completed and all key-values have been appended, the request will be ready to send to Google. Ensure that all listeners and delegates have been set on the Google ad object and proceed to load the ad.
Setting Delegates on iOS
iOS provides an additional applyDynamicPrice
extension method to set the Google delegate on the GAMBannerView
and GAMInterstitial
objects and should be used in all cases. It requires a NimbusRequestManager
instance and an optional NimbusAd
object for interstitials only.
// Banners
bannerView.applyDynamicPrice(requestManager: nimbusRequestManager, delegate: self)
// Interstitials
interstitialAd.applyDynamicPrice(
ad: ad,
requestManager: nimbusRequestManager,
delegate: self)
Setting a listener or delegate on the Google ad object after the ad has loaded will interfere with proper functionality of Dynamic Price and should be avoided.
Load the Ad
// Banners
adManagerAdView.load(adManagerAdRequest)
// AdLoader
adManagerAdLoader.loadAd(adManagerAdRequest)
// Interstitials
AdManagerInterstitialAd.load(requireContext(), adUnit, adManagerAdRequest, loadCallback)
// Rewarded
RewardedAd.load(requireActivity(), rewardedUnitId, adManagerRequest, loadCallback)
// Banners
bannerView.loadDynamicPrice(gamRequest: gamRequest, ad: nimbusAd, mapping: priceMapping)
// AdLoader
adLoader.loadDynamicPrice(gamRequest: gamRequest, ad: ad, mapping: priceMapping)
// Interstitials
GAMInterstitialAd.load(withAdManagerAdUnitID: adUnit, request: gamRequest) {
...
interstitialAd.presentDynamicPrice(fromRootViewController: self)
}
// Rewarded
GADRewardedAd.load(withAdUnitID: adUnit,request: gamRequest, completionHandler)
Proper functionality of Dynamic Price requires the use of the applyDynamicPrice, loadDynamicPrice
, and presentDynamicPrice
extension methods on the GAMBannerView and GAMInterstitial objects and should be called for every ad load. If Nimbus does not return an ad, pass ad: nil
for each function or omit the parameter.
Code Examples
Fully functional Dynamic Price examples are available in the nimbus-android-sample and nimbus-ios-sample repositories.
Banner and Inline Video
lateinit var nimbusAdManager: NimbusAdManager
lateinit var googleAdView: AdManagerAdView
lateinit var nimbusRequest: NimbusRequest
/* Helper property to determine if the request did not fill */
inline val LoadAdError.isNoFill: Boolean
get() = code in intArrayOf(AdRequest.ERROR_CODE_NO_FILL, AdRequest.ERROR_CODE_MEDIATION_NO_FILL)
/**
* Helper function to create and set the Listeners required for Dynamic Price rendering.
*
* If using another implementation of AdListener, AppEventListener, onPaidEventListener the
* following four methods must be modified to send signals to the Nimbus SDK.
* @param auctionData Created after receiving a response from Nimbus
*/
fun AdManagerAdView.setNimbusListeners(auctionData: GoogleAuctionData) {
val listener = object : AdListener(), AppEventListener, OnPaidEventListener {
/**
* If the ad fails to load with no fill, notify the NimbusAdManager.
* No Fill = AdRequest.ERROR_CODE_NO_FILL or AdRequest.ERROR_CODE_MEDIATION_NO_FILL
*/
override fun onAdFailedToLoad(loadError: LoadAdError) {
if (loadError.isNoFill) adManager.notifyNoFill(auctionData)
}
/** When an impression occurs, notify the NimbusAdManager with the responseInfo */
override fun onAdImpression() {
adManager.notifyImpression(auctionData, responseInfo)
}
/** When pricing information is available, call onPaidEvent on auctionData */
override fun onPaidEvent(event: AdValue) {
auctionData.onPaidEvent(event)
}
/**
* This method is called when the AdManagerAdView loads the creative.
*
* Call handleEventForNimbus before any other code to ensure it receives the event.
*
* If handleEventForNimbus returns true, set nimbusWin on auctionData */
*/
override fun onAppEvent(name: String, info: String) {
if (handleEventForNimbus(name, info)) auctionData.nimbusWin = true
}
}
/* Set the listeners on the instance of the AdManagerAdView */
adListener = listener
appEventListener = listener
onPaidEventListener = listener
}
/* Dynamic Price request and rendering flow */
lifecycleScope.launch {
val adManagerRequest = AdManagerAdRequest.Builder()
runCatching {
adManager.makeRequest(root.context, nimbusRequest)
}.onSuccess { nimbusAd ->
/* Create and store a GoogleAuctionData instance for use with this ad load */
val auctionData = GoogleAuctionData(nimbusAd)
/* Ensure the Nimbus callbacks are included in the AdManagerAdView */
adManagerAdView.setNimbusListeners(auctionData)
/* Call apply Dynamic Price on the AdManagerRequest */
adManagerRequest.applyDynamicPrice(nimbusAd, mapping = priceMapping)
/* Send the adManagerRequest to Google */
adManagerAdView.loadAd(adManagerRequest.build())
}
}
import static com.adsbynimbus.google.DynamicPriceRenderer.handleEventForNimbus;
import static com.adsbynimbus.google.DynamicPriceWinLossKt.notifyImpression;
import static com.adsbynimbus.google.DynamicPriceWinLossKt.notifyNoFill;
import static com.adsbynimbus.lineitem.GoogleDynamicPrice.applyDynamicPrice;
class NimbusRenderingDynamicPriceBanner {
final static NimbusAdManager nimbusAdManager = new NimbusAdManager();
/**
* Helper function to create and set the Listeners required for Dynamic Price rendering.
*
* If using another implementation of AdListener, AppEventListener, onPaidEventListener the
* following four methods must be modified to send signals to the Nimbus SDK.
* @param adView The Google AdView
* @param response The Nimbus Response
*/
public static void setNimbusListeners(AdManagerAdView adView, NimbusResponse response) {
/* Create and store a GoogleAuctionData instance for use with this ad load */
final GoogleAuctionData auctionData = new GoogleAuctionData(response);
adView.setAdListener(new AdListener() {
/**
* If the ad fails to load with no fill, notify the NimbusAdManager.
* No Fill = AdRequest.ERROR_CODE_NO_FILL or AdRequest.ERROR_CODE_MEDIATION_NO_FILL
*/
@Override
public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
if (loadAdError.getCode() == AdRequest.ERROR_CODE_NO_FILL ||
loadAdError.getCode() == AdRequest.ERROR_CODE_MEDIATION_NO_FILL) {
notifyNoFill(nimbusAdManager, auctionData);
}
}
/** When an impression occurs, notify the NimbusAdManager with the responseInfo */
@Override
public void onAdImpression() {
notifyImpression(nimbusAdManager, auctionData, adView.getResponseInfo());
}
});
/*
* This method is called when the AdManagerAdView loads the creative.
*
* Call handleEventForNimbus before any other code to ensure it receives the event.
*
* If handleEventForNimbus returns true, set nimbusWin on auctionData
*/
adView.setAppEventListener((name, info) -> {
if (handleEventForNimbus(adView, name, info)) {
auctionData.setNimbusWin(true);
}
});
/* When pricing information is available, call onPaidEvent on auctionData */
adView.setOnPaidEventListener(adValue -> auctionData.onPaidEvent(adValue));
}
/**
* Banner Example - NOTE: this example does not include refresh logic
*
* @param nimbusRequest A Nimbus banner request (i.e. NimbusRequest.forBannerAd(...))
* @param adManagerAdRequest The Google request builder, a new instance is required on each call
* @param adView The Google ad view
*/
public static void example(NimbusRequest nimbusRequest, AdManagerAdRequest.Builder adManagerAdRequest, AdManagerAdView adView) {
nimbusAdManager.makeRequest(adView.getContext(), nimbusRequest, new RequestManager.Listener() {
@Override
public void onAdResponse(@NonNull NimbusResponse nimbusResponse) {
/* Ensure the Nimbus callbacks are included in the AdManagerAdView */
setNimbusListeners(adView, nimbusResponse);
/* Call applyDynamicPrice on the AdManagerRequest */
applyDynamicPrice(adManagerAdRequest, nimbusResponse, priceMapping);
/* Send the adManagerRequest to Google */
adView.loadAd(adManagerAdRequest.build());
}
@Override
public void onError(@NonNull NimbusError error) {
if (error.errorType != NimbusError.ErrorType.NO_BID) {
/* A network or some other error occurred */
}
}
});
}
}
let requestManager = NimbusRequestManager()
var bannerView: GAMBannerView
var nimbusRequest: NimbusRequest
var priceMapping: NimbusGAMLinearPriceMapping
// Implement the adView method of the GADAppEventDelegate
extension UIViewController: GADAppEventDelegate {
// This method is called when the GADBannerView loads the creative.
// Call handleEventForNimbus before any other code to ensure it receives the event.
func adView(_ banner: GADBannerView, didReceiveAppEvent name: String, withInfo info: String?) {
bannerView.handleEventForNimbus(name: name, info: info)
}
}
// Implement the NimbusRequestManagerDelegate
extension UIViewController: NimbusRequestManagerDelegate {
// Call loadDynamicPrice to append Nimbus parameters and send the request to Google
func didCompleteNimbusRequest(request: NimbusRequest, ad: NimbusAd) {
// Send the request to Google and enable Dynamic Price
bannerView.loadDynamicPrice(gamRequest: GAMRequest(), ad: ad, mapping: priceMapping)
// Do not set the bannerView.delegate after calling this method
}
func didFailNimbusRequest(request: NimbusRequest, error: NimbusError) {
// Clear any previous Nimbus ad and send the request to Google
bannerView.loadDynamicPrice(gamRequest: GAMRequest(), ad: nil, mapping: priceMapping)
}
}
// When a price is returns for the ad, call updatePrice to notify the Nimbus SDK
bannerView.paidEventHandler = { [weak bannerView] adValue in
bannerView?.updatePrice(adValue)
}
bannerView.rootViewController = self
// Set the appEventDelegate and call applyDynamicPrice to enable Nimbus
bannerView.appEventDelegate = self
bannerView.applyDynamicPrice(requestManager: requestManager, delegate: self)
// Send the request to Nimbus to start the Dynamic Price auction
requestManager.performRequest(request: nimbusRequest)
AdLoader
lateinit var nimbusAdManager: NimbusAdManager
lateinit var googleAdView: AdManagerAdView
lateinit var nimbusRequest: NimbusRequest
/* Helper property to determine if the request did not fill */
inline val LoadAdError.isNoFill: Boolean
get() = code in intArrayOf(AdRequest.ERROR_CODE_NO_FILL, AdRequest.ERROR_CODE_MEDIATION_NO_FILL)
/**
* Helper function to create and set the Listeners required for Dynamic Price rendering.
*
* If using another implementation of AdListener the
* following four methods must be modified to send signals to the Nimbus SDK.
* @param auctionData Created after receiving a response from Nimbus
*/
class AdLoaderAdListener(
val auctionData: GoogleAuctionData,
val adManager: NimbusAdManager,
) : AdListener() {
var responseInfo : ResponseInfo? = null
/**
* If the ad fails to load with no fill, notify the NimbusAdManager.
* No Fill = AdRequest.ERROR_CODE_NO_FILL or AdRequest.ERROR_CODE_MEDIATION_NO_FILL
*/
override fun onAdFailedToLoad(loadError: LoadAdError) {
if (loadError.isNoFill) adManager.notifyNoFill(auctionData)
}
/** When an impression occurs, notify the NimbusAdManager with the responseInfo */
override fun onAdImpression() {
adManager.notifyImpression(auctionData, responseInfo)
}
}
/* Dynamic Price request and rendering flow */
lifecycleScope.launch {
runCatching {
adManager.makeRequest(root.context, forBannerAd("<position>", Format.MREC))
}.onSuccess { nimbusAd ->
val adManagerRequest = AdManagerAdRequest.Builder()
/* Create and store a GoogleAuctionData instance for use with this ad load */
val auctionData = GoogleAuctionData(nimbusAd)
/* Call apply Dynamic Price on the AdManagerRequest */
adManagerRequest.applyDynamicPrice(nimbusAd, mapping = priceMapping)
/* Create an instance of the listener above */
val adLoaderAdListener = AdLoaderAdListener(auctionData, nimbusAdManager)
googleAdLoader = AdLoader.Builder(root.context.applicationContext, unitId).forAdManagerAdView({
/* Adjust the layout params as needed */
it.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
/**
* This method is called when the AdManagerAdView loads the creative.
* Call handleEventForNimbus before any other code to ensure it receives the event.
* If handleEventForNimbus returns true, set nimbusWin on auctionData */
*/
it.setAppEventListener { name, info ->
if (it.handleEventForNimbus(name, info)) auctionData.nimbusWin = true
}
/** When pricing information is available, call onPaidEvent on auctionData */
it.setOnPaidEventListener { event ->
auctionData.onPaidEvent(event)
}
/* AdLoaderAdListener needs responseInfo to track impressions */
adLoaderAdListener.responseInfo = it.responseInfo
/* Add adView to the container view. */
view.addView(it)
}, AdSize.MEDIUM_RECTANGLE).withAdListener(adLoaderAdListener).build()
/* Send the adManagerRequest to Google */
googleAdLoader.loadAd(adManagerRequest)
}
}
class NimbusRenderingViewController : UIViewController {
let requestManager = NimbusRequestManager()
var adLoader: GADAdLoader?
var nimbusAd: NimbusAd?
var priceMapping: NimbusGAMLinearPriceMapping
weak var bannerView: GAMBannerView?
}
// Implement the adView method of the GADAppEventDelegate
extension NimbusRenderingViewController: GADAppEventDelegate {
// This method is called when the GADBannerView loads the creative.
// Call handleEventForNimbus before any other code to ensure it receives the event.
func adView(_ banner: GADBannerView, didReceiveAppEvent name: String, withInfo info: String?) {
bannerView.handleEventForNimbus(name: name, info: info)
}
}
// Implement the NimbusRequestManagerDelegate
extension NimbusRenderingViewController: NimbusRequestManagerDelegate {
func didCompleteNimbusRequest(request: NimbusRequest, ad: NimbusAd) {
// Remove any previously loaded banners from the screen
bannerView?.removeFromSuperview()
// Send the request to Google with the Nimbus Ad
load(ad: ad)
}
func didFailNimbusRequest(request: NimbusRequest, error: NimbusError) {
// Nimbus did not return an ad, proceed with the load
load()
}
func load(ad: NimbusAd? = nil) {
adLoader = GADAdLoader(
adUnitID: googleDynamicPricePlacementId,
rootViewController: self,
adTypes: [.gamBanner],
options: nil
)
adLoader?.delegate = self
// Send the request to Google and enable Dynamic Price
adLoader?.loadDynamicPrice(gamRequest: GAMRequest(), ad: ad, mapping: priceMapping)
}
}
extension NimbusRenderingViewController {
func loadDynamicPriceBannerAd() {
requestManager.delegate = self
let nimbusRequest = NimbusRequest.forBannerAd(position: "ad_loader_banner")
// Send the request to Nimbus to start the Dynamic Price auction
requestManager.performRequest(request: nimbusRequest)
}
}
extension NimbusRenderingViewController: GADAdLoaderDelegate, GAMBannerAdLoaderDelegate {
func validBannerSizes(for adLoader: GADAdLoader) -> [NSValue] {
[NSValueFromGADAdSize(GADAdSizeBanner)]
}
func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
print("adLoader finished loading")
}
func adLoader(_ adLoader: GADAdLoader, didReceive bannerView: GAMBannerView) {
print("adLoader got bannerView")
bannerView.rootViewController = self
// Set the appEventDelegate and call applyDynamicPrice to enable Nimbus
bannerView.appEventDelegate = self
bannerView.applyDynamicPrice(
requestManager: requestManager,
delegate: self,
ad: adLoader.nimbusAd
)
// When a price is returns for the ad, call updatePrice to notify the Nimbus SDK
bannerView.paidEventHandler = { [weak bannerView] adValue in
bannerView?.updatePrice(adValue)
}
view.addSubview(bannerView)
bannerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
bannerView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
bannerView.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor)
])
self.bannerView = bannerView
}
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
print("adLoader failedWithError \(error)")
}
}
Interstitials
lateinit var nimbusAdManager: NimbusAdManager
lateinit var nimbusRequest: NimbusRequest
/* Helper property to determine if the request did not fill */
inline val LoadAdError.isNoFill: Boolean
get() = code in intArrayOf(AdRequest.ERROR_CODE_NO_FILL, AdRequest.ERROR_CODE_MEDIATION_NO_FILL)
/**
* Helper function to create and set the Listeners required for Dynamic Price rendering.
*
* If using another implementation of AdListener, AppEventListener, onPaidEventListener the
* following four methods must be modified to send signals to the Nimbus SDK.
* @param auctionData Created after receiving a response from Nimbus
*/
fun AdManagerInterstitialAd.setNimbusListeners(auctionData: GoogleAuctionData) {
val eventListener = object : FullScreenContentCallback(), AppEventListener, OnPaidEventListener {
/** When an impression occurs, notify the NimbusAdManager with the responseInfo */
override fun onAdImpression() {
adManager.notifyImpression(auctionData, responseInfo)
}
/**
* This method is called when the AdManagerAdView loads the creative.
*
* Call handleEventForNimbus before any other code to ensure it receives the event.
*
* If handleEventForNimbus returns true, set nimbusWin on auctionData */
*/
override fun onAppEvent(name: String, info: String) {
if (handleEventForNimbus(name, info)) auctionData.nimbusWin = true
}
/** When pricing information is available, call onPaidEvent on auctionData */
override fun onPaidEvent(p0: AdValue) {
auctionData.onPaidEvent(p0)
}
}
/* Set the listeners on the instance of the AdManagerInterstitialAd */
appEventListener = eventListener
fullScreenContentCallback = eventListener
onPaidEventListener = eventListener
}
/* Dynamic Price request and rendering flow */
lifecycleScope.launch {
runCatching {
adManager.makeRequest(root.context, nimbusRequest)
}.onSuccess { nimbusAd ->
/* Create and store a GoogleAuctionData instance for use with this ad load */
val auctionData = GoogleAuctionData(nimbusAd)
/* Call applyDynamicPrice on the AdManagerRequest */
val adManagerRequest = AdManagerAdRequest.Builder()
.applyDynamicPrice(nimbusAd, mapping = priceMapping)
.build()
AdManagerInterstitialAd.load(requireContext(), unitId,
adManagerRequest, object : AdManagerInterstitialAdLoadCallback() {
override fun onAdLoaded(ad: AdManagerInterstitialAd) {
/* Ensure the Nimbus callbacks are included in the AdManagerInterstitialAd */
ad.setNimbusListeners(auctionData)
/* Display the interstitial */
ad.show(requireActivity())
}
})
}
}
import static com.adsbynimbus.google.DynamicPriceRenderer.handleEventForNimbus;
import static com.adsbynimbus.google.DynamicPriceWinLossKt.notifyImpression;
import static com.adsbynimbus.google.DynamicPriceWinLossKt.notifyNoFill;
import static com.adsbynimbus.lineitem.GoogleDynamicPrice.applyDynamicPrice;
class NimbusRenderingDynamicPriceInterstitial {
final static NimbusAdManager nimbusAdManager = new NimbusAdManager();
/**
* Helper function to create and set the Listeners required for Dynamic Price rendering.
*
* If using another implementation of AdListener, AppEventListener, onPaidEventListener the
* following four methods must be modified to send signals to the Nimbus SDK.
* @param interstitialAd The Google Interstitial
* @param response The Nimbus Response
*/
public static void setNimbusListeners(AdManagerInterstitialAd interstitialAd, NimbusResponse response) {
/* Create and store a GoogleAuctionData instance for use with this ad load */
final GoogleAuctionData auctionData = new GoogleAuctionData(response);
interstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() {
@Override
public void onAdImpression() {
notifyImpression(nimbusAdManager, auctionData, interstitialAd.getResponseInfo());
}
});
/*
* This method is called when the Intertstitial Ad loads the creative.
*
* Call handleEventForNimbus before any other code to ensure it receives the event.
*
* If handleEventForNimbus returns true, set nimbusWin on auctionData
*/
interstitialAd.setAppEventListener((name, info) -> {
if (handleEventForNimbus(interstitialAd, name, info)) {
auctionData.setNimbusWin(true);
}
});
/* When pricing information is available, call onPaidEvent on auctionData */
interstitialAd.setOnPaidEventListener(adValue -> auctionData.onPaidEvent(adValue));
}
/**
* Interstitial Example
*
* @param context Any context; an Activity is required to call show
* @param nimbusRequest A Nimbus interstitial request (i.e. NimbusRequest.forInterstitialAd(...))
* @param adManagerAdRequest The Google request builder, a new instance is required on each call
* @param unitId The interstitial ad unit id
*/
public static void example(Activity context, NimbusRequest nimbusRequest, AdManagerAdRequest.Builder adManagerAdRequest, String unitId) {
nimbusAdManager.makeRequest(context, nimbusRequest, new RequestManager.Listener() {
@Override
public void onAdResponse(@NonNull NimbusResponse nimbusResponse) {
/* Call apply Dynamic Price on the AdManagerRequest */
applyDynamicPrice(adManagerAdRequest, nimbusResponse, priceMapping);
/* Send the adManagerRequest to Google */
AdManagerInterstitialAd.load(context, unitId, adManagerAdRequest.build(), new AdManagerInterstitialAdLoadCallback() {
@Override
public void onAdLoaded(@NonNull AdManagerInterstitialAd interstitialAd) {
/* Ensure the Nimbus callbacks are included in the AdManagerInterstitialAd */
setNimbusListeners(interstitialAd, nimbusResponse);
/* Display the interstitial */
interstitialAd.show(context);
}
});
}
@Override
public void onError(@NonNull NimbusError error) {
if (error.errorType != NimbusError.ErrorType.NO_BID) {
/* A network or some other error occurred */
}
}
});
}
}
class NimbusRenderingViewController : UIViewController {
let requestManager = NimbusRequestManager()
var nimbusRequest: NimbusRequest
var priceMapping: NimbusGAMLinearPriceMapping
}
// Implement the interstitialAd method of the GADAppEventDelegate
extension NimbusRenderingViewController: GADAppEventDelegate {
// This method is called when the GADInterstitialAd loads the creative.
// Call handleEventForNimbus before any other code to ensure it receives the event.
func interstitialAd(_ interstitialAd: GADInterstitialAd, didReceiveAppEvent name: String, withInfo info: String?) {
interstitialAd.handleEventForNimbus(name: name, info: info)
}
}
// Implement the NimbusRequestManagerDelegate
extension NimbusRenderingViewController: NimbusRequestManagerDelegate {
func didCompleteNimbusRequest(request: NimbusRequest, ad: NimbusAd) {
// Load the GAMInterstitialAd and include the NimbusAd
loadInterstitial(nimbusAd: ad)
}
func didFailNimbusRequest(request: NimbusRequest, error: NimbusError) {
// Nimbus did not return an ad, continue with the interstitial load
loadInterstitial()
}
func loadInterstitial(nimbusAd: NimbusAd? = nil, gamRequest: GAMRequest = GAMRequest()) {
// Call applyDynamicPrice to append Nimbus parameters to the GAMRequest
nimbusAd?.applyDynamicPrice(into: gamRequest, mapping: mapping)
GAMInterstitialAd.load(
withAdManagerAdUnitID: adManagerAdUnitId,
request: gamRequest) { [weak self] interstitialAd, error in
// Notidy the NimbusRequestManager if an error occurs and return
if let error {
if let nimbusAd {
self?.requestManager.notifyError(ad: nimbusAd, error: error)
}
return
}
guard let self, let interstitialAd else { return }
if let ad = nimbusAd {
// Call applyDynamicPrice and set the appEventDelegeate to enable Nimbus
interstitialAd.applyDynamicPrice(
ad: ad,
requestManager: requestManager,
delegate: self
)
interstitialAd.appEventDelegate = self
interstitialAd.paidEventHandler = { [weak interstitialAd] adValue in
interstitialAd?.updatePrice(adValue)
}
} else {
interstitialAd.fullScreenContentDelegate = self
}
// Call presentDynamicPrice to initiate the load.
// If a NimbusAd was not present this will immediately call interstitialAd.present
DispatchQueue.main.async {
interstitialAd.presentDynamicPrice(fromRootViewController: self)
}
}
}
}
extension NimbusRenderingViewController {
// Send the request to Nimbus to start the Dynamic Price auction
func loadDynamicPriceInterstitialAd() {
requestManager.delegate = self
requestManager.performRequest(request: nimbusRequest)
}
}
Rewarded Video
import com.adsbynimbus.google.*
lateinit var nimbusAdManager: NimbusAdManager
var nimbusRequest: NimbusRequest = NimbusRequest.forRewardedVideo(position = )
object ExampleRewardCallback : NimbusRewardCallback {
override fun onAdImpression() { }
override fun onAdClicked() { }
override fun onAdPresented() { }
override fun onAdClosed() { }
override fun onUserEarnedReward(rewardItem: RewardItem) { }
override fun onError(nimbusError: NimbusError) { }
}
lifecycleScope.launch {
runCatching {
adManager.makeRequest(root.context, nimbusRequest)
}.onSuccess { nimbusAd ->
val adManagerRequest = AdManagerAdRequest.Builder()
.applyDynamicPrice(nimbusAd, mapping = priceMapping)
.build()
RewardedAd.load(requireActivity(), rewardedUnitId,
adManagerRequest, object : RewardedAdLoadCallback() {
override fun onAdLoaded(ad: RewardedAd) {
/* When ready to show the ad, use */
ad.showAd(requireActivity(), nimbusAd, adManager, ExampleRewardCallback)
}
})
}
}
class NimbusRenderingViewController : UIViewController {
let requestManager = NimbusRequestManager()
let dynamicPriceRenderer: NimbusDynamicPriceRenderer = NimbusDynamicPriceRenderer(requestManager)
var nimbusRequest: NimbusRequest
var priceMapping: NimbusGAMLinearPriceMapping
var rewardedAdPresenter: NimbusRewardedAdPresenter?
}
// Implement this listener to receive the Nimbus win notification
extension NimbusRenderingViewController: GADAdMetadataDelegate {
func adMetadataDidChange(_ ad: GADAdMetadataProvider) {
let isNimbusWin: Bool = dynamicPriceRenderer.handleRewardedEventForNimbus(
adMetadata: ad.adMetadata,
ad: rewardedAd
)
/* Show an ad whenever ready */
rewardedAdPresenter?.showAd(
isNimbusWin: isNimbusWin,
presentingViewController: self
)
}
}
// Implement the NimbusRewardedAdPresenterDelegate to receive Rewarded callbacks
extension NimbusRenderingViewController: NimbusRewardedAdPresenterDelegate {
func didTriggerImpression() { }
func didTriggerClick() { }
func didPresentAd() { }
func didCloseAd() { }
func didEarnReward(reward: GADAdReward) { }
func didReceiveError(error: NimbusError) { }
}
extension NimbusRenderingViewController: GADFullScreenContentDelegate {
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { }
func adDidRecordImpression(_ ad: GADFullScreenPresentingAd) { }
}
// Implement the NimbusRequestManagerDelegate
extension NimbusRenderingViewController: NimbusRequestManagerDelegate {
// Notify the dynamicPriceRenderer that Nimbus returned an Ad then send the GAMRequest
func didCompleteNimbusRequest(request: NimbusRequest, ad: NimbusAd) {
// Apply targeting parameters to the gamRequest
ad.applyDynamicPrice(into: gamRequest, mapping: priceMapping)
loadRewardedAd(gamRequest)
}
func didFailNimbusRequest(request: NimbusRequest, error: NimbusError) {
// Nimbus did not return an ad, send the request to Google
loadRewardedAd(gamRequest)
}
func loadRewardedAd(gamRequest: GAMRequest) {
GADRewardedAd.load(
withAdUnitID: googleDynamicPriceRewardedPlacementId,
request: gamRequest,
completionHandler: { [weak self] rewardedAd, error in
// If the Rewarded ad did not load, notify the requestManager
if let error {
if let errorCode = GADErrorCode(rawValue: (error as NSError).code),
errorCode == .noFill || errorCode == .mediationNoFill {
self?.requestManager.notifyLoss(ad: ad, auctionData: NimbusAuctionData(auctionPrice: "-1"))
}
return
}
guard let self, let rewardedAd else { return }
// Set the fullScreenContentDelegate and adMetadataDelegate
rewardedAd.fullScreenContentDelegate = self
rewardedAd.adMetadataDelegate = self
// When a price is returns for the ad, notify the dynamicPriceRenderer
rewardedAd.paidEventHandler = { [weak self] adValue in
self?.dynamicPriceRenderer.notifyRewardedPrice(
adValue: adValue,
fullScreenPresentingAd: rewardedAd
)
}
dynamicPriceRenderer.willRender(ad: ad, fullScreenPresentingAd: rewardedAd)
rewardedAdPresenter = NimbusRewardedAdPresenter(
request: request,
ad: ad,
rewardedAd: rewardedAd
)
rewardedAdPresenter?.delegate = self
}
)
}
}
extension NimbusRenderingViewController {
// Send the request to Nimbus to start the Dynamic Price auction
func loadDynamicPriceRewardedAd() {
requestManager.delegate = self
requestManager.performRequest(request: nimbusRequest)
}
}
Last updated