I want to add push notifications to an chat application I am working on.

Initially I thought that I should write business logic to detect that a message wasn't delivered and then attempt to send the notification for the unread message. If a user's online presence is detected, I can skip the push notification call.

However, after doing some research, I discovered this answer from a support engineer at PubNub.

The answer states that they don't really care whether the subscription is active, they just send GCM/APNS requests for all messages.

The publisher does not know or care whether subscribers are active (foreground) or inactive (background or not running at all - kill state) on the device. Publisher always publishes the message with a GCM (and possibly APNS) payload.

Active apps will receive both and will prevent the display of the push notification via the OS's push msg receiver listener.

Inactive apps will receive only the push notification and display that. When end user taps the push msg, it will open the app where you can get the missed message and display the full content in your app's UI.

If I understand correctly, this would display a notification if the app is in the background and trigger a method (didReceiveRemoteNotification iOS, ??? Android) if the app is open. I could then choose to display a local notification depending on my own logic.

Is this good design or do chat applications generally make more effort to detect if a message was delivered before falling back to push notifications?

If user is connected to chat server, chat library will receive message on handler and app itself can generate required notification in this case.

You can send push notification using Amazon SNS service or can also integrate GCM and APNS.

Design wise Notification Queue makes chat and push notification asynchronous. So it is easy to pick notification and send using Notification service. There could be other ways to do this but better not to put conditions/processing in flow of chat message. It will introduce extra delay in message delivery.

You can send a notification foe each but as far as I know iOS only has the ability to do a custom trigger if the app is open. So you may want to look into tracking a user a different way.

You can also track if a user is active through a couple different ways.

One way would be on foreground and background events. If a user opens the app or returns to it a call is made to let the server know the user is active and does not need to send a push. When the user backgrounds the app then there can be a call made to let your server know the user is away and should send push notifications.

Depending on how your server and app connect to each other the server can track if a user is active based on an active connection or the length of time from the last request. (The app may need to make periodic calls to the server when in the foreground which can increase your server load just to let it know that you are active.)

I know that in the past an app that I have worked on has used a foreground/background call to let the server know if a user was currently active (but it was not for a chat specific app)

Actually it is possible to send a silent push note to an iOS app even when the app is not running. You can include some metadata with the silent push to let the app construct the visible local notification.
– RibaldEddieJul 18 '17 at 20:59

It's hard to say what others do, but what should you do depends (as usual) on your requirements.

What are you notifying? New incoming messages or pending messages to be read?

If the first, you have no choice, you have to send the notification with every incoming message and delegate to the client the notification handling and how to proceed according to its state (in the background, foreground, off, etc). So basically no control on the acknowledgement is required. If your chat is WebSocket-based, instead of push notifications, you could simulate this behaviour with specific events.

Each platform (iOS and Android) handles push notifications in different ways. For example, on iOS the system (not the app) is who handles the notification and pass it to the app after tapping on the screen. Android is quite different. It could be handled by the system or by the app (but not for both at the same time) depending on the notification format and the app state.

In any case, is the client who decides what to do with the notification. Otherwise the server-side should be aware of every single state of every single client and act accordingly. The hell on earth. Imagine applications at the scale of WhatsApp. With enough resources, It should be possible, but I assume that it would be absurdly expensive in many senses.

It's the least cost effective too. GCM (or Firebase CM) are free to a point. I'm not sure about APNS. We started to work with Firebase as cloud notification provider recently, so we don't have to care too much about APNS.

Sending push notifications per chat message also concerns the client-side. Handling push notifications have a cost in terms of resources.

If you want to notify pending messages to be read, the solution is simpler and cheaper than the previous one.

I will assume that you have a chat server. The chat server knows the state of the messages. Delivered means it was pushed to the client. Received means the client acknowledges receipt (or it requested the room activity).

Notifying pending messages is about tracking the transition from delivered to received. For instance, our chat server set a timeout after a new message is delivered. By the time the timeout ends, if the server didn't get acknowledgement, it sends the notification. Otherwise, we abort the process. We repeat this process with every new incoming message.

This way, we only send push notifications in very specific situations, cutting-down costs and saving resources on both client and server side.