diff --git a/prebid-mobile/modules/rendering/android-sdk-integration-pb.md b/prebid-mobile/modules/rendering/android-sdk-integration-pb.md index 9215c191c5..4c221aaee0 100644 --- a/prebid-mobile/modules/rendering/android-sdk-integration-pb.md +++ b/prebid-mobile/modules/rendering/android-sdk-integration-pb.md @@ -17,7 +17,7 @@ You can use Prebid SDK to monetize your app with a custom ad server or even with ## Transport API -The default ad server for Prebid's Mobile SDK is GAM. The SDK can be expanded to include support for 3rd party ad servers through the fetchDemand function. This function returns the Prebid Server bidder key/values (targeting keys), which can then be passed to the ad server of choice. +The default ad server for Prebid's Mobile SDK is GAM. The SDK can be expanded to include support for 3rd party ad servers through the fetchDemand function. This function returns the Prebid Server bidder key/values (targeting keys), which can then be passed to the ad server of choice. In this mode, the publisher will be responsible for the following actions: @@ -39,46 +39,43 @@ This approach is avaliable for the following ad formats: The basic integration steps for these ad units you can find at the page for integration using [Original API](/prebid-mobile/pbm-api/android/android-sdk-integration-gam-original-api.html). The diference is that you should use the `fetchDemand` function with following signature: ```kotlin -public void fetchDemand(@NonNull Object adObj, - @NonNull OnCompleteListener2 listener) { ... } - -public interface OnCompleteListener2 { - /** - * This method will be called when PrebidMobile finishes attaching keywords to unmodifiableMap. - * @param resultCode see {@link ResultCode} class definition for details - * @param unmodifiableMap a map of targeting Key/Value pairs - */ - @MainThread - void onComplete(ResultCode resultCode, - @Nullable Map unmodifiableMap); -} +public void fetchDemand(OnFetchDemandResult listener) { ... } + +public interface OnFetchDemandResult { + void onComplete(@NonNull BidInfo bidInfo); +} ``` Examples: -```kotlin -private fun loadRewardedVideo() { - adUnit?.fetchDemand { resultCode, unmodifiableMap -> - val keywords: Map = HashMap(unmodifiableMap) +``` kotlin +adUnit?.fetchDemand { result -> + if(result.getResultCode() == ResultCode.SUCCESS) { + val keywords = resultCode.targetingKeywords - adServerObject.loadRewardedVideo(ADUNITID_REWARDED, keywords) + makeAdRequest(keywords) } } ``` +The `BidInfo` provides the following properties: + +* `resultCode` - the object of type `ResultCode` describing the status of the bid request. +* `targetingKeywords` - the targeting keywords of the winning bid +* `exp` - the number of seconds that may elapse between the auction and the actual impression. In this case, it indicates the approximate TTL of the bid in the Prebid Cache. Note that the actual expiration time of the bid will be less than this number due to the network and operational overhead. The Prebid SDK doesn't make any adjustments to this value. +* `nativeAdCacheId` - the local cache ID of the winning bid. Applied only to the `native` ad format. + ## Rendering API -The integration and usage of the Rendering API is similar to any other Ad SDK. It sends the bid requests to the Prebid Server and renders the winning bid. +The integration and usage of the Rendering API is similar to any other Ad SDK. It sends the bid requests to the Prebid Server and renders the winning bid. ![Rendering with GAM as the Primary Ad Server](/assets/images/prebid-mobile/modules/rendering/Prebid-In-App-Bidding-Overview-Pure-Prebid.png) - ### Banner API Integration example: - -```kotlin +``` kotlin // 1. Create an Ad View bannerView = BannerView(requireContext(), configId, adSize) bannerView?.setBannerListener(this) @@ -90,8 +87,8 @@ viewContainer?.addView(bannerView) bannerView?.loadAd() ``` -{% capture warning_note %} -Pay attention that the `loadAd()` should be called on the main thread. +{% capture warning_note %} +Pay attention that the `loadAd()` should be called on the main thread. {% endcapture %} {% include /alerts/alert_warning.html content=warning_note %} @@ -100,23 +97,23 @@ Pay attention that the `loadAd()` should be called on the main thread. Initialize the `BannerAdView` with properties: -- `configId` - an ID of a [Stored Impression](/prebid-server/features/pbs-storedreqs.html) on the Prebid server -- `size` - the size of the ad unit which will be used in the bid request. +* `configId` - an ID of a [Stored Impression](/prebid-server/features/pbs-storedreqs.html) on the Prebid server +* `size` - the size of the ad unit which will be used in the bid request. #### Step 2: Load the Ad {:.no_toc} Call `loadAd()` and SDK will: -- make bid request to Prebid -- render the winning bid on display +* make bid request to Prebid +* render the winning bid on display #### Outstream Video {:.no_toc} For **Banner Video** you will also need to specify the `bannerView.videoPlacementType`: -```kotlin +``` kotlin bannerView.videoPlacementType = PlacementType.IN_BANNER // or any other available type ``` @@ -124,7 +121,7 @@ bannerView.videoPlacementType = PlacementType.IN_BANNER // or any other availabl Integration example: -```kotlin +``` kotlin // 1. Create an Interstitial Ad Unit interstitialAdUnit = InterstitialAdUnit(requireContext(), configId, minSizePercentage) interstitialAdUnit?.setInterstitialAdUnitListener(this) @@ -137,27 +134,27 @@ interstitialAdUnit?.loadAd() interstitialAdUnit?.show() ``` -{% capture warning_note %} -Pay attention that the `loadAd()` should be called on the main thread. +{% capture warning_note %} +Pay attention that the `loadAd()` should be called on the main thread. {% endcapture %} {% include /alerts/alert_warning.html content=warning_note %} The **default** ad format for interstitial is **DISPLAY**. In order to make a `multiformat bid request`, set the respective values into the `adUnitFormats` parameter. -``` +``` kotlin interstitialAdUnit = InterstitialAdUnit( - requireContext(), - configId, + requireContext(), + configId, EnumSet.of(AdUnitFormat.BANNER, AdUnitFormat.VIDEO)) ``` #### Step 1: Create an Ad Unit {:.no_toc} -Initialize the `InterstitialAdUnit ` with properties: +Initialize the `InterstitialAdUnit` with properties: -- `configId` - an ID of a [Stored Impression](/prebid-server/features/pbs-storedreqs.html) on the Prebid server -- `minSizePercentage` - specifies the minimum width and height percent an ad may occupy of a device’s real estate. +* `configId` - an ID of a [Stored Impression](/prebid-server/features/pbs-storedreqs.html) on the Prebid server +* `minSizePercentage` - specifies the minimum width and height percent an ad may occupy of a device’s real estate. You can also assign the listener for processing ad events. @@ -173,7 +170,7 @@ Call the `loadAd()` to make a bid request. Wait until the ad is loaded and present it to the user in any suitable time. -```kotlin +``` kotlin override fun onAdLoaded(interstitialAdUnit: InterstitialAdUnit) { //Ad is ready for display } @@ -183,11 +180,11 @@ override fun onAdLoaded(interstitialAdUnit: InterstitialAdUnit) { Integration example: -```kotlin +``` kotlin // 1. Create an Ad Unit rewardedAdUnit = RewardedAdUnit(requireContext(), configId) rewardedAdUnit?.setRewardedAdUnitListener(this) - + // 2. Execute the loadAd function rewardedAdUnit?.loadAd() @@ -197,8 +194,8 @@ rewardedAdUnit?.loadAd() rewardedAdUnit?.show() ``` -{% capture warning_note %} -Pay attention that the `loadAd()` should be called on the main thread. +{% capture warning_note %} +Pay attention that the `loadAd()` should be called on the main thread. {% endcapture %} {% include /alerts/alert_warning.html content=warning_note %} @@ -207,7 +204,7 @@ Pay attention that the `loadAd()` should be called on the main thread. Create the `RewardedAdUnit` object with parameters: -- `adUnitId` - an ID of Stored Impression on the Prebid server. +* `adUnitId` - an ID of Stored Impression on the Prebid server. #### Step 2: Load the Ad {:.no_toc} @@ -219,7 +216,7 @@ Call the `loadAd()` to make a bid request. Wait until the ad is loaded and present it to the user in any suitable time. -```kotlin +``` kotlin override fun onAdLoaded(rewardedAdUnit: RewardedAdUnit) { //Ad is ready for display } diff --git a/prebid-mobile/modules/rendering/ios-sdk-integration-pb.md b/prebid-mobile/modules/rendering/ios-sdk-integration-pb.md index 5282ec6b82..8fe5952a0f 100644 --- a/prebid-mobile/modules/rendering/ios-sdk-integration-pb.md +++ b/prebid-mobile/modules/rendering/ios-sdk-integration-pb.md @@ -17,17 +17,17 @@ You can use Prebid SDK to monetize your app with a custom ad server or even with ## Transport API -The default ad server for Prebid's Mobile SDK is GAM. The SDK can be expanded to include support for 3rd party ad servers through the fetchDemand function. This function returns the Prebid Server bidder key/values (targeting keys), which can then be passed to the ad server of choice. +The default ad server for Prebid's Mobile SDK is GAM. The SDK can be expanded to include support for 3rd party ad servers through the fetchDemand function. This function returns additional bid information like Prebid Server bidder key/values (targeting keys), which can then be passed to the ad server of choice. In this mode, the publisher will be responsible for the following actions: -* Call fetchDemand with extended targetingDict callback -* Retrieve targeting keys from extended fetchDemand function +* Call the `fetchDemand` method with specific callback +* Retrieve targeting keys from the `BidInfo` callback parameter * Convert targeting keys into the format for your ad server * Pass converted keys to your ad server * Render ad with Prebid Universal Creative or custom renderer -This approach is avaliable for the following ad formats: +This approach is available for the following ad formats: * Display Banner via `BannerAdUnit` * Video Banner and Instream Video via `VideoAdUnit` @@ -35,42 +35,37 @@ This approach is avaliable for the following ad formats: * Video Interstitial via `VideoInterstitialAdUnit` * Rewarded Video via `RewardedVideoAdUnit` * Native Styles via `NativeRequest` +* Multiformat ad unit via `PrebidAdUnit` The basic integration steps for these ad units you can find at the page for integration using [Original API](/prebid-mobile/pbm-api/ios/ios-sdk-integration-gam-original-api.html). The diference is that you should use the `fetchDemand` function with following signature: -```swift -dynamic public func fetchDemand( - completion: @escaping(_ result: ResultCode, - _ kvResultDict: [String : String]?) -> Void) +``` swift +public func fetchDemand(adObject: AnyObject, request: PrebidRequest, + completion: @escaping (BidInfo) -> Void) ``` Examples: -```swift -func loadBanner() { - - //adUnit is BannerAdUnit type - adUnit.fetchDemand { [weak self] (resultCode: ResultCode, targetingDict: [String : String]?) in - - self?.adServerRequest.customTargeting = targetingDict - self?.adServerBanner.load(self?.adServerRequest) - } -} +``` swift +adUnit.fetchDemand(adObject: gamRequest, request: prebidRequest) { [weak self] bidInfo in + guard let self = self else { return } -func loadRewardedVideo() { - let adUnit = RewardedVideoAdUnit(configId: "1001-1") - adUnit.fetchDemand { [weak self] (resultCode: ResultCode, targetingDict: [String : String]?) in - //Publisher should provide support for converting keys into format of 3rd party ad server and loading ads - let keywords = convertDictToAdServerKeywords(dict: targetingDict) - AdServerLoadAds.loadAd(withAdUnitID: "46d2ebb3ccd340b38580b5d3581c6434", keywords: keywords) - } + let keywords = convertDictToAdServerKeywords(dict: bidInfo.targetingKeywords) + AdServerLoadAds.loadAd(withAdUnitID: "46d2ebb3ccd340b38580b5d3581c6434", keywords: keywords) } ``` +The `BidInfo` provides the following properties: + +* `resultCode` - the object of type `ResultCode` describing the status of the bid request. +* `targetingKeywords` - the targeting keywords of the winning bid +* `exp` - the number of seconds that may elapse between the auction and the actual impression. In this case, it indicates the approximate TTL of the bid in the Prebid Cache. Note that the actual expiration time of the bid will be less than this number due to the network and operational overhead. The Prebid SDK doesn't make any adjustments to this value. +* `nativeAdCacheId` - the local cache ID of the winning bid. Applied only to the `native` ad format. + ## Rendering API -The Rendering API integration and usage are similar to any other Ad SDK. In this case, Prebid SDK sends the bid requests to the Prebid Server and renders the winning bid. +The Rendering API integration and usage are similar to any other Ad SDK. In this case, Prebid SDK sends the bid requests to the Prebid Server and renders the winning bid. ![In-App Bidding with Prebid](/assets/images/prebid-mobile/modules/rendering/Prebid-In-App-Bidding-Overview-Pure-Prebid.png) @@ -78,14 +73,14 @@ The Rendering API integration and usage are similar to any other Ad SDK. In this Integration example: -```swift +``` swift // 1. Create an Ad View let banner = BannerView(frame: CGRect(origin: .zero, size: adSize), configID: CONFIG_ID, adSize: adSize) - + banner.delegate = self - + // 2. Load an Ad banner.loadAd() ``` @@ -95,24 +90,24 @@ banner.loadAd() Initialize the `BannerAdView` with properties: -- `frame` - the frame rectangle for the view -- `configID` - an ID of the Stored Impression on the Prebid Server -- `size` - the size of the ad unit which will be used in the bid request. +* `frame` - the frame rectangle for the view +* `configID` - an ID of the Stored Impression on the Prebid Server +* `size` - the size of the ad unit which will be used in the bid request. #### Step 2: Load the Ad {:.no_toc} Call the method `loadAd()` which will: -- make a bid request to the Prebid Server. -- render the winning bid on display. +* make a bid request to the Prebid Server. +* render the winning bid on display. #### Outstream Video {:.no_toc} For **Banner Video** you also need to specify the ad format: -```swift +``` swift banner.adFormat = .video ``` @@ -120,13 +115,13 @@ banner.adFormat = .video Integration example: -```swift +``` swift // 1. Create an Interstitial Ad Unit interstitial = InterstitialRenderingAdUnit(configID: CONFIG_ID, minSizePercentage: CGSize(width: 30, height: 30)) - + interstitial.delegate = self - + // 2. Load an Ad interstitial.loadAd() @@ -141,14 +136,14 @@ if interstitial.isReady { The **default** ad format for interstitial is **.banner**. In order to make a `multiformat bid request`, set the respective values into the `adFormats` property. -```swift -// Make bid request for video ad +``` swift +// Make bid request for video ad adUnit?.adFormats = [.video] -// Make bid request for both video and banner ads +// Make bid request for both video and banner ads adUnit?.adFormats = [.video, .banner] -// Make bid request for banner ad (default behaviour) +// Make bid request for banner ad (default behaviour) adUnit?.adFormats = [.banner] ``` @@ -157,9 +152,9 @@ adUnit?.adFormats = [.banner] {:.no_toc} Initialize the Interstitial Ad Unit with properties: - -- `configID` - an ID of Stored Impression on the Prebid Server -- `minSizePercentage` - specifies the minimum width and height percent an ad may occupy of a device’s real estate. + +* `configID` - an ID of Stored Impression on the Prebid Server +* `minSizePercentage` - specifies the minimum width and height percent an ad may occupy of a device’s real estate. > **NOTE:** minSizePercentage - plays an important role in a bidding process for banner ads. If provided space is not enough demand partners won't respond with the bids. @@ -173,9 +168,9 @@ Call the method `loadAd()` which will make a bid request to Prebid server. Wait until the ad will be loaded and present it to the user in any suitable time. -```swift +``` swift // MARK: InterstitialRenderingAdUnitDelegate - + func interstitialDidReceiveAd(_ interstitial: InterstitialRenderingAdUnit) { // Now the ad is ready for display } @@ -185,11 +180,11 @@ func interstitialDidReceiveAd(_ interstitial: InterstitialRenderingAdUnit) { Integration example: -```swift +``` swift // 1. Create an Ad Unit rewardedAd = RewardedAdUnit(configID: CONFIG_ID) rewardedAd.delegate = self - + // 2. Load an Ad rewardedAd.loadAd() @@ -201,13 +196,12 @@ if rewardedAd.isReady { } ``` - #### Step 1: Create Rewarded Ad Unit {:.no_toc} Create the `RewardedAdUnit` object with parameter: -- `configID` - an ID of Stored Impression on the Prebid Server +* `configID` - an ID of Stored Impression on the Prebid Server #### Step 2: Load the Ad {:.no_toc} @@ -219,10 +213,10 @@ Call the `loadAd()` method which will make a bid request to Prebid server. Wait until the ad will be loaded and present it to the user in any suitable time. -```swift +``` swift // MARK: RewardedAdUnitDelegate - + func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { // Now the ad is ready for display -} +} ``` diff --git a/prebid-mobile/pbm-api/android/android-sdk-integration-gam-original-api.md b/prebid-mobile/pbm-api/android/android-sdk-integration-gam-original-api.md index b8f2909ca4..3e7559b162 100755 --- a/prebid-mobile/pbm-api/android/android-sdk-integration-gam-original-api.md +++ b/prebid-mobile/pbm-api/android/android-sdk-integration-gam-original-api.md @@ -1120,6 +1120,305 @@ Without it the SDK won't be able to recognize the Prebid line item. Once the Prebid line item is recognized you should extract the ad from the winning bid and init the view properties with native assets data. +## Multiformat API + +Starting with version `2.1.5` Prebid SDK supports the fully multiformat ad unit. It allows to run bid requests with any combination of `banner`, `video`, and `native` formats. + +The following code demonstrates the integration of multiformat ad unit. + +``` kotlin +private fun createAd() { + // random() only for test cases, in production use only one config id + val configId = listOf(CONFIG_ID_BANNER, CONFIG_ID_VIDEO, CONFIG_ID_NATIVE).random() + + // Step 1: Create a PrebidAdUnit + prebidAdUnit = PrebidAdUnit(configId) + + // Step 2: Create PrebidRequest + val prebidRequest = PrebidRequest() + + // Step 3: Setup the parameters + prebidRequest.setBannerParameters(createBannerParameters()) + prebidRequest.setVideoParameters(createVideoParameters()) + prebidRequest.setNativeParameters(createNativeParameters()) + + // Step 4: Make a bid request + val gamRequest = AdManagerAdRequest.Builder().build() + prebidAdUnit?.fetchDemand(prebidRequest, gamRequest) { + // Step 5: Load an Ad + + loadGam(gamRequest) + } +} + +private fun createBannerParameters(): BannerParameters { + val parameters = BannerParameters() + parameters.api = listOf(Signals.Api.MRAID_3, Signals.Api.OMID_1) + + return parameters +} + +private fun createVideoParameters(): VideoParameters { + return VideoParameters(listOf("video/mp4")) +} + +private fun createNativeParameters(): NativeParameters { + val assets = mutableListOf() + + val title = NativeTitleAsset() + title.setLength(90) + title.isRequired = true + assets.add(title) + + val icon = NativeImageAsset(20, 20, 20, 20) + icon.imageType = NativeImageAsset.IMAGE_TYPE.ICON + icon.isRequired = true + assets.add(icon) + + val image = NativeImageAsset(200, 200, 200, 200) + image.imageType = NativeImageAsset.IMAGE_TYPE.MAIN + image.isRequired = true + assets.add(image) + + val data = NativeDataAsset() + data.len = 90 + data.dataType = NativeDataAsset.DATA_TYPE.SPONSORED + data.isRequired = true + assets.add(data) + + val body = NativeDataAsset() + body.isRequired = true + body.dataType = NativeDataAsset.DATA_TYPE.DESC + assets.add(body) + + val cta = NativeDataAsset() + cta.isRequired = true + cta.dataType = NativeDataAsset.DATA_TYPE.CTATEXT + assets.add(cta) + + val nativeParameters = NativeParameters(assets) + nativeParameters.addEventTracker( + NativeEventTracker( + NativeEventTracker.EVENT_TYPE.IMPRESSION, + arrayListOf(NativeEventTracker.EVENT_TRACKING_METHOD.IMAGE) + ) + ) + nativeParameters.setContextType(NativeAdUnit.CONTEXT_TYPE.SOCIAL_CENTRIC) + nativeParameters.setPlacementType(NativeAdUnit.PLACEMENTTYPE.CONTENT_FEED) + nativeParameters.setContextSubType(NativeAdUnit.CONTEXTSUBTYPE.GENERAL_SOCIAL) + + return nativeParameters +} +``` + +If you use Custom Native Ads follow the [guide](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/native-banner) on how to implement processing of the ad response of the respective type. The following code snipet demonstrates how you can process the banner, video and in-banner native (Native Styles) ad resposnse: + +``` kotlin +private fun loadGam(gamRequest: AdManagerAdRequest) { + val onBannerLoaded = OnAdManagerAdViewLoadedListener { adView -> + showBannerAd(adView) + } + + val onNativeLoaded = OnNativeAdLoadedListener { nativeAd -> + showNativeAd(nativeAd, adWrapperView) + } + + val onPrebidNativeAdLoaded = OnCustomFormatAdLoadedListener { customNativeAd -> + showPrebidNativeAd(customNativeAd) + } + + // Prepare the lisners for multiformat Ad Response + val adLoader = AdLoader.Builder(this, AD_UNIT_ID) + .forAdManagerAdView(onBannerLoaded, AdSize.BANNER, AdSize.MEDIUM_RECTANGLE) + .forNativeAd(onNativeLoaded) + .forCustomFormatAd(CUSTOM_FORMAT_ID, onPrebidNativeAdLoaded, null) + .withAdListener(AdListenerWithToast(this)) + .withAdManagerAdViewOptions(AdManagerAdViewOptions.Builder().build()) + .build() + + adLoader.loadAd(gamRequest) +} +``` + +The methods managing the prebid and GAM ads: + +``` kotlin +private fun showBannerAd(adView: AdManagerAdView) { + adWrapperView.addView(adView) + AdViewUtils.findPrebidCreativeSize(adView, object : AdViewUtils.PbFindSizeListener { + override fun success(width: Int, height: Int) { + adView.setAdSizes(AdSize(width, height)) + } + + override fun failure(error: PbFindSizeError) {} + }) +} + +private fun showNativeAd(ad: NativeAd, wrapper: ViewGroup) { + val nativeContainer = View.inflate(wrapper.context, R.layout.layout_native, null) + + val icon = nativeContainer.findViewById(R.id.imgIcon) + val iconUrl = ad.icon?.uri?.toString() + if (iconUrl != null) { + ImageUtils.download(iconUrl, icon) + } + + val title = nativeContainer.findViewById(R.id.tvTitle) + title.text = ad.headline + + val image = nativeContainer.findViewById(R.id.imgImage) + val imageUrl = ad.images.getOrNull(0)?.uri?.toString() + if (imageUrl != null) { + ImageUtils.download(imageUrl, image) + } + + val description = nativeContainer.findViewById(R.id.tvDesc) + description.text = ad.body + + val cta = nativeContainer.findViewById