Manage iAd banner's touch while using iAdAdditions category - ios

iOS 7 bring the iAdAdditions category to UIViewController.
With it managing a banner is a matter of one line of code:
self.canDisplayBannerAds = YES;
But I wonder how to detect user touching the iAd banner. My need is to pause game behaviors (music, animations, timers...) while iAd is displayed full screen.
I have tried the following code:
- (void) viewWillDisappear:(BOOL)animated {
if ([self isPresentingFullScreenAd]) {
// view will disappear because of user action on iAd banner
}
else {
// view will disappear for any other reasons
}
}
- (void) viewWillAppear:(BOOL)animated {
if ([self isPresentingFullScreenAd]) {
// view will appear because full screen iAd — caused by previous user action on iAd banner — is dismissed
}
else {
// view will appear for other reasons
}
}
I have done some testings showing everything is OK. But I wonder if it's the correct way to implement it!
UPDATE
This is the solution I use in the production version of the application and everything is fine: no problems has showned.

You can use these specific delegates in your view controller, here's code ripped straight from my game where I toggle the audio/music off when a banner is clicked.
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner
willLeaveApplication:(BOOL)willLeave
{
[[CPAudioManager sharedInstance] toggleOnOffDependingOnSettings];
return YES;
}
-(void)bannerViewActionDidFinish:(ADBannerView *)banner
{
[[CPAudioManager sharedInstance] toggleOnOffDependingOnSettings];
}
For full screen interstitials the code is roughly the same, but you don't get such nice delegates.
You know when you are showing a full screen ad when you call requestInterstitialAdPresentation and it returns YES, e.g.
if( [self requestInterstitialAdPresentation]==YES ) {...}
You should pause your views, toggle your music off, and kill your banner view (probably).
Then, you know when the user has closed the interstitial in ViewDidAppear
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if( self.isPresentingFullScreenAd )
{
// we are about to stop presenting full screen ads
// unpause view
// enable banner ads
// turn music back on if it was playing before
}
else
{
// we are presenting the normal view or the full screen ad
}
}

Related

adMob iOS resume (back to app button)

