iAd freezes game's scene - ios

I am developing a game using SpriteKit. I have iAds displayed in a view on the scene. When an ad in the Ad view is touched, the Ad appears, however, if I cross(X)/close the ad the scene in the game is frozen. I do not pause the scene or do anything on the events when the Ad appears and disappears. If I touch the ad again (now this is second time with frozen scene) and return to the scene, the scene un-freezes and everything starts to work as they were suppose to (strangely). I am not sure where is the problem in iAd or my app?
// Method is called when the iAd is loaded.
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
NSLog(#"Banner did load");
[self animateAdBanner];
}
-(void) animateAdBanner{
if(iAdsEnable){
[UIView animateWithDuration:6 delay:8
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
[self.adBanner setAlpha:0.85];
}
completion:^(BOOL finished){
if(finished){
//[self.adBanner setAlpha:0.7];
}
}];
}
}

According to Apple's ADBannerViewDelegate Protocol Reference:
bannerViewActionShouldBegin:willLeaveApplication:
If the willLeave parameter is YES, then your application is moved to the background shortly after this method returns. In this situation, your method implementation does not need to perform additional work. If willLeave is set to NO, then the triggered action will cover your application’s user interface to show the advertising action. Although your application continues to run normally, your implementation of this method should disable activities that require user interaction while the action is executing. For example, a game might pause its game play until the user finishes watching the advertisement.
Basically meaning that as your game is pushed into the background, the game will pause.
The delegate has a further method to notify you when the banner view has finished its action:
bannerViewActionDidFinish:
Discussion
If your delegate paused activities before allowing an action to run, it should resume those activities when this method is called.
It seems you can either use the above delegate methods to implement your own pause/un-pause or you could use the a NSNotification in your Scene to pause/un-pause when your app moves into the background and foreground respectively.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(pause)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(unPause)
name:UIApplicationWillEnterForegroundNotification
object:nil];
Sources:
iAd Framework Reference and ADBannerViewDelegate Protocol Reference

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.

pausing spritekit game using appdelegate in ios8

I have a pause menu in my game that I want to toggle when the i hit my home button. it works when I'm within my game, however when I hit my home button the menu comes up, but the game will not pause.
when i restart the app, the menu is still there, but the game un-pauses itself. It seems like spritekit automatically pauses and restarts the game on its own when you leave and enter the app. When I'm within the app I have full control over it. But when I'm exiting/entering the app it behaves how it likes.
Any suggestions?
func applicationWillResignActive(application: UIApplication!) {
// get the root viewcontroller
// toggle my pausemenu method. pause menu sets skview.paused = true
}
Send an NSNotification to GameSceneViewController to pause the SKScene:
AppDelegate:
- (void)applicationWillResignActive:(UIApplication *)application
{
// Pause sprite kit scene
[[NSNotificationCenter defaultCenter] postNotificationName:#"PauseGameScene" object:self];
}
GameSceneViewController:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(pauseGameScene)
name:#"PauseGameScene"
object:nil];
}
- (void)pauseGameScene {
if (self.skView.scene) {
self.skView.paused = self.skView.scene.paused = YES;
}
}

Enable UIButton after UIImagePicker is presented

I have tried everything or at least I think I have.
I am presenting a custom UIImagePicker with a shutter UIButton disable.
This UIButton is only enable when my view controller receives a notification telling that the camera is ready.
This method is being called; however, when I set the UIButton to enable nothing happen. The button is there because I can touch it but I cannot see it.
Here is a piece of code:
- (void)viewDidLoad
{
...
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cameraIsReady:) name:AVCaptureSessionDidStartRunningNotification object:nil];
}
- (void)cameraIsReady:(NSNotificationCenter *)notigivation{
NSLog(#"Camera is ready");
[self.shutterButton setEnable:YES];
[self.shutterButton setNeedsDisplay]; //I tried with and without this method.
}

How can I stop iOS displaying snapshot on resume?

I am creating an app with functionality like a stopwatch. When the app moves to the background, iOS takes a snapshot, and when it moves back into the foreground it uses that snapshot for the animation while switching back to the app.
This means that if the app was backgrounded for 10 seconds, the stopwatch will have the wrong time (by 10 seconds) displayed during the opening animation.
Is there some way to stop iOS taking this snapshot, or stop iOS from using it when the app moves back to the foreground?
You can not stop iOS from taking snapshot.
But you can display and hide a temporary view using below notifications :
UIApplicationDidEnterBackgroundNotification
UIApplicationWillEnterForegroundNotification
The temporary view will be then taken as the snapshot.
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(displayTempView) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(hideTempView) name:UIApplicationWillEnterForegroundNotification object:nil];
- (void) displayTempView {
tempWebView.hidden = NO;
}
- (void) hideTempView {
tempWebView.hidden = YES;
}
Hope it helps.

Finish up existing iOS animation

I have an application with multiple views that transitions to the main screen depending on which button was pressed. My current problem is that if the view is in the middle of animating then when the user selects another button then the whole layout becomes messed up. (ex: the views don't align with the screen meaning that they become a few pixels off)
What I would like to know is if there is a way to check if the view is currently animating and if so just have it animate to the last frame and skip anything in between. Below is a small piece of code that I have just tested based on what I have read on other user asked questions on SO:
-(IBAction)buttonPress:(id)sender
{
if([selectedView.layer.animationKeys count] > 0)
{
[selectedView.layer removeAllAnimations];
}
// Perform other calculations once the animation has stopped
}
There are many ways to do this but....
If you are using block animations you could set a "isAnimating" flag when the animation starts and set it again in the completion block. You could check the bool from anywhere and handle cases as needed.
As for needing code to execute after an animation occurs, but
// animation code in some method...
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
isAnimating = YES;
fooView.alpha = 0.0;
}
completion:^(BOOL finished){
isAnimating = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:#"FooBeDone" object:nil userInfo:nil]
}];
-(IBAction)buttonPress:(id)sender {
if (isAnimating) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doBar:)
name:#"FooBeDone"
object:nil];
// possibly disable button to prevent multiple taps?
} else {
[self doBar];
}
}
- (void)doBar {
// do what needs to be done when when the animation is over
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"FooBeDone" object:nil];
// possibly enable button again
}
edit: I added more code to show a possible notification method. Creating extended loops in your IBAction will lock the user interface until the loop finishes and you can get back to the main run loop, so it's highly advised to avoid it. Notifications should give you the same effect but allow your main run loop to continue unhindered.

Resources