Backgrounding behaviour when an outgoing phone call is made, iOS7 vs iOS8 - ios

When my iOS app makes a phone call by doing the following:
NSString *telephoneUrl = #"tel:12345678";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:telephoneUrl]];
what happens to the app lifecycle state?
e.g. if I put the following lines below the above phone call lines:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(#"dispatch callback was called!!!");
});
On iOS 7, applicationDidEnterBackground is called, the above code doesn't run, and when the phone call terminates, I am inside the Phone app. The console lines are written only when i return to my app.
However, on iOS 8, only applicationWillResignActive is called and the app doesn't enter background, and you can actually see the log being written to the console while I am inside the phone call. When the call terminates, i am still inside my app.
Can someone confirm the behaviour, or point me to the relevant documentation?

Yes iOS 7 & iOS 8 are different here. And I can't find document about it either.
So in iOS 7 if you have an incoming call applicationWillResignActive: will be called first. If you reject the phone applicationDidEnterBackground will not be called;but if you answer the phone applicationDidEnterBackground will be called and when you end the phone and your app become active again applicationWillEnterForeground: will be called too.
But in iOS 8 only applicationWillResignActive: will be called no matter you answer the phone or not.

Related

iOS - How to guarantee that applicationWillTerminate will be executed

Is there A way to guarantee that the applicationWillTerminate method in the AppDelegate delegate will be hit? Something like a key in the info.plist file, etc..?
My goal: I'm working in a beacon app, the piece of code is in this article. My problem is that the message from the didEnterRegion keeps poping even when i'm beside the beacon. To solve that I'm setting a flag to control the message. My code below:
if(!UserDefaults.standard.bool(forKey: Constants.EnterZoneMsgShowName)){
let notification = UILocalNotification()
notification.alertBody = "Hi, you are about to arrive at CIDMA's office. Please open de demo app and turn on the bluetooth on your device to enrich your experience. "
UIApplication.shared.presentLocalNotificationNow(notification)
UserDefaults.standard.set(true, forKey: Constants.EnterZoneMsgShowName)
}
I want to set this flag to false when I close the app. I tried to put it at the applicationWillTerminate but this method is not hit every time.
I would like to know how to guarantee that this code will be hit or if there is a better place to put the code: UserDefaults.standard.set(false, forKey: Constants.EnterZoneMsgShowName)
applicationWillTerminate(_:) - Tells the delegate when the app is about
to terminate.
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app.
For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
What you want to call is applicationDidEnterBackground if your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

phone call failure or disconnected call backs while making a phone call

On a button click I am making a call inside my app by using the following code
NSString *phoneNumber =#"telprompt://123-4567-890";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
I want to do some working if the call is failed or disconnected (might be due to low balance or network signal problem). Is there any delegate for call disconnect or failure for doing this? Any help will be appreciated.
No, once you have handed over functionality to the telephone app your app is then put in the background and will only be activated once the user goes back to it manually.

Objective-c make phone call in background mode

