Push notifications

= Push Notifications =

Push notifications on iOS

 * Some overview about push/background modes (starting at slide 5): https://xmpp-meetup.in-berlin.de/talks/monal-and-push.pdf
 * VoIP pushes: MUST always make the device ring via CallKit
 * Low priority pushes: can prevent display, but Apple may drop or arbitrarily delay them
 * High priority pushes: MUST show a notification unless being a chat app. Chat apps are granted an extra entitlement by Apple to suppress the notification.
 * citing the apple introduction on the "com.apple.developer.usernotifications.filtering" entitlement application page:
 * "This entitlement is intended for certain types of apps — such as messaging apps or location sharing apps — that use notification service extensions to receive push notifications without delivering notifications to the user."
 * https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_usernotifications_filtering?language=objc
 * Other popular messenger apps use this entitlement, too
 * Using this entitlement apps can even fetch/decrypt incoming call information and trigger a local "voip push"
 * Apple documentation: https://developer.apple.com/documentation/callkit/cxprovider/3727263-reportnewincomingvoippushpayload?language=objc
 * example in Monal: https://github.com/monal-im/Monal/blob/develop/Monal/NotificationService/NotificationService.m#L175
 * example in Signal: https://github.com/signalapp/Signal-iOS/blob/main/SignalNSE/NSECallMessageHandler.swift#L129

Some words about push server implementations and iOS time limits
Contributed by: Thilo Molitor

Pushes of all types (see above) can only wake up the iOS app for 30 seconds. In most cases that's more than enough to connect to the xmpp server and retrieve pending stanzas (if using the entitlement mentioned above and XEP-0198, it is even possible to get pushes for iq stanzas etc., thus being virtually permanently connected while still sleeping most of the time because of CSI). Even if the 30 seconds don't suffice, the client can disconnect and both, Prosody and eJabberd, will send another push if there are still unacked stanzas in the XEP-0198 queue. This will give the app another 30 seconds. Even longer catchups lasting for 5 minutes can be done completely in the background this way. I (the Monal author) observed this myself in a real world example using the push 1.0 infrastructure (e.g. only XEP-0357) and Monal.

Transporting (encrypted) xmpp message stanzas through push
Contributed by: Thilo Molitor

When using the iOS push infrastructure provided by apple for transporting (encrypted) stanzas out of band, multiple thing have to be considered. First of all, pushes can get lost. That frequently happens if the device was in flight mode while the push was sent. Second, xmpp is a streaming protocol, strongly relying on the ordering of stanza (even inter-type ordering like the ordering of message and iq stanzas for mam). The order of message stanza matters for other XEPs, too (for example message retraction or last message correction). Using the iOS push service which is loosing pushes or even only sending pushes for a particular type of stanza (message stanzas having a body for example) breaks this ordering of events that every XEP implicitly relies upon. The payload sizes allowed for each push are also somewhat low (~4kb including some of the push metadata). OMEMO's self-healing through key-transport-elements requires the client to send those key-transport message stanzas once a broken session gets detected. But using the push service for data transport is a one way channel only.

Last but not least the UX can be really degraded if a user does not open the app for some hours (while still receiving push notifications). Once they open the app, a long mam catchup has to be waited for until the ui does reflect what the user already saw in notifications. If the device has no connectivity when the user opens it, they might even be really confused why those messages they alread saw a notification for are not displayed in the app at all). Writing incoming messages to the database to solve this will only make the reordering problem depicted above harder. The client not being able to execute the OMEMO self-healing stuff mentioned above, will degrade UX, further.

NOT using the entitlement mentioned above will not allow the client to receive push notifications for XEP-0333 read markers and remove already displayed notifications instead of posting a new one (because apps not having that entitlement are forced to show a notification for each incoming high priority push, even if the push was only for a XEP-0333 read marker). To be clear: without that entitlement neither last message correction, nor message retraction or XEP-0333 read markers can be implemented! And if an app has the entitlement: why bother delivering some stanzas out of band and running into the ordering problem if the app could as well connect to the xmpp server in the background and retrieve all pending stanzas in the right order?