Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange Behaviour with iAd Interstitial

I am experiencing some weird behaviour in both ios7 and 8..

What happens is sometimes the full screen is presented with an X(POTRAIT FUllSCREEN AD - my app is landscape only). You click the X and you can go back to my menu fine.

But sometimes an ad will show without an X(LANDSCAPE FUllSCREEN AD). If you wait DiDFinish delegate NEVER gets called. So then I try clicking it to go away. It then shows another ad with an X(LANDSCAPE FUllSCREEN AD). So i click the X. It then goes to another ad(LANDSCAPE FUllSCREEN AD) where DiDFinish gets called. iOS7 it'll just freeze on that 3rd ad shown. ios8 it'll show the 3rd ad for a second then go to a black screen? Has anyone dealt with something like this?

Not sure if when the first ad shows in portrait orientation it works fine, is a clue or not?

Also the multiple ads showing are all iAd not rev mob and iAd combined as I have 100 percent fill rate for iAd. at the moment im just trying to get iAds full screen ads to work consistently

I know the delegate is being set as didLoad delegate gets called when the ad loads Also this is an issue for both iPhone and iPad

Has anyone else had these problems?

Using..

[interstitial presentFromViewController:self];

Instead of..

[interstitial presentInView:self.view];

makes everything work properly..but presentFromViewController: is deprecated now

enter image description here

Here is my code I use...

-(void)showFullScreenAd {
    //Check if already requesting ad
    if (requestingAd == NO) {
        //[ADInterstitialAd release];
        interstitial = [[ADInterstitialAd alloc] init];
        interstitial.delegate = self;
        self.interstitialPresentationPolicy = ADInterstitialPresentationPolicyManual;
        [self requestInterstitialAdPresentation];
        NSLog(@"interstitialAdREQUEST");
        requestingAd = YES;
    }
}

-(void)interstitialAd:(ADInterstitialAd *)interstitialAd didFailWithError:(NSError *)error {
    interstitial = nil;
    requestingAd = NO;
    NSLog(@"interstitialAd didFailWithERROR");
    NSLog(@"%@", error);

    [revmobFS loadWithSuccessHandler:^(RevMobFullscreen *fs) {
        [fs showAd];
        NSLog(@"Ad loaded");
    } andLoadFailHandler:^(RevMobFullscreen *fs, NSError *error) {
        NSLog(@"Ad error: %@",error);
    } onClickHandler:^{
        NSLog(@"Ad clicked");
    } onCloseHandler:^{
        NSLog(@"Ad closed");
    }];
}

