My code for application will Enter Foreground is given below. I am working on the iOS simulator. What I am trying in my code is, when a player clicks home button while game is going on and returns back to the game after sometime, I want the game to be in pause state. Although my code pauses the game, but it does not pause it immediately. That is, when I go to my game again, there is 1 second of movement before everything pauses.
-(void)applicationWillEnterForeground:(UIApplication *)application
{ [[NSNotificationCenter defaultCenter] postNotificationName:#"didEnterForeground" object:self];
}
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(handleEnterFg)
name: #"didEnterForeground"
object: nil];
-(void) handleEnterFg
{
if (gameIsOver== NO)
{
[myTimer pause];
gamePause = YES;
self.scene.view.paused = YES;
}
}
-(void) handleEnterBg
{
if (gameIsOver== NO)
{
[bgPlayer pause];
[self childNodeWithName:#"pauseButton"].zPosition = -10;
[self childNodeWithName:#"playButton"].zPosition = 160;
}
}
Thank you!
You need to pause the game when you receive applicationWillEnterBackground if you want to pause it immediately.
Related
I am getting EXC_BAD_ACCESS crash that occurs in the AudioToolBox. How to handle interrupts properly?
Please have a look at crashlytics screenshot for more info.
My audio streaming player was crashing when I get a phone call/ faceTime. It was actually an older class with Non ARC. Simply Add an InterruptionNotification Observer for the streaming class, and if the streaming class is playing we need to pause the player instance while interrupt begins.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleInterruptionChangeToState:) name:#"ASAudioSessionInterruptionOccuredNotification" object:nil];
- (void)handleInterruptionChangeToState:(NSNotification *)notification {
AudioQueuePropertyID inInterruptionState = (AudioQueuePropertyID) [notification.object unsignedIntValue];
if (inInterruptionState == kAudioSessionBeginInterruption){
if ([self isPlaying]) {
[self pause];
pausedByInterruption = YES; //a global Bool variable
}
}
else if (inInterruptionState == kAudioSessionEndInterruption){
AudioSessionSetActive( true );
if ([self isPaused] && pausedByInterruption) {
[self pause]; // this is actually resume
pausedByInterruption = NO;
}
}
}
Hope it helps.
I'm in the process of developing an iOS app where I need to track if the user leaves the app (presses the home button to use other apps) while they are 'in game' however the user should be able to lock and un-lock their device without this function being called.
func applicationDidEnterBackground(application: UIApplication) {
if defaults.boolForKey("TimerActive"){
defaults.setBool(true, forKey: "Failed")
}
}
This, unfortunately, is triggered when the user locks their devices as well as when they exit the app.
A little context about the app: The app encourages people to focus on their work and not become distracted by their phones for a preset time period.
Other suggestions of how I can encourage the users to reopen the app upon exit while the timer is still active but not when they lock their devices would be greatly welcomed!
Well, there's no clean way to do this. But there is a hack that you can use. It's not guaranteed to keep working though(I've tested up to iOS 9.3 and I'm pretty sure it works on the iOS 10 betas).
The idea is that there's a system-wide notification for the phone being locked. You can listen to that and coupled with listening to background/foreground events on your app you can determine what's happening.
This is a piece of code for an object that will watch for this stuff. Create it from app delegate or wherever and keep a strong ref for as long as you need it. Give it a delegate it can call for whatever events you want to observer and react to(or put the code right there in checkState). I haven't compiled this so I may have made some errors typing it up. It's derived from code I use in an app, but the original has a lot more stuff I won't post here. It's in objc but it shouldn't be too hard to convert to swift(someone feel free to post a second answer in swift or edit mine, but I don't have the time to do it right now)
#interface LockStateDetector : NSObject {
int _notify_token;
}
#property BOOL deviceIsLocked;
#property BOOL appIsInBackground;
#property NSTimer * checkStateTimer;
#end
#implementation LockStateDetector
- (instancetype)init
{
self = [super init];
if (self) {
[self registerForNotifications];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
notify_cancel(_notify_token);
}
- (void)registerForNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didMoveToBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
__weak__ LockStateDector * wSelf = self;
notify_register_dispatch("com.apple.springboard.lockstate", &_notify_token, dispatch_get_main_queue(), ^(int token) {
__strong__ LockStateDetector sSelf = wSelf;
if (!sSelf) {
return;
}
uint64_t state = UINT64_MAX;
notify_get_state(token, &state);
sSelf.deviceIsLocked = state != 0;
NSLog(#"device lock state changed: %#", #(state));
[sSelf checkState];
});
}
- (void)didBecomeActive
{
self.appIsInBackground = NO;
[self checkState];
}
- (void)didMoveToBackground
{
self.appIsInBackground = YES;
[self checkState];
}
- (void)checkState
{
[self.checkStateTimer invalidate];
self.checkStateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(_checkState) userInfo:nil repeats:NO];
}
- (void)_checkState
{
[self.checkStateTimer invalidate];
self.checkStateTimer = nil;
if (!self.appIsInBackground) {
return;
}
if (!self.deviceIsLocked) {
// app is in background because device was locked
} else {
// app is in background because user pressed home and switched to something else
}
}
AVPlayer video not resuming from where it left, instead video starts from beginning. Here is my code.Can anyone help me??
-(void)appEnteredForeground:(NSNotification*)notification {
if(playerViewController.player.status == AVPlayerStatusReadyToPlay &&
playerViewController.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
total_duration = self.playerViewController.player.currentItem.duration;
[self.playerViewController.player seekToTime:currentTime];
[_playerViewController.player play];
}
}
-(void)appEnteredBackground:(NSNotification*)notification {
[playerViewController.player pause];
currentTime = [playerViewController.player currentTime];
[playerViewController.player seekToTime:currentTime];
}
1.It's seek to time problem, when u ask it to seek to time, it can't be done as it's already in background. Why did u seek to time when u enter background? pause should do just fine. remove the following line.
[playerViewController.player seekToTime:currentTime];
2.you had better pause in resign active notification instead of background notification. because the last one shall be triggered in a few seconds later after pressing the home button
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(becomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(resignActive) name:UIApplicationWillResignActiveNotification object:nil];
}
- (void)becomeActive {
NSLog(#"active");
if(playerViewController.player.status == AVPlayerStatusReadyToPlay &&
playerViewController.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
total_duration = self.playerViewController.player.currentItem.duration;
[self.playerViewController.player seekToTime:currentTime];
[_playerViewController.player play];
}
}
- (void)resignActive {
NSLog(#"resign active");
[playerViewController.player pause];
currentTime = [playerViewController.player currentTime];
}
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;
}
}
I need to pause the game before my game goes to background, so when it comes to foreground again I see the pause dialog in my game. To show pause dialog I have a scene method. How to call scene method right before application goes to background? I see that the following method is the right place:
-(void) applicationDidEnterBackground:(UIApplication*)application
{
if( [navController_ visibleViewController] == director_ )
[director_ stopAnimation];
}
Should I just get the scene from director runningScene, cast it to my scene class and then send pause message to it or that way is ugly?
In this scenario, I think Notifications are the cleanest and safest option. You can just post a notification from applicationDidEnterBackground and receive wherever you want to perform certain actions like:
In App Delegate:
- (void)applicationDidEnterBackground:(UIApplication*)application {
[[NSNotificationCenter defaultCenter] postNotificationName:#"EnteringBackground" object:nil];
}
In GameScene:
- (void)onEnter {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(showPausePopup) name:#"EnteringBackground" object:nil];
}
- (void)onExit {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)showPausePopup:(NSNotification*)notification {
// Code to show popup
}