0

I have my Watch app reacting to receiving localNotifications in my extension delegate's

- (void)didReceiveLocalNotification:(UILocalNotification *)notification

as follows

WKAlertAction *okAction = [WKAlertAction actionWithTitle:@"OK" style:WKAlertActionStyleCancel handler:^(void) {
DbgLog(@"Dismissed notification alert ");
}];

NSArray *alertActions = @[okAction];

assert(extension.rootInterfaceController);
[extension.rootInterfaceController presentAlertControllerWithTitle:notification.alertTitle message:notification.alertBody preferredStyle:WKAlertControllerStyleAlert actions:alertActions];

Which works. Local notifications firing from my app appear on my watch as the alert if the watch app is in focus, just like how they do on the iPhone if the iPhone app is in focus. Falling back to the system notification handling if the watch app isn't in focus or its screen is not currently powered up.

The problem is that these local notifications can appear in relatively quick succession. When they do this, the same code is called and nothing is presented.. You cannot present another alert controller on top of the current one, not saying i want to but I don't think you can dismiss the current alert to then be able to present the new one.

On iOS there were similar problems but you could get round them by using the right view controller to present the new one using something like this

- (UIViewController *)myVisibleViewController
{
  if ([self isKindOfClass:[UINavigationController class]])
  {
     return [[(UINavigationController*)self topViewController] myVisibleViewController];
  }

  if ([self isKindOfClass:[UITabBarController class]])
  {
     return [[(UITabBarController *)self selectedViewController] myVisibleViewController];
  }

  if (self.presentedViewController == nil || self.presentedViewController.isBeingDismissed)
  {
    return self;
  }

  return [self.presentedViewController myVisibleViewController];
}

WatchOS however doesn't seem to offer such abilities. Meaning my app cannot really handle notifications as well as i'd like. If anything I'd prefer to just always have the system handle the notifications the way it does when the app's not in focus or if the watch screen is off. But I don't think there's a way you can get this behaviour whilst your app is in focus.

To be honest even the system notifications I find a little flaky if a lot of notifications arrive at once, i don't think the system handles it very well at all and its often the reason that I'll miss some notifications hidden behind others and not properly being shown to the user, something i hope Apple fixes in subsequent WatchOS versions.

Anyone got any ideas, or is it just impossible to have a WatchOS 2 app handle notifications that overlap in presentation timing?

Cheers!

jimbobuk
  • 1,211
  • 12
  • 25

2 Answers2

1

Not sure this will help with the 'overlapping' part - but you appear be mixing up two distinct 'features' here - Local Notifications and WKAlertControllers.

The WKAlertController is used to pop an alert window to the user whilst your app is active (i.e. on the watch screen). You give it a title, message, buttons, etc.

Local (and Remote) Notifications are different. They fire from the phone, which decides which device you are using currently, and presents an alert to that device. If it is the watch, then the Notification Interface ("Short Look" - not customisable) is used to present the notification message. This is then followed by the "Long Look" interface (which you can customise). You don't set the watch up for listening out for Local/Remote Notifications - it is there by default if you enable them when creating your project (or adding the capability later). If you want to create a Local Notification from the Watch, you send it to the phone in a message via WCSession, and the phone handles it from there.

Be aware - the Notification will show on the watch if you are using it, but not if your actual app is active (on screen). This is the same on the phone - you might set Alerts if your app is active, and/or Local Notifications for when your app is in the background. (But with the phone, you can listen to that Local Notification inside your app and fire an Alert if it happens, too.)

In summary - you cannot call a WKAlertController using a Local (or Remote) Notification. EDIT - actually yes you can!

Hopefully this helps. Not sure the overlapping alerts is caused by any of this, but maybe!