-(void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd {
    NSLog(@"interstitialAdDidLOAD");
    if (interstitialAd != nil && interstitial != nil && requestingAd == YES) {
        [interstitial presentInView:self.view];
        NSLog(@"interstitialAdDidPRESENT");
    }//end if
}

-(void)interstitialAdDidUnload:(ADInterstitialAd *)interstitialAd {
    interstitial = nil;
    requestingAd = NO;
    NSLog(@"interstitialAdDidUNLOAD");
}

-(void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd {
    interstitial = nil;
    requestingAd = NO;
    NSLog(@"interstitialAdDidFINISH");
}

if someone could just post there code that is fully working in there app for me to try will also earn +50 reputation

like image 226
4GetFullOf Avatar asked Oct 19 '22 22:10

4GetFullOf


1 Answers

No working code from my end, but I have had a look in the Documentation and found a catergory for UIViewController with iAd methods

Here

It appears you are mixing old code with new code.

From what I have seen I would suggest:

        -(void)showFullScreenAd {
        //Check if already requesting ad
        if (requestingAd == NO) {
            [self requestInterstitialAdPresentation];
            requestingAd = YES;
        }
    }

    -(void)viewDidLoad()
{
    [super viewDidLoad];
// Any other setup.
 self.ADInterstitialPresentationPolicy = ADInterstitialPresentationPolicyManual

}

This follows the new iOS7 implementation. Setting the policy in the viewDidLoad method allows the Framework to pre cache assets and start getting any ads from the iAd Server. Ready so when the "showFullScreenAd" method is called an ad should be ready.

You can also call a class method +(void)prepareInterstitialAds when loading the view or doing other data tasks, this lets the Framework pre-cache assets if it can, which can mean subsequent requests are quicker.

For RevMob handling with ad's failing: [self requestInterstitialAdPresentation]; returns a boolean, this means you can handle that and tell RevMob it failed, etc. For when the Ad has been closed. It may be best to do some KVO on the presentingFullScreenAd property of the ViewController. Which states whether it is showing a FullScreenAd, I believe this is only iAd, Full Ad's.

The reason you have such different results is because you have 2 ways of requesting and presenting ad's within the same view controller.

When the ad is presented Portrait, the [self requestInterstitialAdPresentation]; failed to retrieve an ad, but the Instantiation of the ADInterstitialAd instance has sent another request. This has loaded, because you do not set a frame for the instance's view it does not know it is meant to be landscape and so a portrait version is presented. As this is now presented in the view, the view doesn't know/care what orientation it is in, so presents the ad view based on it's geometry.

When it is landscape that is down to the [self requestInterstitialAdPresentation]; succeeding. That top Ad is the ad from this call. I'm not sure why the rest of the ad's display landscape, unless that is something from the Framework, ie the [self requestInterstitialAdPresentation]; internally decides it must be landscape from the ViewControllers layout, so all subsequent ad requests fit this, unless the VC orientation changes again.

[EDIT] - I have thrown together a basic example piece. This has been done from memory/documentation so will probably not be 100% correct and will most likely not work from a direct copy and paste. This is to give an idea, which also includes support for versions pre iOS7

//.h 

@import UIKit;
@import iAd;

@interface MyInterstitialViewController : UIViewController <ADInterstitialAdDelegate>
{

}
@property (strong) ADInterstitialAd *fullScreenAd;

@end

//.m

#include MyInterstitialViewController.h

@implementation MyInterstitialViewController
{
    - (instancetype)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
    {
        if(self = [super initWithNibName:nibName bundle:nibBundle])
        {

        }
        return self;
    }


    -(void)viewDidLoad()
    {
        [super viewDidLoad];

        if([self respondsToSelector:@selector(requestInterstitialAdPresentation)] == YES)
        {
            self.ADInterstitialPresentationPolicy = ADInterstitialPresentationPolicyManual;
        }
    }

    -(void)viewWillDisappear
    {
        @try 
        {
                    **[self  removeObserver:self forKeyPath:@"isPresentingFullScreenAd"];**
                }
                @catch (NSException * __unused exception) 
        {
        }
    }

    -(void)showFullScreenAd()
    {
        if([self respondsToSelector:@selector(requestInterstitialAdPresentation)] == NO)
        {
            self.fullScreenAd = [[ADInterstitialAd alloc] init];
            self.fullScreenAd.delegate = self;
        }
        else
        {
            if([self requestInterstitialAdPresentation] == NO)
            {
                //Report back to RevMob Controller that the Ad Failed.
                [revmobFS loadWithSuccessHandler:^(RevMobFullscreen *fs) 
                { 
                    [fs showAd]; 
                    NSLog(@"Ad loaded"); 
                } andLoadFailHandler:^(RevMobFullscreen *fs, NSError *error) 
                { 
                    NSLog(@"Ad error: %@",error); 
                } onClickHandler:^{
                    NSLog(@"Ad clicked"); 
                } onCloseHandler:^{
                    NSLog(@"Ad closed"); 
                }]; 
            }
            else
            {
                **[self addObserver:self forKeyPath:@"isPresentingFullScreenAd" options:NSKeyValueObservingOptions.NSKeyValueObservingOptionNew context:nil];**
            }
        }
    }

//ADInterstitialAd Delegate Methods.
-(void)interstitialAd:(ADInterstitialAd *)interstitialAd didFailWithError:(NSError *)error 
{
    interstitial = nil; 
    NSLog(@"interstitialAd didFailWithERROR"); 
    NSLog(@"%@", error); 
    [revmobFS loadWithSuccessHandler:^(RevMobFullscreen *fs) 
        { 
            [fs showAd]; 
            NSLog(@"Ad loaded"); 
        } andLoadFailHandler:^(RevMobFullscreen *fs, NSError *error) 
        { 
            NSLog(@"Ad error: %@",error); 
        } onClickHandler:^{
            NSLog(@"Ad clicked"); 
        } onCloseHandler:^{
            NSLog(@"Ad closed"); 
        }]; 
} 
-(void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd 
{
    NSLog(@"interstitialAdDidLOAD"); 
    if (self.fullScreenAd != nil) 
    { 
                   CGRect interstitialFrame = self.view.bounds;
 interstitialFrame.origin = self.view.origin;
 UIView *view = [[UIView alloc] initWithFrame:interstitialFrame];
 [self.view addSubview:view];
[self.fullScreenAd presentInView:view];


        NSLog(@"interstitialAdDidPRESENT"); 
    }//end if
}
-(void)interstitialAdDidUnload:(ADInterstitialAd *)interstitialAd 
{
    NSLog(@"interstitialAdDidUNLOAD");
}
-(void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd
{
    NSLog(@"interstitialAdDidFINISH"); 
}


//KVO Responding

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    **if([keyPath isEqualTo:"isPresentingFullScreenAd"] == YES)
    {
        if([object === self])
        {
          if([self isPresentingFullScreenAd] == false)
          {
             //Handle logic for your app. New Screen etc.
          }
          else
          {
            //Handle logic for your app. Pause current activity etc.
          }
        }
    }**
}

}

For reference.

The changes I have made allow for the Ad Framework to work as you are expecting it to on all versions of iOS from 4.3 - 8.X

From iOS 4.3 - 6.X the general flow was:

Create an Ad, set it's delegate, present and handle in the delegate methods.

From 7 - 8.X (The previous way of presenting in a UIViewController was deprecated in iOS 7, but deprecation means previous methods work until the next X.0 release, generally.)

For this case you ask the Framework for an ad through the [UIViewController requestInterstitialAdPresentation]; method. The Controller will create a View and Present it if it has got an ad. You don't get the delegate methods anymore, the "- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context"

method allows you to essentially get the delegate call for when the Ad has finished displaying so you can continue with the logic of your app. Essentially the "AdDidFinish" delegate call. But as we don't remove the observer until the Controller is unloaded, there is logic to handle if a new ad has been displayed.

This means that the logic for your VC doesn't have to check if it is presenting a full screen ad all the time.

You can still use the flow from iOS 4.3 - 6.X but using the presentInView Method. As is described in iAd Programming guide, this should be used if you have a content view inside, what I have set out is a "Transition Ad" Methodology.

like image 152
Naughty_Ottsel Avatar answered Nov 03 '22 23:11

Naughty_Ottsel