iOS integration documentation

iOS integration documentation

iOS SDK Integration Manual

Important Notice
Starting from Version 10, all libraries are integrated into the Yieldlove Pacakge. Please read carefully in the setup section.
For better resource management, we start to use iOS 15 from this version.

Ensure you are using the correct version for all dependencies.

Release Note (v10.5.0)

  • Added web Debug pages.

  • DisplayManager and DisplayManagerVer are updated. ("StroeerSDK", "10.5.0")

  • General bug fixes and stability improvements.

  • Updated third-party libraries:

    • CMP: 7.12.9

    • Google Mobile Ads SDK: 12.11.0>

Note:

  • Public CocoaPods Distribution

    • The public CocoaPods release of YieldloveAdIntegration will include only the following subspecs:

      • Core

      • Consent

    • pod 'YieldloveAdIntegration', '10.5.0'

    • This version uses:

      • Google Mobile Ads SDK 12.11.0

  • Private CocoaPods Distribution

  • Note: The difference in the Google Mobile Ads SDK version is due to compatibility constraints introduced by the Gravite plugin.

1. Overview

This manual shows how to integrate and setup YieldloveAdIntegration in your iOS app.

Find the CMP integration manual here: https://stroeerdigitalgroup.atlassian.net/wiki/spaces/SDGPUBLIC/pages/2408022033/iOS+CMP

2. Before you start

Receive an APPLICATION_NAME (to be set only once) and a PUBLISHER_CALL_STRING (represents the ad slot). Please contact your account manager at Ströer to get the APPLICATION_NAME and PUBLISHER_CALL_STRING. You will need to pass these two identifiers when requesting an ad using the SDK.

3. Try out our example app

We invite you to take a look at example app. It already contains test configuration, so you can try it even before receiving APPLICATION_NAME and PUBLISHER_CALL_STRING.

