From d5dff4c452b125d294f688721d1b96cced8ec7e8 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 28 Jan 2014 17:17:22 +0100 Subject: [PATCH] Implement silent push support, with special string sent to the register server "IC_SIL". Only works on iOS 7. --- Classes/LinphoneAppDelegate.m | 33 ++++++++++++++++++++++++++++--- Classes/LinphoneManager.h | 3 ++- Classes/LinphoneManager.m | 37 +++++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 5bd94532f..f42b55f08 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -60,6 +60,10 @@ - (void)applicationDidEnterBackground:(UIApplication *)application{ [LinphoneLogger logc:LinphoneLoggerLog format:"applicationDidEnterBackground"]; +#ifdef DEBUG_PUSH + // simulate a lost socket when going in background + linphone_core_set_network_reachable([LinphoneManager getLc], FALSE); +#endif if(![LinphoneManager isLcReady]) return; [[LinphoneManager instance] enterBackgroundMode]; } @@ -91,15 +95,19 @@ - (void)applicationDidBecomeActive:(UIApplication *)application { [LinphoneLogger logc:LinphoneLoggerLog format:"applicationDidBecomeActive"]; + [self startApplication]; LinphoneManager* instance = [LinphoneManager instance]; [instance becomeActive]; - +#ifdef DEBUG_PUSH + linphone_core_set_network_reachable([LinphoneManager getLc], FALSE); +#endif + LinphoneCore* lc = [LinphoneManager getLc]; LinphoneCall* call = linphone_core_get_current_call(lc); - + if (call){ if (call == instance->currentCallContextBeforeGoingBackground.call) { const LinphoneCallParams* params = linphone_call_get_current_params(call); @@ -121,7 +129,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound |UIRemoteNotificationTypeBadge]; + [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeNewsstandContentAvailability]; //work around until we can access lpconfig without linphonecore NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys: @@ -257,6 +265,25 @@ } } +// this method is implemented for iOS7. It is invoked when receiving a push notification for a call and it has "content-available" in the aps section. +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler +{ + LinphoneManager* lm = [LinphoneManager instance]; + [LinphoneLogger log:LinphoneLoggerLog format:@"Silent PushNotification: Receive %@", userInfo]; + + // save the completion handler for later execution. + // 2 outcomes: + // - if a new call/message is received, the completion handler will be called with "NEWDATA" + // - if nothing happens for 15 seconds, the completion handler will be called with "NODATA" + lm.silentPushCompletion = completionHandler; + [NSTimer scheduledTimerWithTimeInterval:15.0 target:lm selector:@selector(silentPushFailed:) userInfo:nil repeats:FALSE]; + + // Force Linphone to drop the current socket, this will trigger a refresh registers + linphone_core_set_network_reachable([LinphoneManager getLc], FALSE); + linphone_core_set_network_reachable([LinphoneManager getLc], TRUE); + [lm refreshRegisters]; +} + #pragma mark - PushNotification Functions diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 3a3fe4657..bbab62112 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -155,7 +155,7 @@ typedef struct _LinphoneManagerSounds { - (BOOL)lpConfigBoolForKey:(NSString*)key; - (void)lpConfigSetBool:(BOOL)value forKey:(NSString*)key forSection:(NSString*)section; - (BOOL)lpConfigBoolForKey:(NSString*)key forSection:(NSString*)section; - +- (void)silentPushFailed:(NSTimer*)timer; @property (readonly) FastAddressBook* fastAddressBook; @property Connectivity connectivity; @@ -172,6 +172,7 @@ typedef struct _LinphoneManagerSounds { @property (readonly) ALAssetsLibrary *photoLibrary; @property (readonly) NSString* contactSipField; @property (readonly,copy) NSString* contactFilter; +@property (copy) void (^silentPushCompletion)(UIBackgroundFetchResult); @end diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 4bfa8c2cc..23571eff6 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -109,6 +109,7 @@ extern void libmsbcg729_init(); @synthesize bluetoothAvailable; @synthesize bluetoothEnabled; @synthesize photoLibrary; +@synthesize silentPushCompletion; struct codec_name_pref_table{ const char *name; @@ -408,7 +409,16 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char data = [[LinphoneCallAppData alloc] init]; linphone_call_set_user_pointer(call, data); } - + + if (silentPushCompletion) { + + // we were woken up by a silent push. Call the completion handler with NEWDATA + // so that the push is notified to the user + NSLog(@"onCall - handler %p", silentPushCompletion); + silentPushCompletion(UIBackgroundFetchResultNewData); + silentPushCompletion = nil; + } + const LinphoneAddress *addr = linphone_call_get_remote_address(call); NSString* address = nil; if(addr != NULL) { @@ -587,6 +597,15 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo char *fromStr = linphone_address_as_string_uri_only(linphone_chat_message_get_from(msg)); if(fromStr == NULL) return; + + if (silentPushCompletion) { + + // we were woken up by a silent push. Call the completion handler with NEWDATA + // so that the push is notified to the user + NSLog(@"onMessageReceived - handler %p", silentPushCompletion); + silentPushCompletion(UIBackgroundFetchResultNewData); + silentPushCompletion = nil; + } // Save message in database ChatModel *chat = [[ChatModel alloc] init]; @@ -1384,7 +1403,13 @@ static void audioRouteChangeListenerCallback ( #else #define APPMODE_SUFFIX @"prod" #endif - NSString *params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IM_MSG;pn-call-str=IC_MSG;pn-call-snd=ring.caf;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString]; + NSString *params; + if( [[[UIDevice currentDevice] systemVersion] doubleValue] >= 7 ){ /// use silent push for ios7 devices + params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IC_SIL;pn-call-str=IC_SIL;pn-call-snd=empty;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString]; + } else { + params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IM_MSG;pn-call-str=IC_MSG;pn-call-snd=ring.caf;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString]; + } + linphone_proxy_config_set_contact_uri_parameters(proxyCfg, [params UTF8String]); linphone_proxy_config_set_contact_parameters(proxyCfg, NULL); } @@ -1492,6 +1517,14 @@ static void audioRouteChangeListenerCallback ( - (BOOL)lpConfigBoolForKey:(NSString*)key forSection:(NSString *)section { return [self lpConfigIntForKey:key forSection:section] == 1; } +- (void)silentPushFailed:(NSTimer*)timer +{ + NSLog(@"silentPush failed, silentPushCompletion block: %p", silentPushCompletion); + if( silentPushCompletion ){ + silentPushCompletion(UIBackgroundFetchResultNoData); + silentPushCompletion = nil; + } +} #pragma GSM management -(void) removeCTCallCenterCb {