travelnsam
  • 193
  • 9
  • Thanks for your answer. Perhaps my rambling has confused the issue a little. My app is running mainly on my iPhone, the watch is just a window into what is occurring back on the phone. Whilst my app is running on the phone it generates local notifications from time to time, sometimes they occur in quick succession. On the watch I'm trying to do what you describe and make the user aware of the notification. As you said whilst it's running the system notification handling isn't done your app is just notified. In this notification handling I present alerts. – jimbobuk Jan 11 '16 at 09:05
  • If two notifications arrive at similar times then when trying to display an alert for the second notification it just fails, leaving the user unaware that the 2nd notification has arrived. I don't see a solution due to this inability to cascade alerts like you can in iOS – jimbobuk Jan 11 '16 at 09:06
  • I've noticed the documentation says only one alert can be presented at any time, if a second alert is presented the first should be dismissed to make way. This doesn't seem to happen so maybe I will log a radar about it – jimbobuk Jan 11 '16 at 13:21
1

(Adding as another answer because too long for Comment!)

OK after re-reading your post a few times, and doing some digging myself, I think I understand better. And I also learned something. You CAN kick off an Alert from a Notification whilst the app is active, same as on the phone! So thank you.

Now that I understand your problem better, I tried it out and see what you mean about stacking multiple Alert controllers. Subsequent alerts simply replace any that are already on screen. according to Apple’s docs:

Only one action or alert sheet may be visible at a time. If you call this method and a sheet is already visible, this method dismisses the previous sheet before displaying the new one.

My testing appeared to show subsequent alerts were simply ignored, rather than replacing them, but there you go. This sounds like what you are experiencing also?

I am assuming you want the user to press OK (or Cancel) and dismiss each Alert, so they are able to action each one in turn? One potential workaround I can think of (but have not tried): Perhaps you can create a queue of alerts and utilise the fact that, upon dismissal of the modal alert controller, the underlying Interface Controller’s willActivate is called and check if there are more alerts in the queue. So it could work something like this:

1.) When your didReceiveLocalNotification in the Extension Delegate picks up a Notification, it checks an array (let’s say alertQueue) for alerts. If the array is empty, it adds the details of the new alert, then calls the Alert. If the array is not empty, it simply adds details for this message to the array, but doesn’t call the Alert.

2.) In willActivate check alertQueue for any entries. If there are any, display the alert and remove that one from the array. When the Alert is dismissed by the user, willActivate will be run again, if new entries have been added by didReceiveLocalNotification in the meantime it can move through them all until the array is empty again.

Maybe not elegant or fully thought through, and as I said I haven’t tried this myself, but it seems (in my head!) that it is a possible start point for you?

travelnsam
  • 193
  • 9
  • Thanks for your answer again. I would prefer that they'd stack the alerts which your suggestion may allow for, I wasn't aware of willActivate being called after alerts are finished with. May look at this. The default behaviour of replacing is ok but stacked is perhaps better. Clearly there is a bug there for Apple to fix. I struggled testing this on simulator this morning as even with the phone simulator locked it seemed to awake to notify rather than the notification appearing on the watch simulator.The 2nd notification did arrive on the watch but it made testing this stuff difficult. Cheers! – jimbobuk Jan 11 '16 at 16:47
  • I think they limit this to control resource usage i.e. if a whole series of alerts arrived one after the other that is a lot of Interface Controllers for the watch to handle (and present on top of each other), and the minimal resources of the Watch could get swamped very quickly. – travelnsam Jan 11 '16 at 17:25
  • I tend to leave the Notification delivery in the lap of the (Apple) gods. You can't control where the phone decides to send it - for me, so long as a Notification appears *somewhere*, then I consider that successful and move on. One thing to remember with using Notifications to trigger in-app alerts in the way you are - under Watch OS2 the phone may not be in comms with the watch, so may not be able to send the Notification to it. If your app is designed to run independantly on the Watch, you may be better off handling in-app Alerts exclusively on the Watch. – travelnsam Jan 11 '16 at 17:29
  • It's just a window to the phone state really so it's fine if it fails when out of contact with the phone. Thanks for your help, I'll accept the answer after trying it! – jimbobuk Jan 11 '16 at 18:17