I’m building an application which supports both video playback and recording (not simultaneously, it’s just two separate features it provides). In order to make the videos play after the app enters background and gets back, I had to add an App plays audio item to Required background modes in the plist (I’m using MPMoviePlayerController for playback).
This, however, causes a problem with my video recording (I’m using UIImagePickerController for it). Basically, even after the picker is dismissed (either by the Cancel button or when it’s finished picking media), the app still keeps the audio recording session running.
If I remove the App plays audio item from the plist, the ImagePickerController’s audio session stops misbehaving, but then I can’t resume the playback of MPMoviePlayerViewController on switching to app from background mode.
Is there a way I can customise the handling of the audio session so that both the MPMoviePlayerController and UIImagePickerController can work properly?
yes, there is a way you can customize the handling of the audio session for what you desire: don't try to set the App plays audio setting.
instead, in your AppDelegate code (which is usually in AppDelegate.m from the simple wizard projects provided), supply code in the applicationWillResignActive: method that will stop the playback in your MPMoviePlayerController, and then use applicationDidBecomeActive: to resume the playback at the point at which you paused it if so desired.
this will not only allow the video to be resumed after a temporary pause, but it will allow you to save the state so that the video can be resumed in case the app is removed from memory or in case the user causes it to be quit.
You can scratch the background modes and instead use notifications to pause/resume your player. See UIApplicationDidBecomeActiveNotification and UIApplicationWillResignActiveNotification in the UIApplication class reference.
You can snag some code and see this implemented in this class. Here is some of the relevant code from that class:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(_didBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(_willResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
- (void) _didBecomeActive:(NSNotification*)notification {
if (_wasPlaying) {
[_movieController play];
}
}
- (void) _willResignActive:(NSNotification*)notification {
_wasPlaying = _movieController.currentPlaybackRate != 0.0;
if (_wasPlaying) {
[_movieController pause];
}
}
Related
Hi friends i'm developing MAC desktop application using cocoa. I want to add session time out for in the app. Example my application running in background user dont touch and do nothing in app. After 20(we need to set) app will return home page(login page) for session time out.
Will help me how to set session in cocoa application
Use a custom NSApplication class and override sendEvent:. Something like this:
- (void)sendEvent:(NSEvent *)event
{
[super sendEvent:event];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(applicationSessionTimeout:) object:nil];
[self performSelector:#selector(applicationSessionTimeout:) withObject:self afterDelay:SESSION_TIMEOUT];
}
Basically all mouse and keyboard events enter your app through this method. You just need to override it to set your timers.
I have a Single View Application. When I hit the home button and ‘minimise’ the application I want to be able to execute code when the user reopens it.
For some reason viewDidAppear and viewWillAppear do not execute when I minimise and reopen the application.
Any suggestions?
Thanks in advance
sAdam
You can either execute code in the app delegate in
- (void)applicationDidBecomeActive:(UIApplication *)application
or register to observe the UIApplicationDidBecomeActiveNotification notification and execute your code in response.
There is also the notification UIApplicationWillEnterForegroundNotification and the method - (void)applicationWillEnterForeground:(UIApplication *)application in the app delegate.
To hook up notifications add this at an appropriate point
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
Define a the corresponding method
- (void)didBecomeActive:(NSNotification *)notification;
{
// Do some stuff
}
Then don't forget to remove yourself an observer at an appropriate point
[[NSNotificationCenter defaultCenter] removeObserver:self];
Discussion
You most likely only want your viewController to respond to events whilst it is the currently active view controller so a good place to register for the notifications would be viewDidLoad and then a good place to remove yourself as an observer would be viewDidUnload
If you are wanting to run the same logic that occurs in your viewDidAppear: method then abstract it into another method and have viewDidAppear: and the method that responds to the notification call this new method.
This is because since Apple implemented "Multitasking", apps are completely reloaded when you start them again, just as if you had never closed them. Because of this, there is no reason for viewDidAppear to be called.
You could either implement
- (void)applicationWillEnterForeground:(UIApplication *)application
and do there what ever you want. Or you register for the notification UIApplicationWillEnterForegroundNotification in your view controller. Do this in viewDidLoad:
[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myAppWillEnterForeground)
name:UIApplicationWillEnterForegroundNotification object:nil];
And of course implement the specified selector and do there what you want.
I am not sure how the answer by #Paul.s performs the OP request since registering UIApplicationDidBecomeActiveNotification will be executed twice:
When launching the app
When application goes into the background
A better practice will be to decouple those events into 2 different notifications:
UIApplicationDidBecomeActiveNotification:
Posted when the app becomes active.
An app is active when it is receiving events. An active app can be said to have focus. It gains focus after being launched, loses focus when an overlay window pops up or when the device is locked, and gains focus when the device is unlocked.
Which basically means that all logic related to "when application launched for the first time"
UIApplicationWillEnterForegroundNotification:
Posted shortly before an app leaves the background state on its way to becoming the active app.
Conclusion
This way we can create a design that will perform both algorithms but as a decoupled way:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(yourMethodName1) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(yourMethodName2) name:UIApplicationDidBecomeActiveNotification object:nil];
This because you don't redraw your view. Use applicationWillEnterForeground in the AppDelegate instead. This should work fine for you.
I am developing an iOS Application which uses CLLocationManager to get GPS Data.
What's a proper way to stop CLLocationManager when the user presses the home button and then kills the app using fast app switcher?
How can I stop the CLLocationManager then to stop polling for GPS data? Does anybody knows a good way to achieve this, cause normally I can't execute any code when the user kills the application...
EDIT:
When I am sending the application to background, it should still get significantLocationChanges, so I can't stop CLLocationManager when the application is sent to the background!
In the AppDelegate there is a method called applicationWillResignActive. This method runs when your app is about to be sent to the background. If you have access to the CLLocationManager from your AppDelegate you can stop it right there. Otherwise you can post a Notification from applicationWillResignActive and whatever class has your CLLocationManager can subscribe to that Notification and handle it from there.
Post a Notification like this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"appWillResignActive" object:nil];
And subscribe like this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleResign:) name:#"appWillResignActive" object:nil];
Then some method like this:
- (void)handleResign: (NSNotification *)notification
{
// stop CLLocationManager
}
EDIT:
If you want to run code when the app is being killed then you can run that code in this method in the AppDelegate:
- (void)applicationWillTerminate:(UIApplication *)application
I am making a game for iPhone and want to be able to pause a timer when a user's game is interrupted like when they hit the home button. I know that in the app delegate there is a method when the app leaves the foreground called:
- (void)applicationWillResignActive:(UIApplication *)application
What I am struggling with is how to pause the timer. I have a function in my view controller that's called pauseGame and is used for when the user wants to pause the game. I was thinking that it would be easiest to pause the game by using this method. I cannot however understand how to call this method. Any ideas? And sorry for the beginner question.
The shortest way is to Use Notifications:
1. define a custom notification, at your application delegate (or anywhere else...)
#define kApplicationWillResignActiveNotification
#"kApplicationWillResignActiveNotification"
2. dispatch the notification when the applicationWillResignActive: method is called
[[NSNotificationCenter defaultCenter] postNotificationName:
kApplicationWillResignActive object:nil];
3. listen to that notification where ever you want in your project (* import the header file where you #defined the notification)
[[NSNotificationCenter defaultCenter] addObserver:self
selector: #selector(appResigned:)
name:kApplicationWillResignActiveNotification object: nil];
4. you can get the NSNotification Object if you add it to your selector
-(void)appResigned:(NSNotification *)notification;
I am using a music player property for iPod player controller.
// .h
#property (nonatomic, retain) MPMusicPlayerController *ipodPlayer;
// .m
ipodPlayer = [MPMusicPlayerController iPodMusicPlayer];
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:#selector(changedPlaybackState:) name:MPMusicPlayerControllerPlaybackStateDidChangeNotification object:ipodPlayer];
[notificationCenter addObserver:self selector:#selector(changedNowPlayingItem:) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:ipodPlayer];
[ipodPlayer beginGeneratingPlaybackNotifications];
During background processing, if iPod player app is terminated, the console prints out:
MediaPlayer: Message playbackState timed out.
If it doesn't crash(or freezes, slowing performance), the notification is not being sent to my observing methods anymore. I can still send messages like:
[ipodPlayer pause];
[ipodPlayer play];
[ipodPlayer skipToNextItem];
[ipodPlayer skipToPreviousItem];
but can't receive any notifications
My questions are:
Is there are way to reassign, reload pointers during runtime? How can I restore the property to be just like when it's first launched?
How can I catch the messge:"MediaPlayer: Message playbackState timed out." in console output? This is not like using NSLog.
Thank you for helping me.
UPDATED:
It seems like using assign or weak for ipodPlayer property was the solution. Also, accessing it is done with assumption that the property may not be there. After many trials and a year of actually using it in my app, I think this was the right solution.
I had similar issue with my MpMoviePlayerController in iOS 5. I Found a fix that took care of it. It might work here as well.
Add:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
in viewDidLoad.
More my other post