I am writing an iOS VoIP app that has background mode permission. In background, it will be listening for incoming connection, and once I have an incoming connection, it should start a UIViewController for the user to accept the call. How and where to call and present a UIViewController from background?
I know how to do this in Android, a Service would call an Activity via an Intent.
But in iOS , I am not sure how would the flow go. Also, how do I go into background mode in iOS? I know it has to do with the appDelegate method applicationDidEnterBackground: , But not sure what to do next.
Thanks in advance.
there are two methods in appDelegate that will be called when the app returns to active state. First one is - (void)applicationWillEnterForeground:(UIApplication *)application and the second one is - (void)applicationDidBecomeActive:(UIApplication *)application
In the 2nd you have to restore your user interface.
Related
I'm developing an iOS app that uses CoreLocation in order to manage iBeacons. I have Beacon detection in both the AppDelegate and ViewController, but I want the AppDelegate detection to only work when the app is in background state. I send analytics to a server when the user enters or leaves a region, so if both (AppDelegate and ViewController) detections work when the app is in Foreground, the app will send doubled analytics.
Any solutions to make a code (the server call to send analytics) not to run when the app is in Foreground?
In AppDelegate start your beacon detection in the applicationDidEnterBackground: method and stop beacon detection in the applicationWillEnterForeground: method.
Simply implement methods in your AppDelegate to track if you are in the foreground, and stop sending analytics from your AppDelegate if so. See below:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
_sendAnalytics = YES;
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
_sendAnalytics = NO;
}
Then add an if statement before sending analytics from the AppDelegate to check the value of _sendAnalytics.
Centralizing this logic as #paulw11 suggests in his comment would probably make the code cleaner, but if you do need to send analytics in two places, the above will solve your problem.
Here's my app scenario: When user swipes a notification I will launch some other app via URL.
So it basically launches some other app when notification arrives.
Currently to handle swiping notification scenario, when
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)
method is invoked, within this method, I call processNotification: method, which contains:
...
[[UIApplication sharedApplication] openURL:url];
...
If push received while app is active, url is opened perfectly fine.
If push received by swiping or clicking on notification, url is opened in the background but the currently viewed app is my application. For example if my url is tel:123-456-7890, iOS starts the call (you can hear the sound) but active app is not Phone.app, it is my app.
That seemed pretty strange to me. However if I wait for UI to load, and call processNotification: after that, it brings up Phone.app window correctly. (bug in platform? because call happens but my UI is on the top.)
I need a method to delay execution of this processNotification: call, (maybe through an operation queue) until a view controller is loaded. Otherwise, my app stays on top and the URL is opened in the background.
I was facing the same issue, I moved the openURL into main_queue and it seems to be working fine. I did not have to even make that change in didBecomeActive
dispatch_async(dispatch_get_main_queue(), ^(void){
[[UIApplication sharedApplication] openURL:url];
});
You should delay your handling of the push notification (i.e. calling openURL:) until applicationDidBecomeActive:. Keep the parameters you need from application:didFinishLaunchingWithOptions: but only call your handling code in applicationDidBecomeActive:.
I think the problem here is that SpringBoard is unable to cope with one app transition being called while another is in progress. An iOS bug of course. You should open a bug report at https://bugreport.apple.com
I want to check every time the app launches whether or not there's a URL in the clipboard, and if so, do something with it. Which method fires that I can override whenever the app launches, whether from a cold launch (it was killed in the background for instance) or if I just press the home button, copy a URL and jump back in.
Is it one of these?
- (void)applicationDidBecomeActive:(UIApplication *)application
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive
- (void)applicationDidFinishLaunching:(UIApplication *)application
Confused.
As #rmaddy says, the correct method to use once the app launched is applicationWillEnterForeground: from your app delegate.
This method will be called when the user jump backs in, but NOT in other circumstances you don't need to respond to (such as the user receiving a text message and dismissing it).
However, from my testing, applicationWillEnterForeground: is not called when an app is launched from cold; you should catch that in applicationDidFinishLaunchingWithOptions:.
So, basically, your app delegate should include code like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self checkForURL];
...
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self checkForURL];
...
}
- (void)checkForURL{
//code for checking for URL goes here
}
Hope that helps.
- (void)applicationDidBecomeActive is called when the app is launched or becomes active from the background.
This doc explains everything pretty well: http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
With reference to the UIApplicationDelegate Protocol, the handling of app launches can be handled in 2 methods:
application:willFinishLaunchingWithOptions:
application:didFinishLaunchingWithOptions:
And the handling of app launches from background can be handled with the help of method:
applicationDidBecomeActive:
Based on the above call, you can handle your application.
In your app delegate add it to the methods that the other answers have suggested (applicationDidFinishLaunchingWithOptions:). In your root view controller register for the following notification. This will always be called when your application launches once it has already started running.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(bringingItBack) name:UIApplicationWillEnterForegroundNotification object:nil];
This will cover both the instances when the app launches and when you are just bringing it back from the background.
I read through almost a dozen questions on SO and Apple documentation, but still unclear on one case (mainly, because everybody use a little different terminology).
The case which I am interested in is:
a) An application is running in background state (as example VOIP).
I refer to background state as defined here
b) The application is registered for remote notifications.
c) Provider sends a push notification. iOS devices receives this notification.
What will happen next?
1) iOS will display according UI (alert, badge) and no delegate will be called until user clicks VIEW button on an alert or will tap application icon on Springboard.
My understanding this is what suppose to happen.
or
2) didReceiveRemoteNotification delegate will be called immediately
I would appreciate, if you can clear this out for me.
No delegate will be called until you eneter application by tapping on the notification.
Then this is the order of callbacks:
1) applicationWillEnterForeground
2) didReceiveRemoteNotification
2) applicationDidBecomeActive
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
will be called.
Which is the proper delegate to implement when an application is waking up from being in the background and you want it to prep it to be active?
applicationWillEnterForeground vs applicationDidBecomeActive -- What's the difference?
Which is the proper delegate to implement for when an application is going to sleep and you want to prep it to cleanup and save data?
applicationWillResignActive vs. applicationDidEnterBackground -- What's the difference?
Also, I've noticed that applicationWillResignActive gets called when an incoming SMS or call comes in but the user chooses to click Ok and continue. I don't want my app to take any action in these cases. I just want it to keep running without any intermediate cleanup since the user didn't exit the app. So, I would think it makes more sense to do cleanup work just in applicationDidEnterBackground.
I would appreciate your input on best practices to follow on choosing which delegates to implement for waking up and going to sleep as well as considering events like being interrupted by SMS/calls.
Thanks
When waking up i.e. relaunching an app (either through springboard, app switching or URL) applicationWillEnterForeground: is called. It is only executed once when the app becomes ready for use, after being put into the background, while applicationDidBecomeActive: may be called multiple times after launch. This makes applicationWillEnterForeground: ideal for setup that needs to occur just once after relaunch.
applicationWillEnterForeground: is called:
when app is relaunched
before applicationDidBecomeActive:
applicationDidBecomeActive: is called:
when app is first launched after application:didFinishLaunchingWithOptions:
after applicationWillEnterForeground: if there's no URL to handle.
after application:handleOpenURL: is called.
after applicationWillResignActive: if user ignores interruption like a phone call or SMS.
applicationWillResignActive: is called:
when there is an interruption like a phone call.
if user takes call applicationDidEnterBackground: is called.
if user ignores call applicationDidBecomeActive: is called.
when the home button is pressed or user switches apps.
docs say you should
pause ongoing tasks
disable timers
pause a game
reduce OpenGL frame rates
applicationDidEnterBackground: is called:
after applicationWillResignActive:
docs say you should:
release shared resources
save user data
invalidate timers
save app state so you can restore it if app is terminated.
disable UI updates
you have 5 seconds to do what you need to and return the method
if you don't return within ~5 seconds the app is terminated.
you can ask for more time with beginBackgroundTaskWithExpirationHandler:
The official documentation.
Managing Your App's Life Cycle is helpful to your questions. For quick concept, you can see Figures in that document.
You can also read the comment from the code generated by the XCode Wizard. Listed as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state.
This can occur for certain types of temporary interruptions (such as an
incoming phone call or SMS message) or when the user quits the application
and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down
OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate
timers, and store enough application state information to restore your
application to its current state in case it is terminated later.
If your application supports background execution, this method is called
instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the active state;
here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the
application was inactive. If the application was previously in the
background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
For more detailed explanations, please refer to official document for UIApplicationDelegate
I was still a bit confused with Dano's answer so I did a little test to get the flow of events in certain scenarios for my reference, but it might be useful to you too. This is for apps that DO NOT use UIApplicationExitsOnSuspend in their info.plist. This was conducted on an iOS 8 simulator + confirmed with iOS 7 device. Please excuse Xamarin's event handler names. They are very similar.
Initial and all subsequent launches from a not-running state:
FinishedLaunching
OnActivated
Interruption (phone call, top slide-down, bottom slide-up):
Home button double-press listing inactive apps, then reselecting our app:
OnResignActivation
OnActivated
Home button double-press listing inactive apps, selecting another app, then relaunching our app:
Home button single press, then relaunch:
Lock (on/off button), then unlock:
OnResignActivation
DidEnterBackground
WillEnterForeground
OnActivated
Home button double-press, and terminate our app: (subsequent relaunch is first case)
OnResignActivation
DidEnterBackground
DidEnterBackground (iOS 7 only?)
Yes, DidEnterBackground is called twice on iOS7 device. Both times UIApplication state is Background. However, iOS 8 simulator does not. This needs testing on iOS 8 device. I will update my answer when I get my hand on it, or someone else could confirm.
applicationWillEnterForeground is called:
when app is relaunched(comes from background to foreground)
This method is not invoked when app starts for the first time i.e when applicationDidFinishLaunch is called but only when comes from background
applicationDidBecomeActive
applicationDidBecomeActive is called
when app is first launched after didFinishLaunching
after applicationWillEnterForeground if there’s no URL to handle.
after application:handleOpenURL: is called.
after applicationWillResignActive if user ignores interruption like a phone call or SMS.
after disappearing of alertView anywhere from the application
applicationWillResignActive is called when system is asking for permissions. (in iOS 10). Just in case someone hit into the same trouble as me...
In iOS 8+ there is a subtle but important difference for taking phone call.
In iOS 7 if user takes phone call both applicationWillResignActive: and applicationDidEnterBackground: are called. But in iOS 8+ only applicationWillResignActive: is called.
For iOS 13+ the following methods will be executed:
- (void)sceneWillEnterForeground:(UIScene *)scene
- (void)sceneDidBecomeActive:(UIScene *)scene