The problem with Islam Q.'s answer is that AVAudioPlayer won't work for a notification since the app will be muted when you're not using the app. Only a UILocalNotification can let your app produce sound when it's not active. The 30 second limit is real. It should be done by repeating the notification with another 30 seconds notification. I don't know how long other VOIP applications will keep ringing but even with a traditional phone there is limit usually, something like a minute.
My strategy would be:
- Send initial notification with 29 seconds alarm that somebody tries
to contact
- Send second notification with a different 29 seconds alarm after 40 seconds that you are about to miss a call
- Send a third notification that you missed a call after 100 seconds
This would allow the user 1:40 of time to respond to a call.
Your code would look something like this:
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"FIRST_CALL", @"%@ is calling you!");
notification.soundName = @"normal_ring.mp3";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(40 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if (!phone.isRinging)
{
// Somebody picked it up already in the mean time
return;
}
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"HURRY_CALL", @"Hurry, you are about to miss a call from %@!");
notification.soundName = @"hurry_ring.mp3";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if (!phone.isRinging)
{
// Somebody picked it up already in the mean time
return;
}
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"MISSED_CALL", @"You've just missed a call from %@");
notification.soundName = @"missed_call.mp3";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
});
});
If you use the code, keep in mind you first need to make sure the app is in the background so the UILocalNotification would be the only option you have. Use a normal AVAudioPlayer when it's in the foreground, much more flexible. Second thing is that the app becomes foreground when the user responds to the call so it should mute the alert and let the AVAudioPlayer take over.
You want more or less a smooth transition between the alert and the in app sound to have a fully polished experience for your users so the best thing to do would be to measure the time between rings and let AVAudioPlayer start in exact the right time at the start of a new loop.
Your second problem is keeping the app alive in the background. This simple code will simply keep on polling the app every now and then to keep it alive. It comes straight from a working application that does just this, this code polls if a timer is still running and sleeps for five seconds when it is:
UIBackgroundTaskIdentifier backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[timerExecuted timerUpdate];
while (!timerExecuted.isStopped)
{
[NSThread sleepForTimeInterval:5];
}
[application endBackgroundTask:backgroundTask];
});