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.
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
})
}
Hey so I have been trying to implement an ad banner view below the split view controller of my app. I managed to do it by creating a BannerViewController, which resizes the splitViewController and places the banner at the bottom, which works. However, now I notice that tapping an item in the list in the TableViewController doesn't work on iPhone. It stays selected like on iPad, so it must think it is on iPad and has to display the detail next to the master. The segue is hooked up in Interface Builder from the UITableViewCell to the navigation controller of the detail view. And it was all working fine even for a while after implementing the banner controller, but just stopped this morning.
I have tried calling performSegue in didSelectRowAtIndexPath, and prepareForSegue is called every time but usually does not show anything on iPhone.
Here is BannerViewController:
class BannerViewController: UIViewController, GADBannerViewDelegate {
var bannerView = GADBannerView()
var showingBanner = false
var contentView, bannVC: UIView!
var originalFrame: CGRect!
init(contentVC: UIViewController) {
contentView = contentVC.view
originalFrame = contentView.frame // Store the original frame of the content view for later use
super.init(nibName: nil, bundle: nil)
// If banner is hidden, position off screen (x > window.height) and make contentView size of window
view.addSubview(contentView)
// Create banner view
setupAds()
}
// Required init, just call super
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// Update the position of the banner on the screen
override func viewDidLayoutSubviews() {
bannerView.frame = CGRect(x: 0, y: contentView.frame.size.height, width: contentView.frame.size.width, height: 50)
}
// MARK: - Adverts
// Checks if ads have been disabled by buying the in app purchase
func checkAdsDisabled() -> Bool {
return Product.findBy(identifier: ProductRepo.DisableAds)?.purchased ?? false
}
func setupAds() {
if (!checkAdsDisabled()) {
// Ads have not been disabled, set them up
bannerView.adUnitID = "ca-app-pub-123456/xyz"
bannerView.translatesAutoresizingMaskIntoConstraints = false
bannerView.adSize = kGADAdSizeSmartBannerPortrait
bannerView.delegate = self
bannerView.rootViewController = self
let request: GADRequest = GADRequest()
request.testDevices = ["xyz"] // My iPhone
bannerView.load(request)
// Initially position off screen
view.addSubview(bannerView)
hideBanner()
}
}
// Hide banner and update view positions
func hideBanner() {
contentView.frame.size.height = originalFrame.size.height
view.layoutSubviews()
showingBanner = false
}
// Show banner and update view positions
// Called by adViewDidReceiveAd
func showBanner() {
contentView.frame.size.height = contentView.superview!.frame.size.height - bannerView.frame.size.height
view.layoutSubviews()
showingBanner = true
}
// MARK: - GADBannerViewDelegate
/// Tells the delegate an ad request loaded an ad.
func adViewDidReceiveAd(_ bannerView: GADBannerView!) {
print("adViewDidReceiveAd: Banner loaded")
if !showingBanner{
showBanner()
}
}
}
If it helps, also I am using SearchController in the master view. When tapping the search bar I get the warning Presenting view controllers on detached view controllers is discouraged, which may be related, but I can't get any info out of that.
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 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.