These instructions work on the assumption that your app already has a banner placement correctly setup.
Here, we'll show you how to start adding some extra options.
First, we have to enable multiple placement sizes for one placement. This allows your Ad Ops team to easily differentiate the content that they would like to insert-
Below is an example of how you would implement this:
import GoogleMobileAds
import UIKit
class ResponsiveAdDelegateViewController: UIViewController, GADAdSizeDelegate {
/// The custom banner size (320x480) switch.
@IBOutlet weak var GADAdSizeCustomBannerSwitch: UISwitch!
/// The medium rectangle size (300x250) switch.
@IBOutlet weak var GADAdSizeMediumRectangleSwitch: UISwitch!
/// The DFP banner view. It's DFPBannerView not GADBannerView right?
var bannerView: DFPBannerView!
override func viewDidLoad() {
super.viewDidLoad()
bannerView = DFPBannerView(adSize: kGADAdSizeMediumRectangle)
bannerView.delegate = self
// You have to set ID and what's the view controller
// Ad Unit ID has to be set up in DV360
bannerView.adUnitID = "/6499/example/banner"
bannerView.rootViewController = self
// Ad Size Delegate, so adView can be called in the bottom
bannerView.adSizeDelegate = self
// Add it into the view
addBannerViewToView(bannerView)
// Let's load an ad into it (whenever you want to do it)
bannerView.load(GADRequest())
}
func addBannerViewToView(_ bannerView: DFPBannerView) {
bannerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(bannerView)
view.addConstraints(
[NSLayoutConstraint(item: bannerView,
attribute: .bottom,
relatedBy: .equal,
toItem: bottomLayoutGuide,
attribute: .top,
multiplier: 1,
constant: 0),
NSLayoutConstraint(item: bannerView,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 0)
])
guard GADAdSizeCustomBannerSwitch.isOn || GADAdSizeMediumRectangleSwitch.isOn else {
let alert = UIAlertView(title: "Load Ad Error",
message: "Failed to load ad. Please select at least one ad size.",
delegate: self,
cancelButtonTitle: "OK")
alert.alertViewStyle = .default
alert.show()
return
}
var adSizes = [NSValue]()
// Let's add the valid Scroller Placement
if GADAdSizeCustomBannerSwitch.isOn {
let scrollerGADAdSize = GADAdSizeFromCGSize(CGSize(width: 320, height: 480))
adSizes.append(NSValueFromGADAdSize(scrollerGADAdSize))
}
if GADAdSizeMediumRectangleSwitch.isOn {
adSizes.append(NSValueFromGADAdSize(kGADAdSizeMediumRectangle))
}
bannerView.validAdSizes = adSizes
}
/// Called before the ad view changes to the new size.
/// Initiated by the view delegate that's set via `bannerView.adSizeDelegate = self` above
func adView(_ bannerView: DFPBannerView, willChangeAdSizeTo size: GADAdSize) {
// The bannerView calls this method on its adSizeDelegate object before the banner updates its
// size, allowing the application to adjust any views that may be affected by the new ad size.
print("Make your app layout changes here, if necessary. New banner ad size will be \(size\).")
}
}
Ref: https://developers.google.com/ad-manager/mobile-ads-sdk/ios/banner#multiple_ad_sizes
Above code has generated a AdViewDelegate that makes the placement possible to be used in two sizes. This means that based on the ad request, it chooses which creative and it's size won the bid.
This still doesn't enable us to yet have a responsive sized layout. 320 width is not anymore a standard full width as it was used to be. To make the placement responsive you have to make the frame in different sizes:
func updateBannerSize(_ bannerView: DFPBannerView, willChangeAdSizeTo size: GADAdSize) {
let width = size.size.width
let height = size.size.height
let ratio = height/width
let newWidth = view.bounds.width
// We assume that 320 means full width and 300 means with 10px padding on left and right
// Change the padding to what you have normal in your feed
let feedPadding = 10
if width != 320 {
newWidth = newWidth - (feedPadding * 2)
}
let newHeight = ( newWidth * ratio )
var frameRect = bannerView.frame
frameRect.size.width = newWidth
frameRect.size.height = newHeight
bannerView.frame = frameRect
}
func adView(_ bannerView: DFPBannerView, willChangeAdSizeTo size: GADAdSize) {
...
updateBannerSize(bannerView, size)
...
}
Ref: https://developers.google.com/ad-manager/mobile-ads-sdk/ios/native-styles#gadadsizedelegate_protocol
Right... So we should have the whole issue with sorting out the sizes and getting correct placements in there.
Now we maybe could also open a funnel so ads can speak to the native side of the ad and vice-versa.
This will be done through events.
class ResponsiveAdDelegateViewController: UIViewController, GADAppEventDelegate {
func viewDidLoad() {
...
bannerView.appEventDelegate = self
...
}
func adView(_ bannerView: DFPBannerView, didReceiveAppEvent name: String,
withInfo info: String?) {
if name == "ad.size" {
guard let info = info else { return }
// I'm using JSON String Parser defined below, use the one you prefer
let size: AnyObject? = info.parseJSONString
updateBannerSize(bannerView, GADAdSizeFromCGSize(CGSize(width: size.width, height: size.height)))
}
}
}
JSON Parser:
extension String {
var parseJSONString: AnyObject? {
let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
if let jsonData = data {
// Will return an object or nil if JSON decoding fails
return NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
} else {
// Lossless conversion of the string was not possible
return nil
}
}
}
We should now have been able to accomplish a responsive placement that can also be controlled with an ad for perfect effect.
Thanks!