Example app can also clarify some implementation details. It is also possible to change settings of the app (as shown in app's README) and run it with your own configuration, after you receive it.

4. Adding SDK to your project

4.1. Cocoapods integration

The ad integration package is distributed as a “Pod”. Follow the instructions to install CocoaPods into your app. Afterwards the SDK dependency can be integrated.

Update repository
pod repo update

Edit your Podfile so that SDK is included as a dependency.

Include SDK pod
pod 'YieldloveAdIntegration', '10.5.0'
Then run
Install SDK
pod install

4.2. Swift Package Manager (SPM) integration

Open your App project in Xcode

  1. Select your YourAppName.xcodeproj file

  2. Click on ‘YourAppName’ below PROJECT

  3. Select Package Dependencies

  4. Click on the '+' Button

     

  5. In the URL field, enter: https://github.com//stroeerSDK-iOS-spm/ and select stroeersdk-ios-spm.

  6. Set the dependency rule to "Exact Version" and specify the desired version.

  7. Click Next and wait for the package to finish fetching.When prompted

  8. select Add to Target and choose the YieldloveAdIntegration dependencies for the libraries you want to include.

  9. Then click "Add Package".



 

Important note for SPM Only:
You must add -ObjC to your app target’s linker flags:

  1. Open your Xcode project.

  2. Select your app targetBuild Settings.

  3. Search for Other Linker Flags.

  4. Add -ObjC.

4.3. Required Google Mobile Ads SDK Dependency

The Google Mobile Ads SDK is not bundled automatically through the StroeerSDK Swift Package.

Publishers must add it manually at the app level.

Required Package

https://github.com/googleads/swift-package-manager-google-mobile-ads.git

Required Version

The required Google Mobile Ads SDK version depends on whether the Gravite plugin is used.

Integration

Required Google Mobile Ads SDK Version

Integration

Required Google Mobile Ads SDK Version

Core only

Exact 12.11.0

Core + Consent

Exact 12.11.0

Core + Confiant

Exact 12.11.0

Core + Consent + Confiant

Exact 12.11.0

Any integration including Gravite

Exact 12.2.0

Important

  • If your app uses YieldloveAdIntegration_Gravite, you must use Google Mobile Ads SDK exact version 12.2.0.

  • For all integrations without Gravite, use Google Mobile Ads SDK exact version 12.11.0.

  • Do not add multiple versions of the Google Mobile Ads SDK to the same project.

4.4. Plugin Integration

4.4.1. Core SDK

If you only use the core SDK, add:

YieldloveAdIntegration

You must also add the Google Mobile Ads SDK at the publisher app level:

  • Package:
    https://github.com/googleads/swift-package-manager-google-mobile-ads.git

  • Version:
    Exact 12.11.0

No additional publisher-managed plugin dependency is required for the core product.


4.4.2. Consent Plugin

If you use:

YieldloveAdIntegration_Consent

you must also add the following dependencies at the publisher app level.

Required Dependencies

Google Mobile Ads SDK

  • Package:
    https://github.com/googleads/swift-package-manager-google-mobile-ads.git

  • Version:
    Exact 12.11.0

SourcePoint CMP

  • Package:
    https://github.com/SourcePointUSA/ios-cmp-app.git

  • Version:
    Exact 7.12.9

Important

The Consent dependency is not bundled automatically through this package.
Publishers using YieldloveAdIntegration_Consent must add ios-cmp-app themselves.


4.4.3. Confiant Plugin

If you use:

YieldloveAdIntegration_Confiant

you must also add the Google Mobile Ads SDK at the publisher app level:

  • Package:
    https://github.com/googleads/swift-package-manager-google-mobile-ads.git

  • Version:
    Exact 12.11.0

The Confiant SDK is intentionally not bundled with the plugin and must be added by the publisher at the app level, if required by the integration.

Exact 6.1.3


4.4.4. Gravite Plugin

If you use:

YieldloveAdIntegration_Gravite

you must also add the following dependencies at the publisher app level.

Required Dependencies

Google Mobile Ads SDK

  • Package:
    https://github.com/googleads/swift-package-manager-google-mobile-ads.git

  • Version:
    Exact 12.2.0

AATKit

  • Package:
    https://github.com/AddApptr/AATKitSPM.git

  • Version:
    Exact 3.12.7

Important

The AATKit dependency is not bundled automatically through this package.
Publishers using YieldloveAdIntegration_Gravite must add AATKitSPM themselves.

Any app that includes the Gravite plugin must use:

  • Google Mobile Ads SDK exact version 12.2.0

This requirement also applies when Gravite is used together with Consent and/or Confiant.

5. Implementation

5.1. Setup

Before requesting an ad, you need to call Yieldlove.setup(appName:). This needs to be done only once. For example, in main application initializer.

Set application name
Yieldlove.setup(appName: "APPLICATION_NAME")

Note on caching: SDK relies on an external configuration to serve ads. Once the app requests the first ad with a certain app name, the configuration is cached on the user’s phone to reduce the number of http requests. It will refresh after a time limit specified in the config itself. During the integration, bear in mind you might need to reinstall the app after using a different appName to wipe configuration that is already downloaded.

5.2. Testing configuration

Use this configuration to start implementation even before receiving own configuration:

  • App name: appDfpTest

  • Banner ad slot: banner

  • Large banner ad slot: banner?large

  • Interstitial ad slot: interstitial

  • Rewarded ad slot: rewarded

5.3. Request a banner ad

5.3.1. Request a banner ad in Swift

Replace PUBLISHER_CALL_STRING placeholder.

Request a banner
Yieldlove.instance.bannerAd( adSlotId: "PUBLISHER_CALL_STRING", viewController: self, delegate: delegate )

Now implement YLBannerViewDelegate like this:

Full implementation
From SDK 10.5.0 onward, the YLBannerView returned by bannerAd(...) should be stored and added to the view hierarchy immediately after the request is created.

import UIKit import YieldloveAdIntegration import GoogleMobileAds final class BannerViewController: UIViewController, YLBannerViewDelegate { private var bannerView: YLBannerView? override func viewDidLoad() { super.viewDidLoad() let bannerView = Yieldlove.instance.bannerAd( adSlotId: "PUBLISHER_CALL_STRING", viewController: self, delegate: self ) self.bannerView = bannerView // Add the banner to the view hierarchy. // The publisher is responsible for placing the banner in their layout. // The SDK manages the banner's rendered size internally once the ad is loaded. view.addSubview(bannerView) } func bannerViewDidReceiveAd(_ bannerView: YLBannerView) { // Use getBannerSize() if your app needs to read the final rendered size. print("Banner received with size: \(bannerView.getBannerSize())") } func bannerView(_ bannerView: YLBannerView, didFailToReceiveAdWithError error: Error) { print("Banner failed to load: \(error.localizedDescription)") }

Using an SDK version below 10.5.0

For SDK versions prior to 10.5.0, the banner view should be added after the ad has loaded, inside bannerViewDidReceiveAd(_:). and resize must be called.

import UIKit import YieldloveAdIntegration import GoogleMobileAds class BannerViewController: UIViewController, YLBannerViewDelegate { var slotId: String = "" var onAdSize: ((CGSize) -> Void)? override func viewDidLoad() { super.viewDidLoad() Yieldlove.instance.bannerAd( adSlotId: slotId, viewController: self, delegate: self ) } func bannerViewDidReceiveAd(_ bannerView: YLBannerView) { view.addSubview(bannerView) Yieldlove.instance.resizeBanner(banner: bannerView) { onAdSize?(bannerView.getBannerSize()) } } func bannerView(_ bannerView: YLBannerView, didFailToReceiveAdWithError error: Error) { print("Banner failed to load: \(error.localizedDescription)") } }



5.3.2. Request a banner ad in Objective-C

Request a banner from ObjC
#import "ViewController.h" @import YieldloveAdIntegration; @interface ViewController () <YLBannerViewDelegate> @property (weak, nonatomic) IBOutlet UIView *adContainer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [Yieldlove setupWithAppName:@"APPLICATION_NAME"]; [Yieldlove.instance bannerAdWithAdSlotId: @"PUBLISHER_CALL_STRING" viewController: self delegate: self]; } - (void)bannerViewDidReceiveAd:(YLBannerView *)bannerView { [self.adContainer addSubview: bannerView.getBannerView]; } @end

5.4. Request an interstitial

5.4.1. Request an interstitial in Swift

Use the following code to show an interstitial. Replace PUBLISHER_CALL_STRING placeholder.

Request an interstitial
// // InterstitialView.swift // SimpleAdTest // // Created by Hyungon Kim on 29/07/2024. // import YieldloveAdIntegration import GoogleMobileAds class InterstitialView: NSObject, YLInterstitialAdDelegate { private var adSlotId: String? weak var viewController: UIViewController? weak var interstitial: GAMInterstitialAd? init(adSlotId: String, viewController: UIViewController) { self.adSlotId = adSlotId self.viewController = viewController } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } public func load() { if let adSlot = adSlotId { let gamRequest = GAMRequest() gamRequest.contentURL = "www.example.com" Yieldlove.instance.interstitialAd( adSlotId: adSlot, interstitialDelegate: self, viewController: viewController!, request: gamRequest) } } public func onAdLoaded(interstitial: YLInterstitialAd) { print("interstitial ad is from \(interstitial.getAdSource().description)") if let viewController = viewController { interstitial.show(viewController: viewController) } } public func onAdFailedToLoad(interstitial: YLInterstitialAd?, error: any Error) { print("interstitial ad failed to load with error: \(error.localizedDescription)") } }

To receive notifications about presentation of the interstitial ad(GAM), implement the GADFullScreenContentDelegate protocol of GADInterstitialAd in YLInterstitialAd class

public func onAdLoaded(interstitial: YLInterstitialAd) { print("interstitial ad is from \(interstitial.getAdSource().description)") if let gamInterstitial = interstitial.getInterstitialAd() { gamInterstitial.fullScreenContentDelegate = /* delegate */ } if let viewController = viewController { interstitial.show(viewController: viewController) } }

This method accepts a third optional parameter, a GAMRequest, useful to pass information like contentURL

The show method can be called after the interstitial is loaded. If it is not loaded, the interstitial will not be rendered.

 

5.4.2. Request an interstitial in Objective-C

Request an interstitial from ObjC
#import "InterstitialViewController.h" @import YieldloveAdIntegration; @import GoogleMobileAds; @interface InterstitialViewController () @property(nonatomic, strong) GAMInterstitialAd *interstitial; @end @implementation InterstitialViewController - (void)viewDidLoad { [super viewDidLoad]; [Yieldlove.instance setAppNameWithAppName:@"appDfpTest"]; [Yieldlove.instance interstitialAdWithAdSlotId: @"interstitial" completion: ^(GAMInterstitialAd *ad, NSError *error) { if (error) { NSLog(@"Failed to load interstitial ad with error: %@", [error localizedDescription]); return; } self.interstitial = ad; if (self.interstitial) { [self.interstitial presentFromRootViewController:self]; } else { NSLog(@"Ad wasn't ready"); } } request: nil ]; } @end

This method accepts a third optional parameter, a GAMRequest, useful to pass information like contentURL

5.5. Memory Management

SDK keeps a weak reference to the YLBannerViewDelegate object that app developers pass with ad request. This allows the developer not only to release resources when ad is not needed anymore, but also acts as a signal to the SDK to do internal cleanup.

When YLBannerViewDelegate reference becomes nil, the SDK will:

  • release all objects associated with this ad

  • stop refreshing the banner in case of auto-refreshable banners

App developers need to clear all strong references inside the app to the YLBannerViewDelegate object passed with ad request after the ad is not needed anymore. This typically requires that app developer decouples YLBannerViewDelegate implementation from UIView or ViewController.

Alternatively, clear the delegate from the bannerView after the ad is not needed anymore. This will have the same effect.

To reiterate, if your app:

  • Keeps one or more strong references to the YLBannerViewDelegate object that it passed with ad request

OR

  • Never clears the delegate from the ads that it serves

then it is impossible for SDK to perform cleanup and as a result, Swift ARC will not remove objects from memory. This means that over time, as the app serves more ads, memory usage will go up significantly. This may lead to performance problems and app being terminated by iOS.

5.6. Auto-refreshable Banners

SDK supports auto-refreshable ad slots. Ad slots are not auto-refreshable by default. Usually only a couple ad slots are configured as auto-refreshable.

Auto-refreshable ad slots will reload an ad after a configured time interval. Publishers need to take a couple more steps to implement auto-refreshable ad slots in addition to normal ad slots.

When banner is reloaded, SDK will call the same delegate method:

func bannerViewDidReceiveAd(_ bannerView: YLBannerView)

Since ad is reloaded into the same GADBannerView which is already added to the app view, publisher should not add the ad to the view again.

Note: Only add banner to view once

If two or more refreshable ad slots with the same ad slot id are placed in the view at the same time, only one of them will be refreshed.

IMPORTANT:

When implementing auto-refreshable ad slots it is crucial to signal to the SDK that ad is no longer in view. SDK will then stop the auto-refreshing. We recommend to set ad delegate to nil when ad is no longer needed. See chapter 5.5. Memory Management for details.

If app does not signal to the SDK that auto-refreshable ad is no longer needed, it will lead to unnecessary ad requests being made in background, reducing performance of the app, consuming battery and mobile data.

5.7. Rewarded ads

5.7.1. Request a rewarded ad in Swift

Use the following code to show a rewarded ad. Replace PUBLISHER_CALL_STRING placeholder.

Request a rewarded ad
Yieldlove.instance.rewardedAd( adSlotId: "PUBLISHER_CALL_STRING", completion: { (ad, error) in if let error = error { print("Failed to load rewarded ad with error: \(error.localizedDescription)") return } self.rewardedAd = ad self.rewardedAd?.fullScreenContentDelegate = self self.rewardedAd?.present(fromRootViewController: viewController) { let reward = rewardedAd?.adReward // reward user here } }) )

To receive notifications about rewarded ad, implement GADFullScreenContentDelegate protocol.

This method accepts a third optional parameter, a GAMRequest, useful to pass information like contentURL

6. Banner Ad Sizes

As the banner may not be the correct the size, we need to resize the banner.

you can get the banner size from .getBannerSize() function:

public func bannerViewDidReceiveAd(_ bannerView: YLBannerView) { print("banner size = \(bannerView.getBannerSize())") }


There are two ways of setting up ad unit sizes. In a 1:1 relation every ad unit is given a single size. All banners served by requesting this ad unit will have the same size. In 1:N relation ad unit may have more than one size. In this case banners may have different sizes. Depending on the setup, a different method should be used to get banner sizes.

6.1. One-to-one relation

Advantage of this setup is that ad sizes are known in advance.

To get banner ad sizes for ad slot use the following API method:

Get ad sizes
@objc public func getAdSizes(adSlotId: String, completion: @escaping GetAdSizesCompletion) // where: typealias GetAdSizesCompletion = (_ adSizes: NSArray, _ error: Error?) -> Void

Example in Swift:

Get ad sizes callback
Yieldlove.instance.getAdSizes(adSlotId: "homepage_article_b1", completion: { (adSizes, err) in for size in sizes { let adSize = GADAdSizeFromNSValue(size as! NSValue) print("Size object \(adSize)") print("Size object width \(adSize.size.width)") print("Size object height \(adSize.size.height)") } })

Or in Objective-C:

Get ad sizes from ObjC
typedef void (^GetAdSizesCompletion)(NSArray * _Nonnull, NSError * _Nullable); GetAdSizesCompletion completion = ^void (NSArray * _Nonnull adSizes, NSError * _Nullable error) { for (id object in adSizes) { GADAdSize adSize = GADAdSizeFromNSValue(object); NSLog(@"Size object width %d", (int)adSize.size.width); NSLog(@"Size object height %d", (int)adSize.size.height); } }; [Yieldlove.instance getAdSizesWithAdSlotId: @"homepage_b1" completion:completion];

6.2. One-to-many relation

Under this approach the sizes are determined after ad response. It is important to read the sizes after the resize function has returned.

To get banner ad sizes for ad slot use the following code in YLBannerViewDelegate implementation:

Get ad sizes in 1:N
public func bannerViewDidReceiveAd(_ bannerView: YLBannerView) { let banner = bannerView.getBannerSize() print("width: ", banner.width) print("height: ", banner.height) }

7. Ad Targeting (recommended)

Ad targeting is the process of delivering advertisements to a specific audience based on predefined criteria. It helps advertisers show ads to the right users at the right time, increasing engagement, relevance, and conversion rates.

Types of Ad Targeting

There are several methods of ad targeting used in digital advertising to reach the right audience effectively.

  1. Contextual Targeting

  • Ads are displayed based on the content of the website or app.

  • Uses keywords, topics, or page context to match relevant ads.

  • Example: Showing car insurance ads on a website about automobiles.

  1. Behavioral Targeting

  • Ads are shown based on a user’s past behavior, such as browsing history, clicks, and searches.

  • Uses cookies, tracking pixels, and device IDs to collect data.

  • Example: A user who searched for laptops sees ads for electronics and accessories.

  1. Demographic Targeting

  • Ads are targeted based on attributes such as age, gender, income, and education.

  • Example: A luxury watch brand might target men aged 30-50 with high income.

  1. Geographic (Geo) Targeting

  • Ads are displayed based on location, including country, city, ZIP code, or GPS data.

  • Example: A food delivery app shows different ads in New York compared to Los Angeles.

  1. Interest-Based Targeting

  • Ads are shown to users based on their interests, such as sports, technology, or fashion.

  • Data is collected from social media activity, website visits, or user profiles.

  • Example: A sportswear brand targets users interested in fitness and running.

  1. Retargeting (Remarketing)

  • Ads are shown to users who previously interacted with a brand but did not convert.

  • Uses tracking cookies to remind users about products they viewed.

  • Example: A user who visited an online store but did not purchase a phone sees ads for the same phone later.

  1. Device and Platform Targeting

  • Ads are shown based on the type of device, such as mobile, tablet, or desktop, and the operating system, such as iOS or Android.

  • Example: A mobile game app displays ads only to iOS users.

  1. Time-Based Targeting

  • Ads are displayed at specific times of the day or week when users are most active.

  • Example: A coffee shop runs ads promoting morning discounts between 7 AM and 10 AM.

We recommend to set contextual targeting parameters. Especially in cases where the user has not given consent in the CMP or ATT (iOS), we see better monetization if, for example, the content URL is available in the ad request.

7.1. Global Targeting

Global targeting allows you to set ad request properties that apply to all ads in your application. This ensures consistent targeting parameters across different ad placements without needing to define them for each ad request.

How It Works

  • Global targeting settings are applied to all ad requests, regardless of the ad slot or format.

  • Set as early as possible in the app lifecycle (e.g., during app initialization) to ensure all requests include the targeting parameters.

  • If a specific local targeting is set for an individual ad, it will override the global settings.

    let sampleTargets: [String: String] = [ "userAge": "25", "userInterest": "sports, technology, music", "userLocation": "New York" ] Yieldlove.instance.setCustomTargets(targets: sampleTargets)

We strongly recommend setting global targeting, especially when user consent is not given in the Consent Management Platform (CMP). In such cases, monetization performance improves when relevant contextual data, such as the Content URL, can be included in the ad request.

7.2. Local Targeting - adSlot/adView Specified

Implement getGAMRequest() method of YLBannerViewDelegate. Return a GAMRequest from this method that contains your desired targeting. This is the same delegate that you will pass as an argument when making an ad request with the SDK.

Supply other properties with request
import GoogleMobileAds class MyYLBannerDelegate: YLBannerViewDelegate { public func getGAMRequest() -> GAMRequest { let request = GAMRequest() request.contentURL = "https://www.example.com" return request } }

For interstitials please pass a GAMRequest as third optional argument to the ad call.

Passing contentURL to an interstitial request
... let gamRequest = GAMRequest() gamRequest.contentURL = "https://www.example.com" Yieldlove.instance.interstitialAd(adSlotId: adSlot, completion: { (ad, error) in if let error = error { print("Failed to load interstitial ad with error: \(error.localizedDescription)") return } self.interstitial = ad self.interstitial?.fullScreenContentDelegate = self self.interstitial?.present(fromRootViewController: viewController) }, request: gamRequest) ...
Passing custom key-values to an interstitial request
... let gamRequest = GAMRequest() gamRequest.customTargeting = ["custom-key": "custom-value"] Yieldlove.instance.interstitialAd(adSlotId: adSlot, completion: { (ad, error) in if let error = error { print("Failed to load interstitial ad with error: \(error.localizedDescription)") return } self.interstitial = ad self.interstitial?.fullScreenContentDelegate = self self.interstitial?.present(fromRootViewController: viewController) }, request: gamRequest) ...

How this works Before SDK makes an ad request it calls this method, takes the targeting that you pass, and applies it to the request. Values passed through this method have higher priority than properties of same name that are set on global level. Values set on global level will be overridden by values passed through this method, unless it is possible to combine them (for example, in case of dictionaries).

8. Enable ID5

Starting from Version 10, the SDK supports ID5. This feature is disabled by default. To enable it, please contact your Ströer account manager.

You don’t need to make any code changes to use ID5. However, for improved identification, you can provide additional user information to ID5. Please refer to the ID5 website for details.

This information can be added at any time. StroeerSDK automatically checks the provided variables and updates the ID from ID5. However, for optimal identification, we recommend setting this information before SDK initialization, if possible.

To use ID5, the user must provide consent as required by the publisher. Additionally, if the user opts out of ID5 in their privacy settings, the SDK will not use ID5.

var customInfo = IdentityCustomInfo() customInfo.email = "customeremail@domain.com"; customInfo.phone = "phonenumber"; customInfo.puid = "ID"; customInfo.regionCode = "RegionalCode"; customInfo.cityCode = "CityCode"; IdentityManager.shared.setCustomInfo(customInfo)