Integrating Feed Ads in iOS
This guide walks you through all necessary steps to integrate feed ads into your iOS app.
If you have not done so already, please start with the Getting Started guide before reading on.
Integration
Overview
Follow these steps to integrate feed ads into your app:
- Prepare your UI
- Prepare your UIViewController
- Set Up and Load a Feed Ad
- Implement
FAFeedAdDelegate
- Implement resizing
Depending on the complexity of your UI and the behavior you want to achieve, this will take you between 30 and 60 minutes.
1. Prepare your UI
Choose a place in your UI, where you would like to integrate feed ads. You need a container view to hold a feed ad. You could place it in a UICollectionView
, a UITableView
or even a static view somewhere in your UI.
Using a simple UIView
Create your container view, and prepare its UI to hold your feed ad.
Using a UICollectionView
Create a subclass of UICollectionView
, and prepare its UI to hold your feed ad.
Using a UITableView
Create a subclass of UITableView
, and prepare its UI to hold your feed ad.
2. Prepare your UIViewController
Create a property to hold your instance of FAFeedAd
in your view controller. Make sure it is
cleaned up when the view controller disappears.
Using Objective-C:
@interface FeedAdViewController () @property (nonatomic, strong) FAFeedAd *feedAd; @end @implementation FeedAdViewController - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.feedAd cancel]; [self.feedAd.adView removeFromSuperview]; self.feedad.delegate = nil; self.feedAd = nil; } @end
Using Swift:
class FeedAdViewController: UIViewController { var feedAd: FAFeedAd? = nil override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) feedAd?.cancel() feedAd?.adView.removeFromSuperview() feedAd?.delegate = nil feedAd = nil } }
3. Set Up and Load a Feed Ad
Set up a feed ad by intializing it with a placement id and setting its
delegate. Finally, call load
to have the SDK load an ad.
Placement ID?
You can choose placement IDs yourself. A placement ID should be named after the ad position inside your product.
For example, if you want to display an ad inside a list of news articles, you could name it "ad-news-overview".
A placement ID may consist of lowercase a-z
, 0-9
, -
and _
. You do not have to manually create the placement IDs before using them.
Just specify them within the code, and they will appear in the FeedAd admin panel after the first request.
Learn more about Placement IDs and how they are grouped to play the same Creative
Using Objective-C:
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // Setup FAFeedAdConfig FAFeedAdConfig *config = [FAFeedAdConfig new]; config.placementId = @"your-placement-id"; // Set up your FAFeedAd instance self.feedAd = [[FAFeedAd alloc] initWithConfig:config]; self.feedAd.delegate = self; // Load ad [self.feedAd load]; }
Using Swift:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Setup FAFeedAdConfig let config = FAFeedAdConfig() config.placementId = "your-placement-id" // Set up your FAFeedAd instance feedAd = FAFeedAd(config: config) feedAd?.delegate = self feedAd?.load() }
4. Implement FAFeedAdDelegate
Declare conformance to the protocol FAFeedAdDelegate
and implement its methods in your view controller.
Feed ads start playing as soon as the ad view of an
FAFeedAd
becomes visible in your UI. Add it to your container view, when the method feedAdDidFinishLoading:
gets
called.
If a feed ad has no more ads to display, feedAdDidFinishPlaying:
, will be called.
If an error occurs feedAd:didFailWithError:
will be called.
In all three cases, remove the ad view of FAFeedAd
from your UI.
Ads within lists
FeedAds are meant to be displayed within scrollable content. Try to hold
content for your UICollectionView
or UITableView
inside a
(multi-dimensional) array that maps to your sections and rows / items to be
displayed. Your implementations of UICollectionViewDelegate
or
UITableViewDelegate
should then fetch content from that array to set up the
correct cell for the type of data at hand.
Injecting ads in-between your content is then merely a task of injecting
your FAFeedAd
instance into your content array using a for
loop. The
code for injecting ads can be easily shared between instances of
UIViewController
by embedding it inside different classes based on the
strategy pattern.
In the following code examples, this injection is resembled by the method injectFeedAd:into:
.
Using a simple UIView
Using Objective-C:
- (void)feedAdDidFinishLoading:(FAFeedAd *)feedAd { // Add ad view to container view UIView *adView = self.feedAd.adView; adView.frame = self.adContainerView.bounds; [self.adContainerView addSubview:adView]; }
Using Swift:
func feedAdDidFinishLoading(_ feedAd: FAFeedAd!) { // Add ad view to container view if let adView = feedAd.adView { adView.frame = adContainerView.bounds adContainerView.addSubview(adView) } }
Using a UICollectionView
Using Objective-C:
- (void)feedAdDidFinishLoading:(FAFeedAd *)feedAd { // Inject the feed ad into a copy of your content data self.displayedData = [self injectFeedAd:self.feedAd into:self.data]; [self.collectionView reloadData]; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { id data = [self.displayedData objectAtIndex:indexPath.row]; if ([data isKindOfClass:[FAFeedAd class]]) { FAFeedAd *feedAd = (FAFeedAd *) data; FAFeedAdCollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([FAFeedAdCollectionViewCell class]) forIndexPath:indexPath]; [cell injectAdView:feedAd.adView]; return cell; } // ... return nil; }
Using Swift:
func feedAdDidFinishLoading(_ feedAd: FAFeedAd!) { // Inject the feed ad into a copy of your content data displayData = injectFeedAd(feedAd, into: data) collectionView.reloadData() } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let currentElement = displayData[indexPath.row] if let ad = currentElement as? FAFeedAd { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: FeedAdCollectionViewCell.self), for: indexPath) as! FeedAdCollectionViewCell cell.injectAdView(ad.adView) return cell } // ... return cell }
Using a UITableView
Using Objective-C:
- (void)feedAdDidFinishLoading:(FAFeedAd *)feedAd { // Inject the feed ad into a copy of your content data self.displayedData = [self injectFeedAd:self.feedAd into:self.data]; [self.tableView reloadData]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { id data = [self.displayedData objectAtIndex:indexPath.row]; if ([data isKindOfClass:[FAFeedAd class]]) { FAFeedAd *feedAd = (FAFeedAd *) data; FAFeedAdTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([FAFeedAdTableViewCell class])]; [cell injectAdView:feedAd.adView]; return cell; } // ... return nil; }
Using Swift:
func feedAdDidFinishLoading(_ feedAd: FAFeedAd!) { // Inject the feed ad into a copy of your content data displayData = injectFeedAd(feedAd, into: data) tableView.reloadData() } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let currentElement = displayData[indexPath.row] if let ad = currentElement as? FAFeedAd { let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: FeedAdTableViewCell.self), for: indexPath) as! FeedAdTableViewCell cell.injectAdView(ad.adView) return cell } // ... return cell }
5. Implement Resizing
To guarantee a seamless integration into your UI and to prevent distractions by letterboxing, you should resize your container views in your UI to match the preferred size of a feed ad.
The ad views of an FAFeedAd
are set up to adjust their sizes following the
desired size, aspect ratio and scalability of the displayed ad. The default
aspect ratio is 16:9.
Every time an FAFeedAd
changes its preferred size, the
delegate method feedAdDidChangeSize:
gets called. To determine the perfect size for your container views, use - (CGSize) [FAFeedAd sizeForSuperviewSize:]
.
The method sizeForSuperviewSize:
takes a parameter of type CGSize
, into which you should pass the size of your container view.
If either width or height of your container view is flexible, set it to CGFLOAT_MAX
.
For example, in the case of an iPhone app with a UITableView
that runs over the full width of the screen:
When you integrate a feed ad here, you will most likely be limited by the width of the screen.
However, each cell can be flexible in height.
In this case, pass the width of your UITableView
and set the height to CFLOAT_MAX
, to have sizeForSuperviewSize:
determine the perfect height for your cell.
Using a simple UIView
Using Objective-C:
- (void)feedAdDidChangeSize:(FAFeedAd *) { // For a view which is only bounded by its width CGSize preferredSize = [feedAd sizeForSuperviewSize:CGSizeMake(self.adContainerView.frame.width, CGFLOAT_MAX)]; self.adContainerView.frame = ({ CGRect frame = self.adContainerView.frame; frame.size = preferredSize; frame; }); self.adContainerView.center = self.view.center; }
Using Swift:
func feedAdDidChangeSize(_ feedAd: FAFeedAd!) { // For a view which is only bounded by its width let preferredSize = feedAd.size(forSuperview: CGSize(width: self.adContainerView.frame.width, height: CGFloat.greatestFiniteMagnitude)) adContainerView.frame.size = preferredSize adContainerView.center = view.center }
Using a UICollectionView
Using Objective-C:
- (void)feedAdDidChangeSize:(FAFeedAd *) { [self.collectionView.collectionViewLayout invalidateLayout]; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { id data = [self.displayedData objectAtIndex:indexPath.row]; if ([data isKindOfClass:[FAFeedAd class]]) { return [self.feedAd sizeForSuperviewSize:CGSizeMake(self.collectionView.frame.size.width, CGFLOAT_MAX)]; } // ... return size; }
Using Swift:
func feedAdDidChangeSize(_ feedAd: FAFeedAd!) { collectionView.collectionViewLayout.invalidateLayout() } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let currentElement = displayData[indexPath.item] if let ad = currentElement as? FAFeedAd { return ad.size(forSuperview: CGSize(width: collectionView.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) } // ... return size }
Using a UITableView
Using Objective-C:
- (void)feedAdDidChangeSize:(FAFeedAd *) { [self.tableView beginUpdates]; [self.tableView endUpdates]; } - (CGFloat)tableView:(UITableView *) heightForRowAtIndexPath:(NSIndexPath *)indexPath { id data = [self.displayData objectAtIndex:indexPath.row]; if ([data isKindOfClass:[FAFeedAd class]]) { return [self.feedAd sizeForSuperviewSize:CGSizeMake(self.tableView.frame.size.width, CGFLOAT_MAX)].height; } // ... return height; }
Using Swift:
func feedAdDidChangeSize(_ feedAd: FAFeedAd!) { tableView.beginUpdates() tableView.endUpdates() } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let currentElement = displayData[indexPath.row] if let ad = currentElement as? FAFeedAd { return ad.size(forSuperview: CGSize(width: tableView.frame.size.width, height: CGFloat.greatestFiniteMagnitude)).height } // ... return height }
It's a Wrap
Once you have completed all of the above steps, you should have a working feed ads integration.
FAFeedAd
Delegate Methods
Implement the delegate methods from FAFeedAdDelegate
to be notified
about events and to customize its appearance:
- an ad has been loaded successfully
- (void)feedAdDidFinishLoading:(FAFeedAd *)feedAd;
- An ad has played through successfully
- (void)feedAdDidFinishPlaying:(FAFeedAd *)feedAd;
- Errors occured during loading or playback of an ad
- (void)feedAd:(FAFeedAd *)feedAd didFailWithError:(NSError *)error;
- An ad has changed its desired size
- (void)feedAdDidChangeSize:(FAFeedAd *)feedAd;
- An ad logged an impression
- (void)feedAdDidLogImpression:(FAFeedAd *)feedAd;
- Should a loading indicator be displayed for an ad in the current context?
- (BOOL)feedAdShouldDisplayLoadingIndicator:(FAFeedAd *)feedAd;
- An ad has been clicked
- (void)feedAdWasClicked:(FAFeedAd *)feedAd;
- An ad has been skipped
- (void)feedAdWasSkipped:(FAFeedAd *)feedAd;
- An ad will leave the application to show its landing page after the user has clicked the ad
- (void)feedAdWillLeaveApplication:(FAFeedAd *)FeedAd;
Ad Request Options
The class FAFeedAdConfig
provides additional properties that allow you specify optional details about the context of an ad placement.
Property Name | Description |
---|---|
contentURL |
iOS Universal Link for the screen where the ad will be displayed. |
customParameters |
Specify custom parameters to pass additional tracking data about the context of your placement. For example, this could be the category of a certain item an user viewed in your app. |
webContentURL |
Can be an iOS Universal Link or a regular website URL to the equivalent page on the publisher's website for the screen where the ad will be displayed. |
Continuous Ad Playback
Feed ads support continuous playback across screen changes, as described in FeedAd Behavior.
To benefit from this behavior for your app, make sure that your placements are linked to the same placement group and follow the integration instructions above for each of your screens.
Passing ads between screens, is then handled by the FeedAd SDK.
Using Feed Ads as Part of an Ad Mediation Waterfall
The FeedAd SDK has been designed with ad mediation waterfalls in mind.
We have implemented and tested FeedAd integration with major mediation networks. Read the mediation documentation to learn more about supported networks or take a look into our example app.
Whenever one of the following delegate methods from FAFeedAdDelegate
has been called, the FAFeedAd
instance finishes any outstanding tasks and then developers are in control again:
feedAdDidFinishLoading:
feedAdDidFinishPlaying:
feedAd:didFailWithError:
This allows you to:
- Simply make another call to
load
to have the SDK load a new ad or - Remove the ad view from screen, to deallocate the feed ad and to move on in your mediation
It will not automatically reload and try to display another ad.
Another important point in this regard, is that whenever an FAFeedAd
detects that it does not have another ad to display, it will simply return a no-fill error instead of idling on your ad placement. This allows you to maximize ad revenues by moving on to the next step in your ad mediation waterfall.