I have a little game with a timer.
I'm implementing adMob to monetize and I am not able to restart timer/ads after user clicks on the banner and come back to the app.
The flow is:
1 - game start
2 - show ads
3 - click on banner and pause timer
4 - oper safari
5 - click "back to my app" link/button (iOS feature)
6 - back to the app and restar timer (problem here)
I had implemented all adMob events method (and insert restar timer code) but I can't get out of this issue.
The code work because it worked with iAds (I'm migrating to adMob).
Any help is appreciated.
Thank you
EDIT:
here is the code:
/// Tells the delegate an ad request loaded an ad.
- (void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"adViewDidReceiveAd");
self.pauseTimer = NO;
}
/// Tells the delegate an ad request failed.
- (void)adView:(GADBannerView *)adView
didFailToReceiveAdWithError:(GADRequestError *)error {
NSLog(#"adView:didFailToReceiveAdWithError: %#", [error localizedDescription]);
self.pauseTimer = NO;
}
/// Tells the delegate that a full screen view will be presented in response
/// to the user clicking on an ad.
- (void)adViewWillPresentScreen:(GADBannerView *)adView {
NSLog(#"adViewWillPresentScreen");
self.pauseTimer = NO;
}
/// Tells the delegate that the full screen view will be dismissed.
- (void)adViewWillDismissScreen:(GADBannerView *)adView {
NSLog(#"adViewWillDismissScreen");
self.pauseTimer = NO;
}
/// Tells the delegate that the full screen view has been dismissed.
- (void)adViewDidDismissScreen:(GADBannerView *)adView {
NSLog(#"adViewDidDismissScreen");
self.pauseTimer = NO;
}
/// Tells the delegate that a user click will open another app (such as
/// the App Store), backgrounding the current app.
- (void)adViewWillLeaveApplication:(GADBannerView *)adView {
NSLog(#"adViewWillLeaveApplication");
self.pauseTimer = YES;
}
In this VC create a property to store this
#property (nonatomic) BOOL didGoToSafari;
- (void)adViewWillLeaveApplication:(GADBannerView *)adView {
NSLog(#"adViewWillLeaveApplication");
self.pauseTimer = YES;
self.didGoToSafari = YES;
}
In the VC that you show right before the ad would show in viewWillAppear or viewDidAppear you should put this code
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(applicationDidBecomeActiveNotification:)
name:UIApplicationDidBecomeActiveNotification
object:[UIApplication sharedApplication]];
And then after viewDidAppear or viewWillAppear, write this function
- (void)applicationDidBecomeActiveNotification:(NSNotification *)notification {
if (self.didGoToSafari = YES){
self.pauseTimer = NO;
self.didGoToSafari = NO;
}
}
In viewWillDisappear
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification
object:[UIApplication sharedApplication]];
Basically what you're doing is listening to see if the app became active again. If it did, check to see if it's coming back from Safari. It's not perfect because you could feasibly be using the app, user goes to Safari and then doesn't go back to or close the game. They could then use Safari later and then go back to the game and it would start running again. There probably some control flow in the AppDelegate you could use to code around this, but in general this code should do it.
EDIT: As per your comment about understanding it, here's the full explanation.
You are using NSNotification to listen for when the app returns to an active state. UIApplicationDidBecomeActiveNotification is automatically called when your app becomes active (it's an app delegate method). When it does, the method (void)applicationDidBecomeActiveNotification gets called automatically and the methods in that method get called. You have a boolean flag to see if the app is returning from Safari because your app could return from any other app if user switched to another app when the ad got pushed. In the end, you remove your VC as an observer to avoid memory leaks.

iAds showing an error of Ad was unloaded from this banner when switching between tabs on a UITabBarController

I am implementing iAds into my app for the first time and the app itself is a simple 5-tabbed UITabBarController where the first 4 tabs are a UIViewController with a UITableView embedded in and the last tab is a UITableViewController.
With following this guide: http://www.appcoda.com/ios-iad-introduction/ I have successfully implemented the iAds and it shows up in the app and works it's way through each delegate method.
I have made it so that the first 4 tabs have the iAds, but the last tab does not. This is because the last tab is a static UITableView and I cannot embed that into a UIViewController, etc. So the first 4 tabs have the adBannerView. The AdBannerView is added in from Storyboard into this UIViewController.
Issue
During developing on a real device, running iOS 8.1.1 (and on another device running 8.2), when I am on the first tab, it shows the iAd Banner with no issues. When I switch to the second tab and come back to the first tab, two things happen:
1) The adBannerView is there, but the actual ad itself is shown for a second and then disappears again.
2) The delegate method below outputs an error as soon as I leave the first tab:
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"Unable to show ads. Error: %#", [error localizedDescription]);
}
NSLog: Unable to show ads. Error: The operation couldn’t be completed. Ad was unloaded from this banner.
A few things to point out here. If I move to the 5th tab which itself doesn't contain the adBannerView and come back to the first tab, this issue doesn't occur and the adBannerView itself it still shown with the ads.
Also, with the use of NSLogs, I can see that when I come back to the first tab from the second tab, viewWillAppear gets run, which is immediately followed by:
- (void)bannerViewWillLoadAd:(ADBannerView *)banner
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
This indicates the ad is ready to be loaded, but it takes a good 2 minutes for the ad to actually be displayed in the adBannerView. When I come back to the first tab from the second tab, the adBannerView is there, but the ads are not.
Here's some code:
- (void)bannerViewWillLoadAd:(ADBannerView *)banner
{
NSLog(#"AD Banner will load ad");
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
NSLog(#"Ad Banner did load ad");
// We must show the ad banner view when an ad is ready to be displayed.
[UIView animateWithDuration:0.5 animations:^{
self.adBanner.alpha = 1.0;
}];
// self.adBanner.hidden = NO;
}
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
NSLog(#"Ad Banner action is about to begin");
return YES;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
NSLog(#"Ad Banner action did finish");
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"Unable to show ads. Error: %#", [error localizedDescription]);
// When there are no ads to show, we should hide it:
Hide the ad banner.
[UIView animateWithDuration:0.5 animations:^{
self.adBanner.alpha = 0.0;
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.adBanner.delegate = self;
self.adBanner.alpha = 0.0;
}
I have read the Apple guide (https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/iAd_Guide/TestingiAdApplications/TestingiAdApplications.html) which states that occasionally, errors will be sent to the app to test that out as well and that's fine, but in this case, it seems like the app itself is unloading the banner view but then taking a long time to load it again.
Also, with looking at some similar situations on Stack Overflow, I have even tried to set the adBannerView delegate to nil in the viewWillDisappear. When I do this, and I change from the first tab to the second tab, I don't get the error saying the ad has been unloaded in the delegate method and when I come back, it shows the AdBannerView but without the ads.
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(#"DISAPEARING");
self.adBanner.delegate = nil;
}
So to confirm, the issue is that when I leave the first tab to go to the second tab, the NSLog outputs an error saying the Ad has been unloaded. When I come back to the first tab, it runs through the delegate methods and even goes to run the method that indicates the ad is ready to be shown, the adBannerView is visible, but the ad itself is not, for about 2 minutes.
Update
I have implemented the use of shared banners using the AppDelegate and the code in this example: https://www.youtube.com/watch?v=_0Mv44FWw0A&feature=youtu.be.
The progress is that I'm now not receiving any errors when switching tabs, but when I switch to the second tab and come back again, it still shows the banner but loads the ad into it after 2 minutes, even though the bannerViewDidLoadAd delegate method IS being called as soon as I return back to the first tab.
Any guidance on this would really be appreciated.

iAd bannerViewActionDidFinish never called: How to know when the user closed an iAd?

I've searched multiple forums and looked at existing questions on stackoverflow but haven't found a solution to this. I have a game screen where I show an iAd at the bottom of the screen. The ad shows up correctly, and when I tap on that it expands to full screen. However, when I click on the X button in the second screen, the ad closes WITHOUT bannerViewActionDidFinish getting called in the delegate.
I really need a way to know when the ad closed so I can relayout my screen accordingly. Any ideas?
Update: Added all my view controller code related to iAd below. I have added the AdBannerView via Interface Builder, and linked it to self.mAdBannerView as an outlet. There's nothing special I am doing in the view controller. And one more point: I haven't posted by app to the iTunes Store yet, so I am getting test Ads from Apple "You're Connected to iAd" and I've tried both on the emulator and a device - same result and same issue.
Note that the callbacks for bannerViewDidLoadAd and didFailToReceiveAdWithError ARE being called, as expected.
Here's my code sample:
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
return YES;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
NSLog(#"bannerViewActionDidFinish"); //this is never called
}
- (void)viewDidLoad
{
self.mAdBannerView.delegate = self;
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
}

Youtube dismissal event (iOS)

Good day,
Through the use of an UIWebview I have now a working method to show a youtube video within my app (using the tag, finding the play button within the webview and firing the touch event on that).
Works like a charm. The video pops up and plays. However I would like to recieve an event when the video ends or the user clicks the done button.
On the internet I have found that there is an event: MPAVControllerItemPlaybackDidEndNotification where you can listen to. However this one does not get called.
After some further research I found that for Youtube Videos embedded through UIWebView another notification was called ( UIMoviePlayerControllerDidExitFullscreenNotification ). Unfortunately that one does not work either anymore. ( found it here )
Does anyone have any idea how I can do some action after the video is done playing or has been dismissed?
Thanks
Use the UIMoviePlayerControllerWillExitFullscreenNotification for getting notified once the user tapped on the DONE button. The UIMoviePlayerControllerDidExitFullscreenNotification seems indeed to be omitted on iOS6.
Mind that ...Did... vs. ...Will... difference!
For more on that subject, once again check my updated answer within that posting you referenced in your question.
Let's look at this scenario :
In your view, you have a button. When it's clicked, you want to play the video directly.
In order, to do so, you open the webview as a modal view of your view :
[self presentModalViewController:videoWebView animated:NO];
For your webview, you should use Youtube API to integrate and autoplay the video. See the proposed working example here : https://stackoverflow.com/a/15538968
You'll see that the video is launched in a modal view of your webview view. One way to detect when the video is dismissed (when the "done" button has been clicked) is to use the viewDidAppear on your webview view class. In this method you will then dismiss the webview view too but...when this view is launched at first, you don't want to dismiss it. You can add a boolean property to avoid that.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (_videoLaunched) {
[self dismissModalViewControllerAnimated:YES];
}
}
In the viewDidLoad method, set this property to NO and in the webViewDidFinishLoad method (delegate method of webview) set it to YES.
I think it answers one part of your question. Concerning the detection of the end of the video you have to modify you YT_Player.html file to listen to state changes.
ytPlayer = new YT.Player('media_area', {height: '100%', width: '100%', videoId: 'SbPFDcspRBA',
events: {'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange}
function onPlayerStateChange(e) {
var result = JSON.parse(event.data);
if (result.info == 0) { // Video end
window.location = "videomessage://end";
}
}
});
You will then catch the event in your webview view and dismiss it like this :
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
if ([[url scheme] isEqualToString:#"videomessage"]) {
[self dismissModalViewControllerAnimated:YES];
return YES;
}
return YES;
}
What you need here is something like this:
- (void)playerWillExitFullscreen:(NSNotification *)notification
{
//do something...
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerWillExitFullscreen:)
name:#"MPMoviePlayerWillExitFullscreenNotification" object:nil];

How do I make my app work with the media control buttons on lock screen?

In recent iOS versions apps have some kind of access to the media control buttons on the lock screen, like the Play/Pause button:
It looks like the buttons are supposed to work with the MPMusicPlayerController class, is that right? Is there a way to get the “raw” events from the buttons? Because the music player only seems to offer an API to supply a bunch of MPMediaItems. What if my app is for example a radio that needs to handle the buttons differently?
After a bit more searching I have found this related question that makes things clear. The music player controller class is not really the right track, the trick is to subscribe for remote events in your controller:
- (void) viewDidAppear: (BOOL) animated
{
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
- (void) remoteControlReceivedWithEvent: (UIEvent*) event
{
// see [event subtype] for details
}

Resources