I have to solve the following problem in objective-c:
Application in background
For an event, i need to call a specific phone number on the iPhone while it is still in background
As i see my logs, the phone call method will be called, but the phone number not dialing by the iOS.
Here is the action method:
//------------------------------------------------//
- (IBAction)actionCall:(id)sender
{
id<ICallModel> _AutoCall = [self retrieveAutoCall];
if(_AutoCall != nil)
{
DDLogDebug(#"RESCUE CALL: %#",_AutoCall.PhoneNumber);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:#"tel:%#",_AutoCall.PhoneNumber]]];
}
[self actionCancel:nil];
}
//------------------------------------------------//
If the application is active, then it works perfectly.
I've added the proper background modes too.
Is it possible some way to achieve this flow?
Thanks,
Tom
Apple doesn't allow you to start calls if your app is running in the background.
What you could do is using Local Notifications to make the user returning to your app.
Once your app is back in the foreground it could start the call.

What is the proper way to handle background tasks in iOS

I have a voip app and it needs to run in the background. To my understanding these are the things I need to do:
Flag the app as voip.
Set the 'application does not run in background' flag to NO.
Set an expiration handler, a piece of code that extends the standard 10 minutes of execution time you get.
More?
I set both flags in the info.plist file and I get my 10 minutes. I tried what is suggested in this post. Here is my code:
//in didFinishLaunchingWithOptions:
expirationHandler = ^{
NSLog(#"ending background task");
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
NSLog(#"restarting background task");
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
NSLog(#"finished running background task");
};
//in applicationDidEnterBackground
NSLog(#"entering background mode");
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// inform others to stop tasks, if you like
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyApplicationEntersBackground" object:self];
//this while loop is just here for testing
inBackground = true;
while (inBackground) {
NSLog(#"stayin alive!!"); //this keeps going forever
sleep(10);
}
});
The situation:
I use a third party library that handles the communication with our webservice. The service is a CommuniGate pro server. I receive presence updates (online/offline) and instant messages from contacts via the library. The library is CommuniGate's ximss library, a protocol they made which is similar to xmpp and is used for xml-based sip requests, as well as IM and presence. When the user logs in to the app, he sees his contacts (CmmuniGate friends list) and he can choose to call one. After a ximss verification message has been sent and the other side accepted the call it logs the start time of the call and starts a facetime call.
The problem:
When the app enters the background by pressing the home button, I start seeing the 'stayin alive' message in the log and every ten minutes I see that it restarts the background task.
When the app enters the background by pressing the power button, the 'staying alive' messages start showing up for ten minutes, after that it restarts the background task and start restarting it about every 50-100 miliseconds.
I would've been fine with this for now, even it eats battery, because I have time to work on updates and our users don't own the ipads, we do. The problem for me now is that the ximss library loses it's connection (it is session-based). I could restart the session in the library, but this means quite a bit of data transfer to fetch the contacts list and some users use 3g.
I can't edit the library's source, nor can I see it, so I don't know if it creates the sockets the right way.
What do I have to do to handle both situations correctly? I don't even understand why there is a difference.
You cannot re-extend background tasks like this; your app is likely to be terminated. If this is working, it's because you have the background voip mode enabled, not because you are restarting the background task.
Once you have set the voip plist entry, iOS will attempt to keep your app alive as long as possible and restart it if it does get terminated. From Implementing a VoIP App:
Including the voip value in the UIBackgroundModes key lets the system
know that it should allow the app to run in the background as needed
to manage its network sockets. An app with this key is also relaunched
in the background immediately after system boot to ensure that the
VoIP services are always available.
In addition to setting this key, if you need to periodically run code to keep your voip connection alive, you can use the setKeepAliveTimeout:handler: method on UIApplication.
See also Tips for Developing a VoIP App:
There are several requirements for implementing a VoIP app:
Add the UIBackgroundModes key to your app’s Info.plist file. Set the value of this key to an array that includes the voip string.
Configure one of the app’s sockets for VoIP usage.
Before moving to the background, call the setKeepAliveTimeout:handler: method to install a handler to be
executed periodically. Your app can use this handler to maintain its
service connection.
Configure your audio session to handle transitions to and from active use.
To ensure a better user experience on iPhone, use the Core Telephony framework to adjust your behavior in relation to cell-based
phone calls; see Core Telephony Framework Reference.
To ensure good performance for your VoIP app, use the System Configuration framework to detect network changes and allow your app
to sleep as much as possible.
Almost all of the documentation you need is on the Apple developer site.

Run app for more than 10 minutes in background

I am trying to keep the iOS app in active state for more than 10 mins when it enters in background state.
How can I implement this.
See "Background Execution" section of the iPhoneAppProgrammingGuide. In short, your app must be one of these types:
Apps that play audible content to the user while in the background, such as a music player app
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Newsstand apps that need to download and process new content
Apps that receive regular updates from external accessories
And you must add to the Info.plist as follows:
Add the UIBackgroundModes key to your
Info.plist file and set its value to an array containing one or more of the following strings:
audio—The app plays audible content to the user while in the background. (This content includes streaming audio or video content using AirPlay.)
location—The app keeps users informed of their location, even while it is running in the background.
voip—The app provides the ability for the user to make phone calls using an Internet connection.
newsstand-content—The app is aNewsstand app that downloads and processesmagazine or newspaper
content in the background.
external-accessory—The app works with a hardware accessory that needs to deliver updates on a
regular schedule through the External Accessory framework.
bluetooth-central—The app works with a Bluetooth accessory that needs to deliver updates on a
regular schedule through the CoreBluetooth framework
Note that part of the review process will be checking to make sure that your app does what it says it's doing with regard to background processing.
Here's what I've done using beginBackgroundTaskWithExpirationHandler.
Write a method that starts a background task.
Inside that background task, run a NSTimer with a scheduled (non repeating) time that is under 10 minutes. For the purposes of my situation I was using 5 minutes.
Once the NStimer's selector fires, end the background task and then instantly call the method that you wrote earlier to start off another background task.
If you want to schedule methods to run at specific times, you will have to check for them in the background task.
This solution isn't really ideal and is still power hungry but will do what you want.
Edit: Since iOS7, I suggest you read this excellent post. Note that this article was last updated in 2013 and is probably irrelevant now.
Only certain types of apps are allowed to run in the background. See the "Implementing Long-Running Background Tasks" section of this guide.
If you aren't requesting permissions to do background processing you can use UIApplication's beginBackgroundTaskWithExpirationHandler but you cannot get extra time.
This code makes your iOS app run indefinitely in the background. Copy and paste the below methods into a singleton / manager which handles the tasks you need to perform in the background.
// #interface
// Declare Private property
#property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
//#end
// ...
// Copy into
//#implementation
- (void)setupBackgrounding {
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(appBackgrounding:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(appForegrounding:)
name: UIApplicationWillEnterForegroundNotification
object: nil];
}
- (void)appBackgrounding: (NSNotification *)notification {
[self keepAlive];
}
- (void) keepAlive {
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
[self keepAlive];
}];
}
- (void)appForegrounding: (NSNotification *)notification {
if (self.backgroundTask != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
}
You can't. Unless your app uses audio, voip or gps. What you can do is notify the user (via local notifications) that the time is almost up and ask him to open/close the app.
Also if you just need to notify the user, you can use push notifications.
https://github.com/yarodevuci/backgroundTask Check my code here I am using audio player that plays blank wav file Works perfectly on IOS 8 Battery usage around 10% in 24 hour period
How to use:
var backgroundTask = BackgroundTask()
backgroundTask.startBackgroundTask() //Starts playing blank audio file. You can run NSTimer() or whatever you need and it will continue executing in the background.
backgroundTask.stopBackgroundTask() //Stops the task
Warning: Apple will reject this if you try to submit it!
If your App type is not one of VOIP/Audio/Location....(check Background Modes),
or you don't want to specify your App as a background App, you can implement beginBackgroundTaskWithName:expirationHandler or beginBackgroundTaskWithExpirationHandler to ask for more time to run your process in background. You can find the detailed description here
Apps moving to the background are expected to put themselves into a quiescent state as quickly as possible so that they can be suspended by the system. If your app is in the middle of a task and needs a little extra time to complete that task, it can call the beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: method of the UIApplication object to request some additional execution time. Calling either of these methods delays the suspension of your app temporarily, giving it a little extra time to finish its work. Upon completion of that work, your app must call the endBackgroundTask: method to let the system know that it is finished and can be suspended.
Each call to the beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: method generates a unique token to associate with the corresponding task. When your app completes a task, it must call the endBackgroundTask: method with the corresponding token to let the system know that the task is complete. Failure to call the endBackgroundTask: method for a background task will result in the termination of your app. If you provided an expiration handler when starting the task, the system calls that handler and gives you one last chance to end the task and avoid termination.

Resources