0

I have an app where I need to send a UILocationNotification when the app is not in the foreground / Active. If I have my code to do so, it will not send until the app is opened and is active.

Here is my function:

- (void)setLocalNotificationForType:(SPKLocalNotificationType)notificationType fromUser:(NSString *)userName withMessageText:(NSString *)msgText {

    UILocalNotification *notif = [[UILocalNotification alloc] init];
    notif.userInfo = @{@"handle": _convoHandle, @"room": _convoName};
    notif.fireDate = [NSDate date];
    notif.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
    notif.soundName = UILocalNotificationDefaultSoundName;
    notif.timeZone = [NSTimeZone defaultTimeZone];

    if (notificationType == 1) { // message
        notif.alertBody = [NSString stringWithFormat:@"@%@ said: \"%@\"", userName, msgText];
    } else if (notificationType == 2) { // image
        notif.alertBody = [NSString stringWithFormat:@"@%@ sent an image", userName];
    } else {
        return;
    }

    if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
        [[UIApplication sharedApplication] presentLocalNotificationNow:notif];
    }
}

Update: It now seems that the problem is that the connection to the server is being "paused" while the app is in the background. Once I then open the app all the data comes in at once. I am using SocketRocket for connecting to my Node.js Primus web socket server. Is this something that normally happens? This is my first time using SocketRocket so I'm not sure.

Update: I have also enabled Remote Notifications for Background Modes, I have also registered for remote notifications, and on the device, I have also made sure that "banners" and "badges" are enabled.

Update: I have additionally set the web socket to use a background queue.

[webSocket setDelegateOperationQueue:[NSOperationQueue new]];

The connection is still being paused.

Thanks!

Jason Silberman
  • 2,471
  • 6
  • 29
  • 47
  • Does your app support some kind of background modes? – AntonijoDev Mar 05 '14 at 08:54
  • "App registers for location updates" for example – AntonijoDev Mar 05 '14 at 09:01
  • @AntonijoDev no, but it should keep the web socket connection, it will still log content within 10 mins – Jason Silberman Mar 05 '14 at 15:52
  • You need to enable the background mode for remote notifications, even if you're only using local notifications. – nekno Mar 06 '14 at 00:15
  • You are not guaranteed any specific amount of time to run when entering the bg. In iOS 7, there are background modes that give you 30s to execute your code in the bg, e.g., Remote Notifications or Background Fetch, or you can use the Background Transfer Service. Are you sure your code is running when the app enters the bg? What calls your method when in the bg? If you set a breakpoint inside the method, and place your app in the bg, does your breakpoint get hit? It would help us help you if you respond with some comments to the answers below. – nekno Mar 08 '14 at 10:17
  • @nekno the breakpoint does not get hit until the app is opened. I have also update the post to show more information. – Jason Silberman Mar 08 '14 at 20:13
  • I updated my answer to see if you've tried moving the work to a bg operation queue. Again, without using one of the available background modes, there's no guarantee for how long you get to run, or that you get to run at all. – nekno Mar 09 '14 at 10:47

2 Answers2

2

Edit: It looks like SocketRocket uses the main dispatch queue by default, which runs on the application's main thread. When the app is backgrounded, processing on the main thread stops, so it would be worth trying to move the work to a background thread in a background operation queue.

On your SRWebSocket object, try calling:

[webSocket setDelegateOperationQueue:[NSOperationQueue new]];


Without checking the docs, perhaps setting timeZone and fireDate on the UILocalNotification is interfering. You don't need those if you're going to pass the notification to presentLocalNotificationNow:.

I have also found that, even if you're using local notifications exclusively, you must:

  1. Enable Remote notifications for your target on the Capabilities tab under Background Modes
  2. Enable either alerts or banners in the Settings app, in Notification Center settings.

A sample event handler for a background fetch:

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    UIBackgroundFetchResult result = UIBackgroundFetchResultNoData;
    // ... perform a network request
    if (successfulNetworkRequest) {
        UILocalNotification* localNotification = [UILocalNotification new];

        localNotification.alertAction = @"View";
        localNotification.alertBody = @"Stuff";

        localNotification.soundName = UILocalNotificationDefaultSoundName;
        localNotification.applicationIconBadgeNumber = 1;

        localNotification.userInfo = @{@"stuff": @"other stuff"};

        [application presentLocalNotificationNow:localNotification];

        result = UIBackgroundFetchResultNewData;
    } else {
        result = UIBackgroundFetchResultFailed;
    }

    completionHandler(result);
}
nekno
  • 19,177
  • 5
  • 42
  • 47
  • How can I trigger this background fetch? It seems that the SRWebSocket connection is still being paused when I enter the background. I've but it on another NSOperationQueue. – Jason Silberman Mar 09 '14 at 19:44
0

I am afraid you are misunderstanding of local notification. I guess what you should do is registering a notification in the future and send it some time after user clicked the home button. But in your code, you registered a alert in CURRENT TIME and did some thing on the notification (sorry but I don't know what you want to do in your code).

You could change it like this to make a sense:

- (void)setLocalNotificationForType:(SPKLocalNotificationType)notificationType fromUser:(NSString *)userName withMessageText:(NSString *)msgText {

    UILocalNotification *notif = [[UILocalNotification alloc] init];
    notif.userInfo = @{@"handle": _convoHandle, @"room": _convoName};

    //Set the fire time 10 seconds later
    notif.fireDate = [[NSDate date] dateByAddingTimeInterval:10];

    notif.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
    notif.soundName = UILocalNotificationDefaultSoundName;
    notif.timeZone = [NSTimeZone defaultTimeZone];

    if (notificationType == 1) { // message
        notif.alertBody = [NSString stringWithFormat:@"@%@ said: \"%@\"", userName, msgText];
    } else if (notificationType == 2) { // image
        notif.alertBody = [NSString stringWithFormat:@"@%@ sent an image", userName];
    } else {
        return;
    }

    //Register this notification
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}

And in your app delegate's -applicationDidEnterBackground:, call your -setLocalNotificationForType:fromUser:withMessageText: method to make and register a notification. Then you can expect a local notification 10s after you click the home button.

onevcat
  • 4,591
  • 1
  • 25
  • 31