I have a Test application setup with AdMob Mediation service being used, only on testing device at the moment. I have setup all the required methods per the documentation. I am having an issue where when the Fail to Receive Ad error occurs, no more ads are requested or shown?
Header:
#import <UIKit/UIKit.h>
#import "GADBannerViewDelegate.h"
#class GADBannerView, GADRequest;
#interface AdTestViewController : UIViewController
<GADBannerViewDelegate> {
GADBannerView *bannerView_;
}
#property (nonatomic, retain) GADBannerView *bannerView;
- (GADRequest *)createRequest;
#end
Imp File
#import "AdTestViewController.h"
#import "Constants.h"
#import "GADBannerView.h"
#import "GADRequest.h"
#implementation AdTestViewController
#synthesize bannerView = bannerView_;
- (void)viewDidLoad {
[super viewDidLoad];
// Create a view of the standard size at the top of the screen.
// Available AdSize constants are explained in GADAdSize.h.
//bannerView_ = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
// Initialize the banner at the bottom of the screen.
//CGPoint origin = CGPointMake(0.0,
// self.view.frame.size.height -
// CGSizeFromGADAdSize(kGADAdSizeBanner).height);
self.bannerView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
//origin:origin];
self.bannerView.adUnitID = kAdMobPublisherID;
self.bannerView.delegate = self;
[self.bannerView setRootViewController:self];
[self.view addSubview:self.bannerView];
self.bannerView.center =
CGPointMake(self.view.center.x, self.bannerView.center.y);
[bannerView_ loadRequest:[self createRequest]];
bannerView_.backgroundColor = [UIColor blueColor];
// Make the request for a test ad. Put in an identifier for
// the simulator as well as any devices you want to receive test ads.
GADRequest *request = [GADRequest request];
request.testDevices = [NSArray arrayWithObjects:
#"4D047EB9-A3A7-441E-989E-C5437F05DB04",
#"YOUR_DEVICE_IDENTIFIER",
nil];
}
- (GADRequest *)createRequest {
GADRequest *request = [GADRequest request];
// Make the request for a test ad. Put in an identifier for the simulator as
// well as any devices you want to receive test ads.
request.testDevices = [NSArray arrayWithObjects:
#"4D047EB9-A3A7-441E-989E-C5437F05DB04",
#"YOUR_DEVICE_IDENTIFIER",
nil];
return request;
}
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error;
{
NSLog(#"Error - did Fail to Receive an Ad");
bannerView_.hidden = YES;
}
- (void)adViewDidReceiveAd:(GADBannerView *)view;
{
NSLog(#"Ad Received");
bannerView_.hidden = NO;
}
#end
What I am seeing in my logs is the 'Ad Received' a few times, then 'Error - did Fail to Receive an Ad'... After this log there are no further entries it is like it stops requesting? Testing only on simulator at present.
Any ideas how to solve this, or potentially an alternative method on hiding the view when an error/no ad is received?
I find the same thing – when the GADBannerView is hidden, no more requests are sent out.
One thing I tried successfully is to move the GADBannerView offscreen instead of hiding it. Of course, you only want to do this as a consequence of didFailToReceiveAdWithError, and then move it back onscreen when adViewDidReceiveAd. I got this working so the user sees a nice animation when ads come and go, much like iAd encourages.
In short, the code below will place your GADBannerView (here called mAdBannerView) either at the bottom of the screen or offscreen, depending on the boolean adIsLoaded.
CGRect bannerFrame = mAdBannerView.frame;
bannerFrame.origin.y = self.view.bounds.size.height - (adIsLoaded * bannerFrame.size.height);
mAdBannerView.frame = bannerFrame;
in the method that's called when there is an error put in some thing like
bannerView_.hidden = 1;
that will hide the view if there's an error and it will probably automatically be displayed if an ad was received with no error
Think you're better off just hiding the bannerView_ with the hidden property.
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error {
bannerView_.hidden = YES;
}
Of course you have to remember to set hidden back to YES when an ad is successfully received.
Simple solution, set the bannerView_.hidden true in adView:didFailToReciewvwAdWithError method. And to retrieve the view use adViewDidReceiveAd method. Example code:
These are ADmob's delegate method:
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error
{
bannerView_.hidden = YES;
}
- (void)adViewDidReceiveAd:(GADBannerView *)view
{
bannerView_.hidden = NO;
}
I had the same problem, this worked for me:
Do not use the .hidden property to hide AdMob ads.
Just set the alpha to 0 (invisible) or 1 (visible).
So in your GADBannerView delegate method...
-(void)adView:(GADBannerView *)bannerView didFailToReceiveAdWithError:(GADRequestError *)error {
// Hide the ad banner.
[UIView animateWithDuration:0.5 animations:^{
self.myADBanner.alpha = 0.0;
}];
}
-(void)adViewDidReceiveAd:(GADBannerView *)bannerView {
//Show the ad banner.
[UIView animateWithDuration:0.5 animations:^{
self.myADBanner.alpha = 1.0;
}];
}
With regards to "After this log there are no further entries it is like it stops requesting?"
This happens to me as well when I remove an ad from the view hierarchy. However, requests continue when I add the ad back to the view hierarchy. The only time they didn't continue was when I was using the .hidden property.
Related
I'm working with the Google Mobile Ads SDK on iOS and trying to display some ads. My code:
GADBannerView* bannerView = [[GADBannerView alloc] initWithAdSize:GADAdSizeFromCGSize(CGSizeMake(300, 250))];
bannerView.adUnitID = #"hidden";
bannerView.rootViewController = self;
bannerView.delegate = self;
GADRequest* request = [GADRequest request];
request.testDevices = #[ kGADSimulatorID ];
[bannerView loadRequest:request];
This works fine if I add the bannerView to the view hierarchy right after the code you see above. However, I don't really want to add it until the ad is loaded, so I wanted to delay it. I noticed that if the bannerView is not in the view hierarchy, the delegate methods are not called at all. Furthermore, I have found this answer, which is in line with what I'm observing. On the other hand, this is a quote from the GADBannerViewDelegate header:
/// 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.
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView;
This suggests that it should be possible to receive those delegate callbacks even if the view is not in the hierarchy, which is exactly what I want. So, any ideas how could I achieve this?
Ok, so the problem here was that I didn't keep the reference to the bannerView. It was deallocated after the method returned, and this is why the delegate methods were not called.
I just had the same issue after upgrading from the Admob SDK 7.56 to 8.2:
They changed the method names of the GADBannerViewDelegate protocol.
E.g. instead of
-(void)adViewDidReceiveAd:(GADBannerView *)adView;
it is now
-(void)bannerViewDidReceiveAd:(GADBannerView *)bannerView;
see also the migration guide to Admob SDK version 8:
https://developers.google.com/admob/ios/migration#methods_removedreplaced
You should add the GADBannerView to your view and set its hidden property to YES initially. Also, I'd suggest using the AdSize Constant kGADAdSizeBanner that AdMob provides. Here's a list of additional AdSize Constants.
For example:
bannerView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
bannerView.adUnitID = #"YourAdUnitID";
bannerView.rootViewController = self;
bannerView.delegate = self;
[bannerView loadRequest:[GADRequest request]];
bannerView.hidden = YES; // Hide banner initially
[self.view addSubview:bannerView];
// This will put the banner at the bottom of the screen and stretch to fit the screens width
[bannerView setFrame:CGRectMake(0, self.view.frame.size.height - bannerView.frame.size.height, self.view.frame.size.width, bannerView.frame.size.height)];
Then, when you receive an ad you unhide the banner. For example:
-(void)adViewDidReceiveAd:(GADBannerView *)adView {
// We've received an ad so lets show the banner
bannerView.hidden = NO;
NSLog(#"adViewDidReceiveAd");
}
-(void)adView:(GADBannerView *)adView didFailToReceiveAdWithError:(GADRequestError *)error {
// Failed to receive an ad from AdMob so lets hide the banner
bannerView.hidden = YES;
NSLog(#"adView:didFailToReceiveAdWithError: %#", [error localizedDescription]);
}
You could also animate this, if you'd prefer, by setting the banner's alpha property to 0.0 initially instead of using it's hidden property. Then, animate the alpha when you receive an ad. For example:
-(void)adViewDidReceiveAd:(GADBannerView *)adView {
// We've received an ad so lets fade in the banner
[UIView animateWithDuration:0.2 animations:^{
bannerView.alpha = 1.0;
}];
NSLog(#"adViewDidReceiveAd");
}
-(void)adView:(GADBannerView *)adView didFailToReceiveAdWithError:(GADRequestError *)error {
// Failed to receive an ad from AdMob so lets fade out the banner
[UIView animateWithDuration:0.2 animations:^{
bannerView.alpha = 0.0;
}];
NSLog(#"adView:didFailToReceiveAdWithError: %#", [error localizedDescription]);
}
Also, as a side note, the GADBannerView is transparent when there is no ad to display. So, adding it to your view and doing nothing else would work too.
I am working on an iOS app that uses Google Ad SDK. The view controller that is supposed to display the ad is a delegate of GADBannerViewDelegate and GADSwipeableBannerViewDelegate.
The ad comes in just fine most of the time. Sometimes however, AdMob seems to hang and I don't get a response whatsoever in my delegate.
Is there something I have done wrong? Alternatively, is there a way to detect this behavior?
I initialize the ad banner and then in viewWillAppear I reload the ad (assuming it's not already loading). It usually works just fine but again, it sometimes doesn't.
Here is the relevant code:
UPDATE::
I changed the code but to no avail. Here is new code (got rid of previous two methods):
-(void)resetAdView:(UIViewController *)rootViewController {
[self.adMob_ActivityIndicator startAnimating];
if (adBanner_ == nil) {
adBanner_ = [[DFPSwipeableBannerView alloc]
initWithFrame:CGRectMake(30, 365, 300, 150)];
}
[adBanner_ setHidden:YES];
if (isLoaded_) {
GADRequest *request = [GADRequest request];
[adBanner_ loadRequest:request];
[self.scrollView addSubview:adBanner_];
} else {
adBanner_.delegate = self;
adBanner_.rootViewController = rootViewController;
adBanner_.adUnitID = AD_UNIT_ID;
GADRequest *request = [GADRequest request];
[adBanner_ loadRequest:request];
[self.scrollView addSubview:adBanner_];
}
}
My instance variables are :
DFPSwipeableBannerView *adBanner_;
BOOL isLoaded_;
This might be due to lack of ad inventory.
Did you implement the banner view's error catching delegate function?
(void)adView:(DFPBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error
If this delegate method isn't implemented in your code, implement it and log the error object to get a detailed error description.
I ended up just wiping the banner view from the superview and completely re-initializing it and the request. This doesn't solve the problem of the hanging response but now if you switch to a different view and come back to this one, the ad does reload. It's possible that I was simply adding too many views into my scrollview which will not be the case anymore.
-(void)resetAdView:(UIViewController *)rootViewController {
// in reset method
[self.adMob_ActivityIndicator startAnimating];
adBanner_ = nil;
for (UIView *subview in self.scrollView.subviews) {
if (subview.tag == 666) {
// removing banner view from superview
[subview removeFromSuperview];
}
}
// (re) initializing banner view
adBanner_ = [[DFPSwipeableBannerView alloc]
initWithFrame:CGRectMake(30, 365, 300, 150)];
[adBanner_ setHidden:YES];
// setting up and requesting ad
adBanner_.delegate = self;
adBanner_.rootViewController = rootViewController;
adBanner_.adUnitID = AD_UNIT_ID;
GADRequest *request = [GADRequest request];
[adBanner_ loadRequest:request];
adBanner_.tag = 666;
[self.scrollView addSubview:adBanner_];
}
i would add ADMOB to my xcode project, but when a test it on iphone and simulator i receive this error :
AdMob Ios Error: Failed to receive ad with error: Request Error: No ad to show.
my code Banner.h:
#import <UIKit/UIKit.h>
#import "GADBannerViewDelegate.h"
#class GADBannerView, GADRequest;
#interface BannerExampleViewController : UIViewController
<GADBannerViewDelegate> {
GADBannerView *adBanner_;
}
#property (nonatomic, retain) GADBannerView *adBanner;
- (GADRequest *)createRequest;
#end
Banner.m
#import "BannerExampleViewController.h"
#import "GADBannerView.h"
#import "GADRequest.h"
#import "SampleConstants.h"
#implementation BannerExampleViewController
#synthesize adBanner = adBanner_;
#pragma mark init/dealloc
// Implement viewDidLoad to do additional setup after loading the view,
// typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
// Initialize the banner at the bottom of the screen.
CGPoint origin = CGPointMake(0.0,
self.view.frame.size.height -
CGSizeFromGADAdSize(kGADAdSizeBanner).height);
// Use predefined GADAdSize constants to define the GADBannerView.
self.adBanner = [[[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner
origin:origin]
autorelease];
// Note: Edit SampleConstants.h to provide a definition for kSampleAdUnitID
// before compiling.
self.adBanner.adUnitID = kSampleAdUnitID;
self.adBanner.delegate = self;
[self.adBanner setRootViewController:self];
[self.view addSubview:self.adBanner];
self.adBanner.center =
CGPointMake(self.view.center.x, self.adBanner.center.y);
[self.adBanner loadRequest:[self createRequest]];
}
- (void)dealloc {
adBanner_.delegate = nil;
[adBanner_ release];
[super dealloc];
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
#pragma mark GADRequest generation
// Here we're creating a simple GADRequest and whitelisting the application
// for test ads. You should request test ads during development to avoid
// generating invalid impressions and clicks.
- (GADRequest *)createRequest {
GADRequest *request = [GADRequest request];
// Make the request for a test ad. Put in an identifier for the simulator as
// well as any devices you want to receive test ads.
request.testDevices =
[NSArray arrayWithObjects:#"6a47e320f03fe2ab9854afe2e5708321", nil];
return request;
}
#pragma mark GADBannerViewDelegate impl
// We've received an ad successfully.
- (void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"Received ad successfully");
}
- (void)adView:(GADBannerView *)view
didFailToReceiveAdWithError:(GADRequestError *)error {
NSLog(#"Failed to receive ad with error: %#", [error localizedFailureReason]);
}
#end
One more thing to point out - if your banner space width/height is set ot 0, you'll receive exactly the same error. I'm currently trying to make a workaround about this because I want to animate ad view on screen only if it successfully load ad.
This is because the server have not update yet.
You should wait for 15 minutes and try again, it will work correctly.
PS: Remember replace kSampleAdUnitID with your App ID in Admob
This code work correctly when I am testing with my ID
I use class to show AdMob ad and it has 320x50 size view, i call only this class's view where i want to display my ad in app but when i click ad and want to return back, it go back to AdMob's class and it resizes to cover all screen (Autoresize is closed) . Does anybody has solution about it?
I use this AdMob class with small view because of my other m files are mm. file and i could not make AdMob work in mm files and its also easy to call just this class's view when i need to display ad.
I use same codes as in AdMob example in official site.
-(void)setAdMob{
CGPoint origin = CGPointMake(0.0,
self.view.frame.size.height -
CGSizeFromGADAdSize(kGADAdSizeBanner).height);
// Use predefined GADAdSize constants to define the GADBannerView.
self.adBanner = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner
origin:origin];
// Note: Edit SampleConstants.h to provide a definition for kSampleAdUnitID
// before compiling.
self.adBanner.adUnitID = kSampleAdUnitID;
self.adBanner.delegate = self;
[self.adBanner setRootViewController:self];
[self.view addSubview:self.adBanner];
self.adBanner.center =
CGPointMake(self.view.center.x, self.adBanner.center.y);
self.adBanner.frame=CGRectMake(0, 0, self.adBanner.frame.size.width, self.adBanner.frame.size.height);
[self.adBanner loadRequest:[self createRequest]];
}
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
-(GADRequest *)createRequest {
GADRequest *request = [GADRequest request];
request.testDevices =
[NSArray arrayWithObjects:
GAD_SIMULATOR_ID,
// TODO: Add your device/simulator test identifiers here. They are
// printed to the console when the app is launched.
nil];
return request;
}
// We've received an ad successfully.
-(void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"Received ad successfully");}
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error {
NSLog(#"Failed to receive ad with error: %#", [error localizedFailureReason]);}
I am integrating iAds into an iOS 6 app with a UITabBarController and UINavigationController and a bunch of UITableView-based screens and have it mostly working with one glaring exception. When I navigate from a parent to child view controller, my banner view does not appear until the ADBannerView delegate methods are invoked (when a new ad is served) even if I already have an ad.
What I want is when I have an ad displayed on the parent and click to the child, I want the ad to appear immediately. However, what is happening is that the ad banner disappears and does reappear until the delegate methods are invoked to update it. Stepping through the debugger it all looks like it should work. I am sure it is something trivial I am not doing, but am stuck. Help!
As I put in the comments, it seems to be that the _contentView frame size is incorrect at the point where the code is placing the ad in the view. With auto-layout off, it places the ad correct initially, but with each new ad, the banner moves up the screen. With auto-layout on, the initial display of the ad is in the wrong place, but subsequent calls (or rotation calls) the ad is in the correct location.
Here is the relevant code:
I have a singleton class that manages the creation of the ADBannerView instance I want to share. The singleton just does the allocation once; otherwise it returns the banner view:
- (ADBannerView *) getAdBannerSingleton
{
if ( bannerView == nil )
{
DDLogInfo(#"iAds: Creating our initial banner view") ;
bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner] ;
// to handle rotation properly
[bannerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth] ;
}
return bannerView ;
}
I have a base class that has a View --> SubView --> UITableView (in a XIB) and manages the ADBannerView and serves as the delegate. My concrete parent/child classes inherit from the base class, but do nothing special themselves (they are blissfully unaware of the ads).
#implementation SSSAdEnabledTableViewController
#synthesize tableView = _tableView;
#synthesize contentView = _contentView;
#synthesize bannerView = _bannerView ;
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil] ;
// this class does not need to do anything special as there are no concrete instances of it
return self ;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//
// manage our ad
//
DDLogInfo(#"iAds: Managing ad View from viewWillAppear for %#",
NSStringFromClass([self class])) ;
[self manageAdView] ;
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated] ;
// no effect with our without the call below
[_bannerView removeFromSuperview];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[_tableView setAutoresizesSubviews:YES] ;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
self.contentView = nil ;
self.tableView = nil ;
self.bannerView = nil ;
}
#pragma mark -- iAd framework methods
- (void) bannerViewDidLoadAd:(ADBannerView *)banner
{
DDLogInfo(#"iAds: Banner ad successfully loaded for %#", NSStringFromClass([self class])) ;
[self manageAdView] ;
}
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
return YES ;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
// don't think we have to do anything?
}
- (void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
DDLogError(#"Error loading iAd for %#. Reason: %#",
NSStringFromClass([self class]),
[error localizedDescription]) ;
[self manageAdView] ;
}
#pragma mark -- ad banner helper methods
//
// Get our shared banner view instance
//
- (void)createAdBannerView
{
// get the banner view instance
_bannerView = [[SSSStoreManager sharedStore] getAdBannerSingleton] ;
// make us the delegate
DDLogInfo(#"iAds: Setting %# to be our banner delegate", NSStringFromClass([self class])) ;
// set it to be the delegate
[_bannerView setDelegate:self] ;
}
//
// Based on the ad status, make room for it in our view or hide it
//
- (void)manageAdView
{
// make sure we always have a banner view to work with here
if ( _bannerView == nil )
{
DDLogInfo(#"Banner View is Nil; Creating it for %#", NSStringFromClass([self class]));
[self createAdBannerView] ;
}
// will hold our banner dimensions and position
CGRect bannerFrame = CGRectZero;
// our inner view dimensions and position
CGRect contentViewFrame = _contentView.frame;
// make sure all of the changes happen at one time
[UIView beginAnimations:#"fixupViews" context:nil];
// is the banner loaded and should it be visible?
if ( _bannerView.bannerLoaded == YES )
{
DDLogInfo(#"iAds: Showing banner view for %#", NSStringFromClass([self class])) ;
bannerFrame.size = [_bannerView sizeThatFits:contentViewFrame.size];
contentViewFrame.size.height -= bannerFrame.size.height;
bannerFrame.origin.y = contentViewFrame.size.height;
}
else
{
DDLogInfo(#"iAds: Hiding banner view for %#", NSStringFromClass([self class])) ;
bannerFrame.origin.y = contentViewFrame.size.height;
}
// reset our content view based on whether we have an ad to show
_contentView.frame = contentViewFrame ;
[self.view addSubview:_bannerView];
_bannerView.frame = bannerFrame;
[UIView commitAnimations];
}