I am using Swift to implement interstitial ads into my app. I have managed to get it to show interstitial adverts, but there is no close 'X' button to get rid of the advert. Why is this?
I also cannot find answer for why built-in framework does not provide close button but i end up with using following solution.
//iAD interstitial definition with custom placeHolderView and close button
//you do not need to add anything to interface builder. All is done with code
var interstitial:ADInterstitialAd!
var placeHolderView:UIView!
var closeButton:UIButton!
//Full Implemantation of iAD interstitial and delegate methods
func cycleInterstitial(){
// create a new interstitial. We set the delegate so that we can be notified
interstitial = ADInterstitialAd()
interstitial.delegate = self;
}
func presentInterlude(){
// If the interstitial managed to load, then we'll present it now.
if (interstitial.loaded) {
placeHolderView = UIView(frame: self.view.frame)
self.view.addSubview(placeHolderView)
closeButton = UIButton(frame: CGRect(x: 270, y: 25, width: 25, height: 25))
//add a cross shaped graphics into your project to use as close button
closeButton.setBackgroundImage(UIImage(named: "cross"), forState: UIControlState.Normal)
closeButton.addTarget(self, action: Selector("close"), forControlEvents: UIControlEvents.TouchDown)
self.view.addSubview(closeButton)
interstitial.presentInView(placeHolderView)
}
}
// iAd Delegate Mehtods
// When this method is invoked, the application should remove the view from the screen and tear it down.
// The content will be unloaded shortly after this method is called and no new content will be loaded in that view.
// This may occur either when the user dismisses the interstitial view via the dismiss button or
// if the content in the view has expired.
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!){
placeHolderView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
cycleInterstitial()
}
func interstitialAdActionDidFinish(_interstitialAd: ADInterstitialAd!){
placeHolderView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
println("called just before dismissing - action finished")
}
// This method will be invoked when an error has occurred attempting to get advertisement content.
// The ADError enum lists the possible error codes.
func interstitialAd(interstitialAd: ADInterstitialAd!,
didFailWithError error: NSError!){
cycleInterstitial()
}
//Load iAd interstitial
func dislayiAdInterstitial() {
//iAd interstitial
presentInterlude()
}
func close() {
placeHolderView.removeFromSuperview()
closeButton.removeFromSuperview()
interstitial = nil
}
using interstitial=InterstitialAd() causes me the same problem as you.
However, if you include the following code in your AppDelegate's application function:
UIViewController.prepareInterstitialAds()
Then, you can generate an interstitial Ad using this:
viewController.requestInterstitialAdPresentation()
I am not sure how to get the callbacks, though.
iOS 9.2.1, Xcode 7.2.1, ARC enabled
Please read my post:
https://stackoverflow.com/a/35467510/4018041
I still use presentFromViewController: method.
Hope this helps! Cheers.
Related
Trying to integrate Facebook audience Network ad placements into my SwiftUI project.
The tutorial published by Facebook assumes the use of UIKit only!
With zero experience in UIKit, need your kind help to enable me to integrate the follwing lines of code into my ContentView as a SwiftUI view:
//Add a UIView element to the main View element and name it to adContainer.
//Now, in your View Controller header file (or Swift file, if you are a Swift user),
//import FBAudienceNetwork, declare conformance to the FBAdViewDelegate protocol,
//and add an instance variable for the ad unit
import UIKit
import FBAudienceNetwork
class ViewController: UIViewController, FBAdViewDelegate {
#IBOutlet private var adContainer: UIView!
private var adView: FBAdView?
}
//Add the code below to viewDidLoad; Create a new instance of FBAdView and add it to the view.
//FBAdView is a subclass of UIView. You can add it to your view hierarchy just like any other view.
override func viewDidLoad() {
super.viewDidLoad()
// Instantiate an AdView object.
// NOTE: the placement ID will eventually identify this as your app, you can ignore while you
// are testing and replace it later when you have signed up.
// While you are using this temporary code you will only get test ads and if you release
// your code like this to the App Store your users will not receive ads (you will get a 'No Fill' error).
let adView = FBAdView(placementID: "YOUR_PLACEMENT_ID", adSize: kFBAdSizeHeight50Banner, rootViewController: self)
adView.frame = CGRect(x: 0, y: 0, width: 320, height: 250)
adView.delegate = self
adView.loadAd()
self.adView = adView
}
//Optionally, you can add the following functions to handle the cases
//where the ad is closed or when the user clicks on it:
func adViewDidClick(_ adView: FBAdView) {
print("Ad was clicked.")
}
func adViewDidFinishHandlingClick(_ adView: FBAdView) {
print("Ad did finish click handling.")
}
func adViewWillLogImpression(_ adView: FBAdView) {
print("Ad impression is being captured.")
}
//Add and implement the following two delegate functions in your
//View Controller to handle ad loading failures:
func adView(_ adView: FBAdView, didFailWithError error: Error) {
print("Ad failed to load with error: \(error.localizedDescription)")
}
func adViewDidLoad(_ adView: FBAdView) {
print("Ad was loaded and ready to be displayed")
showAd()
}
private func showAd() {
guard let adView = adView, adView.isAdValid else {
return
}
adContainer.addSubview(adView)
}
Your help would be tremendously appreciated would be
I have my AdMob ads all setup and working, but I want to make an animation for them when they first load in. For example, I have a banner ad right below the bottom of the screen, and when it loads I want it to go up. The animation I have right now:
UIView.animate(withDuration: 1, animations: {
self.banner.frame.origin.y -= 350
})
works just fine, but only shows to the user if the ad loaded fast enough. What can I do to check?
You could achieve it by setting the delegate of the GADBannerView to the desired class, for instance the self view controller:
override func viewDidLoad() {
super.viewDidLoad()
// let's assume that you init the banner view somewhere in your code...
adMobBannerView.delegate = self
}
And then implementing adViewDidReceiveAd(_ bannerView: GADBannerView!):
Tells the delegate that an ad request successfully received an ad. The
delegate may want to add the banner view to the view hierarchy if it
hasn’t been added yet.
adding to it your animation code, as follows:
func adViewDidReceiveAd(_ bannerView: GADBannerView!) {
UIView.animate(withDuration: 1, animations: {
self.banner.frame.origin.y -= 350
})
}
I have a banner view and want to have a custom close button. My problem is that the button is displayed before the ad is loaded and displayed.
class RootVC: UIViewController, GADBannerViewDelegate {
var googleAdBanner: GADBannerView!
var googleBannerCloseBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
googleAdBanner = GADBannerView(frame:CGRectMake(0,0,100,100))
googleAdBanner.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2)
googleAdBanner.adUnitID = "xx"
googleAdBanner.rootViewController = self
googleAdBanner.loadRequest(GADRequest())
adViewWillPresentScreen(googleAdBanner)
googleAdBanner.delegate = self
self.view.addSubview(googleAdBanner)
}
func adViewWillPresentScreen(bannerView: GADBannerView!) {
googleBannerCloseBtn = UIButton(frame: CGRectMake( 5 , 5, 25, 25))
googleBannerCloseBtn.backgroundColor = UIColor.clearColor()
googleBannerCloseBtn.setImage(UIImage(named: "closeBtn"), forState: .Normal)
googleBannerCloseBtn.setTitle("Click Me", forState: UIControlState.Normal)
googleBannerCloseBtn.addTarget(self, action: #selector(RootVC.buttonAction(_:)), forControlEvents: UIControlEvents.TouchUpInside)
googleBannerCloseBtn.tag = 1
googleAdBanner.addSubview(googleBannerCloseBtn)
}
How do I present the button only when the GADBannerView has loaded an ad and is presented?
Same behavior with adViewDidReceiveAd. The button is visible, even if the GADBannerView is "invisible" because there is no ad loaded currently.
Screens as requested. As you see, the button, that is a subView of the GADBannerView is displayed before the ad itself is displayed.
I've commented out alot of the logic in this example. The only thing that I didn't mention was that you will need to create two Ad Unit ID's. One for your GADBannerView and one for your GADInterstitial on AdMob.com.
import UIKit
import GoogleMobileAds // Import AdMob
class ViewController: UIViewController, GADBannerViewDelegate, GADInterstitialDelegate { // Include our delegates
// Create our ads
var banner = GADBannerView(adSize: kGADAdSizeBanner) // kGADAdSizeBanner is a default banner size
var interstitial = GADInterstitial(adUnitID: "YourInterstitialAdUnitID")
override func viewDidLoad() {
super.viewDidLoad()
// View has loaded so lets setup our ads initially
setupAds()
}
// MARK: - Setup Ads
func setupAds() {
// Setup our banner ad
banner.adUnitID = "YourBannerAdUnitID"
banner.rootViewController = self
banner.delegate = self
// Hide our banner initially until it loads an ad
// Not doing this is why your close button was visible
// GADBannerView's with no ad are essentially "clear", not hidden
banner.alpha = 0.0
banner.loadRequest(GADRequest())
// Position banner on bottom of view
banner.frame = CGRect(x: 0.0,
y: view.frame.height - banner.frame.height,
width: view.frame.width,
height: banner.frame.height)
// Create your button here and add it as a subview to banner
// banner.addSubview(closeButton)
view.addSubview(banner)
// Setup our interstitial ad initially
interstitial.delegate = self
interstitial.loadRequest(GADRequest())
}
// MARK: - Load Interstitial Ad
func loadFullScreenAd() {
// GADInterstitial's are single use. You have to create a new GADInterstitial for each presentation
// So, if you'd like to show more than one GADInterstitial in your apps session we need this
// This func will be used to create a new GADInterstitial after one has been displayed and dismissed
interstitial = GADInterstitial(adUnitID: "YourInterstitialAdUnitID")
interstitial.delegate = self
interstitial.loadRequest(GADRequest())
}
// MARK: - Show Interstitial Ad
func showFullScreenAd() {
// Call this function when you want to present the interstitial ad
// ie. game over, transition to another vc, etc...
// Make sure you give atleast a few seconds for this ad to load before atempting to present it
// For example, don't try to present this ad in viewDidAppear
// Check if the interstitial ad is loaded before trying to present it
if interstitial.isReady {
interstitial.presentFromRootViewController(self)
}
}
// MARK: - Close Button Action
func closeButtonAction() {
// This is where we will handle your close button that you've added to your GADBannerView
// You can handle this two ways and it depends on what you'd like to do
// If you don't want to show the banner ad again during the entire app session you would hide the banner
// This way even if we change the alpha values in our delegate methods the banner will remain hidden
banner.hidden = true
// Another way you can handle the close button would be to hide the banner until another banner ad is loaded
// I believe the refresh rate for banner ads is 45-60 seconds. You can customize the refresh time on AdMob.com
// So, this way if the user tapped the close button the banner would fade out
// But, when another banner ad is loaded the banner would fade back in because of the code in our adViewDidReceiveAd delegate method
UIView.animateWithDuration(0.2) {
self.banner.alpha = 0.0
}
/////* Choose which way you'd like to handle the close button and remove the code for the other */////
}
// MARK: - GADBannerView Delegate Methods
func adViewDidReceiveAd(bannerView: GADBannerView!) {
print("adViewDidReceiveAd")
// We received an ad so lets show it
// You could even fade in the banner if you'd like
UIView.animateWithDuration(0.2) {
self.banner.alpha = 1.0
}
}
func adView(bannerView: GADBannerView!, didFailToReceiveAdWithError error: GADRequestError!) {
print("banner didFailToReceiveAdWithError: \(error)")
// We received an error when trying to load our GADBannerView
// Lets hide it because we don't have an ad
// You could also fade this out if you'd like
UIView.animateWithDuration(0.2) {
self.banner.alpha = 0.0
}
}
// MARK: - GADInterstitial Delegate Methods
func interstitialDidReceiveAd(ad: GADInterstitial!) {
print("interstitialDidReceiveAd")
}
func interstitialWillPresentScreen(ad: GADInterstitial!) {
print("interstitialWillPresentScreen")
// If you needed to pause anything in your app this would be the place to do it
// ie. sounds, game state, etc...
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
print("interstitialDidDismissScreen")
// The GADInterstitial has been shown and dismissed by the user
// Lets load another one for the next time we want to show a GADInterstitial
loadFullScreenAd()
// If you paused anything in the interstitialWillPresentScreen delegate method this is where you would resume it
}
func interstitial(ad: GADInterstitial!, didFailToReceiveAdWithError error: GADRequestError!) {
print("interstitial didFailToReceiveAdWithError: \(error)")
}
}
Also, if you plan on presenting the GADInterstitial often in your application I'd recommend disabling video ads on AdMob.com for that Ad Unit ID. AdMob interstitial video ads disable the close button for 5 seconds, kind of like the skip button on YouTube, and will aggravate your users instantaneously. If you're rarely showing the GADInterstitial then I'd leave the video ads enabled.
My iOS application was denied due to Apple not finding my ads during the review process. I uploaded my application again, included directions on how to see the ads, and it was approved today. Now, once my friends and family downloaded the application no ads are showing up. I checked my AdMob account and no impressions showed up so I don't know what's wrong. Has anyone had this happened to them? Also, it hasn't been 24hrs yet since the app was approved. Since Apple approved it I assume that they have seen the ads. My application shows ads when you start using the filters after you pick a photo. AdMob shows 61 impressions, 61 requests, and 100% fill rate.
// Initialize Apple iAd banner
func initiAdBanner() {
iAdBannerView = ADBannerView(frame: CGRectMake(0, self.view.frame.size.height, 0, 0) )
iAdBannerView.delegate = self
iAdBannerView.hidden = true
view.addSubview(iAdBannerView)
}
// Initialize Google AdMob banner
func initAdMobBanner() {
if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad {
// iPad banner
adMobBannerView.adSize = GADAdSizeFromCGSize(CGSizeMake(728, 90))
adMobBannerView.frame = CGRectMake(0, self.view.frame.size.height, 728, 90)
} else {
// iPhone banner
adMobBannerView.adSize = GADAdSizeFromCGSize(CGSizeMake(320, 50))
adMobBannerView.frame = CGRectMake(0, self.view.frame.size.height, 320, 50)
}
adMobBannerView.adUnitID = "AdMobPublisherID"
adMobBannerView.rootViewController = self
adMobBannerView.delegate = self
// adMobBannerView.hidden = true
view.addSubview(adMobBannerView)
var request = GADRequest()
adMobBannerView.loadRequest(request)
}
// Hide the banner
func hideBanner(banner: UIView) {
if banner.hidden == false {
UIView.beginAnimations("hideBanner", context: nil)
// Hide the banner moving it below the bottom of the screen
banner.frame = CGRectMake(0, self.view.frame.size.height, banner.frame.size.width, banner.frame.size.height)
UIView.commitAnimations()
banner.hidden = true
}
}
// Show the banner
func showBanner(banner: UIView) {
if banner.hidden == true {
UIView.beginAnimations("showBanner", context: nil)
// Move the banner on the bottom of the screen
banner.frame = CGRectMake(0, (self.view.frame.size.height-70) - banner.frame.size.height,
banner.frame.size.width, banner.frame.size.height);
UIView.commitAnimations()
banner.hidden = false
}
}
// iAd banner available
func bannerViewWillLoadAd(banner: ADBannerView!) {
println("iAd loaded!")
hideBanner(adMobBannerView)
showBanner(iAdBannerView)
}
// NO iAd banner available
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
println("iAd can't looad ads right now, they'll be available later")
hideBanner(iAdBannerView)
var request = GADRequest()
adMobBannerView.loadRequest(request)
}
// AdMob banner available
func adViewDidReceiveAd(view: GADBannerView!) {
println("AdMob loaded!")
hideBanner(iAdBannerView)
showBanner(adMobBannerView)
}
// NO AdMob banner available
func adView(view: GADBannerView!, didFailToReceiveAdWithError error: GADRequestError!) {
println("AdMob Can't load ads right now, they'll be available later \n\(error)")
hideBanner(adMobBannerView)
}
Ads are now appearing in your application. When your application is approved by Apple it still must be approved by the iAd team to receive iAd advertisements. This can take a few additional days. As a result, neither of your advertisements were being shown in your application. You can test this by going to Settings>Developer>and setting your fill rate to 0% on your development device. The reason neither ad is being shown if iAd fails to load initially is because of this function:
// Show the banner
func showBanner(banner: UIView) {
if banner.hidden == true {
UIView.beginAnimations("showBanner", context: nil)
// Move the banner on the bottom of the screen
banner.frame = CGRectMake(0, (self.view.frame.size.height-70) - banner.frame.size.height,
banner.frame.size.width, banner.frame.size.height);
UIView.commitAnimations()
banner.hidden = false
}
}
You're checking for if banner.hidden == true but your adMobBannerView's hidden value is never set to true until an iAd banner is loaded. Seeing as no iAd banner was being loaded prior to the approval by iAd's team this condition was never being met. This condition will also never be met in countries that do not support iAd or if iAd fails to load an ad initially.
Also, there's alot of jumping around when your ads load due to you animating them on and off the screen. A more elegant approach would be to animate their alpha values so the user does not notice when your ads change. You can also eliminate alot of your code. I've rewritten what you're trying to accomplish and commented out the reasoning behind it.
import UIKit
import iAd
class ViewController: UIViewController, ADBannerViewDelegate, GADBannerViewDelegate {
var iAdBannerView : ADBannerView = ADBannerView()
var adMobBannerView : GADBannerView = GADBannerView()
override func viewDidLoad() {
super.viewDidLoad()
loadAds()
}
func loadAds() {
// iAd
// Changed banners width to match the width of the view it is on
// You need to set the y origin relative to your view. Not a static number.
iAdBannerView = ADBannerView(frame: CGRectMake(0, self.view.frame.size.height - iAdBannerView.frame.height, self.view.frame.size.width, iAdBannerView.frame.height))
iAdBannerView.delegate = self
view.addSubview(iAdBannerView)
// Hide iAd initially
iAdBannerView.alpha = 0.0
// AdMob
// Changed adSize to Googles set banner size
adMobBannerView.adSize = kGADAdSizeBanner
// Changed banners width to match the width of the view it is on
// You need to set the y origin relative to your view. Not a static number.
adMobBannerView.frame = CGRectMake(0, self.view.frame.size.height - adMobBannerView.frame.height , self.view.frame.size.width, adMobBannerView.frame.height)
adMobBannerView.rootViewController = self
adMobBannerView.delegate = self
adMobBannerView.adUnitID = "AdMobPublisherID"
// Dont need var request = GADRequest()
adMobBannerView.loadRequest(GADRequest())
// Do not hide AdMob initially
view.addSubview(adMobBannerView)
}
// Use bannerViewDidLoadAd function so we know ad is fully loaded
func bannerViewDidLoadAd(banner: ADBannerView!) {
println("iAd has an ad to show")
// Animate fade of banners
UIView.beginAnimations(nil, context: nil)
// Show iAd
iAdBannerView.alpha = 1.0
// Hide AdMob
adMobBannerView.alpha = 0.0
UIView.commitAnimations()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
println("iAd failed to load an ad because \(error)")
// Animate fade of banners
UIView.beginAnimations(nil, context: nil)
// Hide iAd
iAdBannerView.alpha = 0.0
// Show AdMob
adMobBannerView.alpha = 1.0
UIView.commitAnimations()
}
This favors iAd and falls back to AdMob if iAd fails to load an ad. You don't need to check for when AdMob fails to load an ad as its fill rate is almost always 100%, and if there's no AdMob ad I doubt there's an iAd ad to show.
You would need to look at the device logs to determine why no ads were shown. In all likelihood, there were no ads available from the ad server at that point in time.
This is a normal state of affairs and why you should use mediation to ensure you have a back up network.
I implemented an ADInterstitialAd and it works fine on iphones but it doesn't work on ipad. Here is my code:
func close(sender: UIButton) {
closeButton.removeFromSuperview()
interAdView.removeFromSuperview()
}
func loadAd() {
println("load ad")
interAd = ADInterstitialAd()
interAd.delegate = self
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
println("ad did load")
interAdView = UIView()
interAdView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
self.view?.addSubview(interAdView)
interAd.presentInView(interAdView)
UIViewController.prepareInterstitialAds()
interAdView.addSubview(closeButton)
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
closeButton.removeFromSuperview()
interAdView.removeFromSuperview()
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
println("failed to receive")
println(error.localizedDescription)
closeButton.removeFromSuperview()
interAdView.removeFromSuperview()
}
it prints 'ad did load' but on ipad it only shows the closebutton and not the adview and it doesn't print a error description. I imported the iAd framework and included the ADInterstitialAdDelegate in my class.
The presentInView method will return a boolean to tell you if it presented ok. So I would start by checking that.
If that returns NO then check that the view you are presenting the ad into is actually the size you expect it to be. The ad won't present if the view isn't big enough. You may be presenting the ad too early in the view lifecycle and the view hasn't been sized to fit the screen yet?
Some other notes:
You don't need the UIViewController.prepareInterstitialAds() call because that method isn't for people using ADInterstitialAd directly. You prepare Ads just but creating an instance of ADInterstitialAd.
The ADInterstitialAd object is a single use object so make sure you get a fresh one each time.
Also UIViewController.prepareInterstitialAds() is part of an simpler api where you don't have to manage ADInterstitialAd yourself. If you don't have any special requirements you may prefer to use that api.