I have setup a test application using Admob Mediation service. I have an issue that when an error occurs and is handled by a method if I hide the banner View it causes no further ad requests to occur, possibly due to this 'hidden status'.
What I can do is sleep within the error method for a certain amount of time then request again, however this isn't the best method... I am guessing this would lock up some process and potentially other user input whilst sleepng? I am not sure of this as the app only includes ads so cannot test.
Here are my methods...
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error;
{
NSLog(#"Failed to receive ad with error: %#", [error localizedFailureReason]);
bannerView_.hidden = YES;
sleep(59);
[bannerView_ loadRequest:[self createRequest]];
}
- (void)adViewDidReceiveAd:(GADBannerView *)view;
{
NSLog(#"Ad Received");
bannerView_.hidden = NO;
}
I am looking for the best way to either:
1. Hide the view when no ad is returned, but ensure requests continue and the ad view is shown again once an ad is received.
2. Use a loop in the error method to handle requesting again until successful and not locking up anything else.
Only being tested on simulator at the moment, if any difference is made.
I would suggest you to use performSelector to make an asynchronous call instead of using sleep because sleep will block your thread. So this is implemented as in the 1st way you mentioned.
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error;
{
NSLog(#"Failed to receive ad with error: %#", [error localizedFailureReason]);
bannerView_.hidden = YES;
[self performSelector:#selector(repeatAdRequest) withObject:nil afterDelay:60.0];
}
- (void)adViewDidReceiveAd:(GADBannerView *)view;
{
NSLog(#"Ad Received");
bannerView_.hidden = NO;
}
-(void) repeatAdRequest
{
[bannerView_ loadRequest:[self createRequest]];
}
make addview a subview of another blank uiview.
In adview didfail, hide the view and not the adview
and in recieve show the view again.
Related
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.
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.
I am experiencing a very weird issue with interstitials in cocos2d(version 3.1.0) This is the code I use to load both interstitials.
- (void)interstitialDidReceiveAd:(GADInterstitial *)interstitial {
[interstitial presentFromRootViewController:[CCDirector sharedDirector]];
interstitial.delegate = nil;
interstitial = nil;
}
- (void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd {
[interstitialAd presentFromViewController:[CCDirector sharedDirector]];
}
Everything seems fine and works fine until you put and hold your finger on the display before the interstitial has popped, then when you cancel the touch(release the finger) and close the popup window the app becomes unresponsive, the touch handler does not work at all and you have to restart the app. I am struggling for several hours with no success of finding the issue causer. Could it be something with the CCDirector stop and start animation methods?
I found a workaround to the bug. What I did is to disable the respond manager before the google/iAD interstitial is shown, you can see the methods below.
- (void)interstitialDidReceiveAd:(GADInterstitial *)interstitial {
[[[CCDirector sharedDirector]responderManager]setEnabled:false];
[interstitial presentFromRootViewController:[CCDirector sharedDirector]];
interstitial.delegate = nil;
interstitial = nil;
}
- (void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd {
[[[CCDirector sharedDirector]responderManager]setEnabled:false];
[interstitialAd presentFromViewController:[CCDirector sharedDirector]];
}
After that I enabled it again in the - (void) startAnimation in CCDirectorIOS.m file by putting the following code.
if (![[self responderManager]isEnabled]) {
[[self responderManager]setEnabled:true];
}
I know that this is not an elegant solution, because changing the library code directly is not always a good idea, but I could not find any other alternative. I think that this is a cocos2d bug, but I am not sure, may be someone more experienced can point out the exact issue. I have no idea if this bug is present in the newest cocos2d version.
EDIT: This behaviour is also present in the newest version.
I am using google casting through my app. It is working good but I am not able to hide the casting button when the cast device goes offline. It hides automatically but after a long time. How can I hide it immediately. Is there a way to get the notifications from the device scanner class.
You should try adding listener
[self.deviceScanner addListener:self];
[self.deviceScanner startScan];
#pragma mark - GCKDeviceScannerListener
- (void)deviceDidComeOnline:(GCKDevice *)device {
NSLog(#"device found!! %#", device.friendlyName);
[self updateCastIconButtonStates];
if ([self.delegate respondsToSelector:#selector(didDiscoverDeviceOnNetwork)]) {
[self.delegate didDiscoverDeviceOnNetwork];
}
}
- (void)deviceDidGoOffline:(GCKDevice *)device {
[self updateCastIconButtonStates];
}
Update
Similar Question.
I'm currently getting a crash thats holding my app out of the app store, it seems to occur when i create a google ad as a fall back for iAd.
It only occurs on the I-pad running IOS 6.0 - 6.1 in compatibility mode (the app is not universal) and it appears to occur after the:
[googleAdvertBanner loadRequest:releaseRequest];
Any help would be really appreciated, here's what i'm getting in the code view when i crash:
GADMAdNetworkConnectorImpl.m:95
0x49e008: addl $60, %esp --- Thread 1:EXEC_BAD_ACCESS (code=2, address=0xf)
The log shows the following:
DBannerView: Unhandled error (no delegate or delegate does not implement didFailToReceiveAdWithError:): Error Domain=ADErrorDomain Code=3 "The operation couldn’t be completed. Ad inventory unavailable" UserInfo=0x13c9e380 {ADInternalErrorCode=3, ADInternalErrorDomain=ADErrorDomain, NSLocalizedFailureReason=Ad inventory unavailable}
And my app code for the ad handling:
#pragma mark Ad Banner Delegate
#pragma mark -
- (void)bannerViewDidLoadAd:(ADBannerView *)banner{
// remove the google advert banner
[googleAdvertBanner removeFromSuperview];
// dont use auto resizing mask for constraints
advertBanner.translatesAutoresizingMaskIntoConstraints = NO;
// scroll the ad bar
[self moveViews:adView down:YES];
//NSLog(#"IAD advert has SUCCEEDED");
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
// scroll the ad bar
[self moveViews:adView down:NO];
// create the google advert
[self createGoogleAdvert];
//NSLog(#"IAD advert has FAILED");
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner{
}
#pragma mark GoogleAd Banner Delegate
#pragma mark -
- (void)adViewDidReceiveAd:(GADBannerView *)view{
// dont use auto resizing mask for constraints
googleAdvertBanner.translatesAutoresizingMaskIntoConstraints = NO;
// add the google advert banner
[adView addSubview:googleAdvertBanner];
// scroll the ad bar
[self moveViews:adView down:YES];
//NSLog(#"Google advert has SUCCEEDED");
}
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error{
// remove the google ad and instantiate the apple advert
[googleAdvertBanner removeFromSuperview];
// scroll the ad bar
[self moveViews:adView down:NO];
//NSLog(#"Google advert has FAILED");
}
- (void)adViewDidDismissScreen:(GADBannerView *)adView{
}
#pragma mark Create GoogleAd Banner
#pragma mark -
- (void)createGoogleAdvert{
// if the googleadvert banner has not been initiated
if (!googleAdvertBanner) {
// create google advert banner
googleAdvertBanner = [[GADBannerView alloc]initWithAdSize:kGADAdSizeBanner];
}
// set the ads "unit identifier", delegate and root view controller
googleAdvertBanner.adUnitID = #"myid which is correct";
googleAdvertBanner.delegate = self;
googleAdvertBanner.rootViewController = self;
// test request
//GADRequest *testRequest = [GADRequest request];
//testRequest.testDevices = [NSArray arrayWithObjects:GAD_SIMULATOR_ID, #"0525457c40445ae54cac4f282ba0d409", nil];
// release request
GADRequest *releaseRequest = [GADRequest request];
// load the request
[googleAdvertBanner loadRequest:releaseRequest];
}
Try to check internet reachability before performing GADRequest. I had experience with crashing on loading adMob banners offline.
if ([[Reachability reachabilityForInternetConnection] isReachable]) {
//... banner init etc
// release request
GADRequest *releaseRequest = [GADRequest request];
// load the request
[googleAdvertBanner loadRequest:releaseRequest];
}
Ok think i solved this issue:
I had my admob mediation also serving the iAd as well as having an adbannerview, and i believe that on the lower end IOS version 6.0-6.1 When the mediated iAd failed it was unable to call the failedToLoad as the adbannerview did not exist or it was simply couldnt run the method, removing the mediation from my admob setup solved the crash.