My application is primarily a client for a server that really doesn't have a connection to the internet. It connects to a Polycom codec and manages the video calls between 2 endpoints. So my application can send commands like end call, volume up, etc...
However my problem is this. I need some kind of notification when an incoming call happens and the application is not in the foreground.
Since the server does not have internet access APNS/push notifications will not work for me. I have looked into doing something like this. Which does seem to keep my client running however I cannot do an alert since my application is in the background.
So besides the basics of how to fix my problem my questions are:
Can I bring my application to the foreground using the technique listed in the link (doing something like what I'm doing below). I can see from the logs that this code keeps my code running. I know my while loop is not right and in the end I would need KVO but regardless that shouldn't effect the answer. (one thing I dont understand is this keeps my whole application running as opposed to just the class I have in there bcClient?)
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[bcClient connect];
bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while(1) {
sleep(3);
NSLog(@"held join %d",bcClient.heldjoin);
if (bcClient.heldjoin == 602 || bcClient.heldjoin == 604 || bcClient.heldjoin == 513) {
NSLog(@"incoming call");
}
}
});
}
If I cannot bring my application to the foreground then is there anyways to push a notification locally (without the need for a APNS server)?
I have a feeling none of this is possible but I figured I would ask.
Here is my answer. This keeps my client application running in the background and shows a notification when a call comes in.
AppDelegate.h
@interface CameleonAppDelegate : NSObject <UIApplicationDelegate> {
CrestronClient *cClient;
CrestronControllerValues *CCV;
RootViewController *rootViewController;
CrestronValues *crestronValues;
UIBackgroundTaskIdentifier bgTask;
dispatch_block_t expirationHandler;
UIApplication* app;
BOOL showedCall;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
-(void)save;
-(void)load;
- (void)backgroundHandler;
@end
AppDelegate.m (just didFinishLaunchingWithOptions
and applicationDidEnterBackground
)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
app = [UIApplication sharedApplication];
expirationHandler = ^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
};
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *keys = [NSArray arrayWithObjects:@"IPaddress", @"PortNumber",@"IPID", nil];
NSArray *objs = [NSArray arrayWithObjects:@"10.8.40.64", @"41794",@"3", nil];
//10.8.30.143 10.8.40.64
NSDictionary *dict = [NSDictionary dictionaryWithObjects:objs forKeys:keys];
[defaults registerDefaults:dict];
CCV = [CrestronControllerValues sharedManager];
[CCV setIpAddress:[defaults stringForKey:@"IPaddress"]];
[CCV setPortNumber:[defaults stringForKey:@"PortNumber"]];
[CCV setIPID:[defaults stringForKey:@"IPID"]];
cClient = [CrestronClient sharedManager];
rootViewController = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
showedCall = FALSE;
BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
{
NSLog(@"VOIP backgrounding accepted");
}
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
sleep(4);
//NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
if ([rootViewController isIncomingCall] && showedCall != TRUE) {
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif) {
localNotif.alertBody = [NSString stringWithFormat:@"Incoming Call."];
localNotif.alertAction = NSLocalizedString(@"Accept Call", nil);
localNotif.soundName = @"alarmsound.caf";
localNotif.applicationIconBadgeNumber = 1;
[application presentLocalNotificationNow:localNotif];
[localNotif release];
}
showedCall = TRUE;
}
}
});
}
- (void)backgroundHandler {
NSLog(@"### -->VOIP backgrounding callback");
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
[rootViewController isIncomingCall];
sleep(1);
}
});
}