Sending and receiving mobile notifications

Notification fundamentals

When sending and/or receiving user notifications in iOS, it's important to understand that:

  1. You must request permission from the user of the device to present notifications.

  2. A user can revoke permission at any time which means your notifications will no longer be delivered.

  3. Timely delivery is not guaranteed. Notifications can be delayed for a number of reasons including (but not limited to):

    • The user's Screen Time or Sleep settings

    • The user's preferences for your app.

    • The device's available power.

  4. Remote Notifications that are pushed through a server do not work in the iOS simulator. That said, you can create remote notification packet and drag and drop it onto the simulator for testing purposes.

These are limitations of iOS itself, not Xojo.

Preparing to work with notifications

To add Notification support to your project, you need to add a NotificationCenter object to your project. Without it, trying to send and/or receive notifications will result in an UnsupportedOperationException.

Requesting authorization to send notifications

To send notifications to the user, you must request permission. This is done by calling NotificationCenter.RequestNotification.

NotificationCenter.RequestAuthorization(ParamArray options() as MobileNotifications.AuthorizationOptions)

When you do so, you tell the system the ways in which you'd like the notification to be presented to the user. The options are:

Type

Description

Badge

Adds a badge to your app icon when a notification is delivered.

Sound

Plays a sound when a notification is delivered.

Alert

Displays an alert when a notification is delivered.

CarPlay

Indicates that notifications should be displayed when received while CarPlay is in use.

CriticalAlert

Shows notifications regardless of sound and banner restrictions. This option is designed for government agencies and requires a special entitlement from Apple.

ProvidesNotificationSettings

Indicates to the system that your app provides its own notification settings view.

Provisional

Allows the app to show notifications on a provisional basis which the user can decide to accept later.

Announcement

Asks that notifications be read by Siri should the user be using their AirPods when the notification is received.

Requesting authorization will result in NotificationCenter raising either an AuthorizationSucceeded event (along with information about how the user will receive the notification based upon their notification settings) or an Error event because they have notifications turned off for your app.

Methods for sending notifications

Sending local notifications

There are two ways of sending notifications: locally and remotely.

Local notifications are those that are sent by your app.

Immediately sending a simple notification is easy. You create a NotificationContent object, give it some text and send it on its way:

Var content as New NotificationContent("Hello, world!")
NotificationCenter.Send(content)

In this case, Send is a bit of a misnomer. What Send is doing is handing off the notification content you created to the system and asking it to send it ASAP. In addition to creating notifications that are sent immediately, you can also schedule them to be sent later. In this example, the notification will be sent in 30 seconds:

Var content as new NotificationContent("Hello, world!"")
NotificationCenter.Send(30, content)

If you need to send a notification some number of years, months and days in the future, you can do so using a DateInterval. This example sends the notification 3 days from now:

Var di as New DateInterval(0, 0, 3)
NotificationCenter.Send(di, content)

If you need to send the notification on a specific date, use a DateTime object:

Var dt as New DateTime(2023, 4, 1, 0, 0, 0, Timezone.Current)
NotificationCenter.Send(dt, content)

You can also send notifications when the user arrives at or leaves a location:

// Set up some content
Var content as new NotificationContent("Hello, world!")
NotificationCenter.Send(90, 0, 300, "NorthPole", LocationNotification.Modes.NotifyOnEntry, content)

Note

iOS uses some heuristics to figure out if a user is actually entering or leaving the region and that they are not just skimming the edge, so your notification may not appear immediately.

Once notification has been successfully delivered (via the Send method) to the system, the NotificationSent event will be raised.

In all these examples, the content of the notification is very simple. Notifications can contain much more than just a single message.

Canceling local notifications

The Send method can also be called as a function in which case, it returns the ID (specifically a UUID) that uniquely identifies the notification so that you can cancel it later if it becomes irrelevant before it's actually been sent.

To cancel a notification, pass it's ID to the RemovePendingRequests method.

If the notification has already been delivered but you wish to remove it from the user's Notification Center, pass the ID to the RemoveDeliveredNotifications method.

Sending remote notifications

A remote notification is one that is sent to the device rather than sent from the device. For example, when your weather app notifies you of an extreme weather event in your area, that's a remote notification.

To send remote notifications to your app, you'll need to do the following:

  1. Apple Developer website

    • Remote Notifications will need to be added to the application's identifier.

    • You will also need an Apple Push Services certificate (which allows Apple to authenticate from whom a remote notification is being sent).

  2. Xojo

    • The Remote Notifications entitlement needs to be enabled in the Xojo iOS Build Settings on the Advanced Tab under Capabilities.

  3. A service provider for interfacing with the Apple Push Notification system (APNs). Xojo Cloud great simplifies this.

Once you have these things, sending remote notifications to your app is pretty simple. If you want to send notifications that are visible to the user like the ones above, you will still need to get the user's permission for that. In addition, your app needs to make it known that it wishes to receive remote notifications by calling:

NotificationCenter.RegisterForRemoteNotifications

This method asynchronously contacts Apple's Push Notification service (APNs) servers in order to get a globally unique identifier for your app on this particular device. If successful, the RemoteRegistrationSucceeded event will be raised and provide you with a token (a hex-encoded string) for use when you need to send a message to the device. You should immediately send this token to a server and store it with other user relevant data. This token will change if the user reinstalls your app so you should request this information every time the app is launched.

For more information about sending remote notifications see Apple's documentation on the subject.

Remote notifications are sent from a server to devices. This is typically done by using a service that specializes in sending remote notifications. You will need to:

  1. Provide them with your Apple Push Services certificate so that they can send notifications on your behalf.

  2. Learn whatever complex API they provide to send remote notifications.

  3. Budget for the cost because while they all provide some number of remote notifications for free, they charge for them once you exceed that number.

Xojo Cloud provides a simple solution to all of this. You get a Xojo Cloud server (or use the one you already have), upload your Apple Push Services certificate through your Xojo Cloud control panel, and you're ready to go. Xojo already has an easy to use remote notifications API built-in to it designed to work with Xojo Cloud servers. Unlike other services, since your Xojo Cloud server is under your control, you are always in control of your Apple Push Services certificate. This is important because if someone obtained your certificate, they could send notifications that look like they are coming from you. Finally, there's no need to wonder about the cost as a Xojo Cloud server allows for unlimited remote notifications.

Testing remote notifications

While you can't send remote notifications to the iOS simulator (Requires Xcode 11.4 or higher) for testing, you drag a remote notification packet directly into the simulator. Here's an example:

{
   "Simulator Target Bundle": "your.bundle.identifier.here",
   "aps": {
      "alert": {
         "title" : "Chicken Avocado Taco Platter", "subtitle" : "All New Flavors!",
         "body" : "Special - Today Only $4.99"
      }
   }
}

If you would like to test sending remote notifications to a physical device, we suggest using this utility: https://github.com/onmyway133/PushNotifications/releases

Receiving notifications

How your app receives a notification depends upon whether the notification is local or remote.

The NotificationReceived event is raised when your app receives a local notification while in the foreground. If you wish to deliver the notification directly to the user yourself, this is the time to do it. If you would rather have the system deliver it, you will need to return a PresentationMode value to tell the system how it should notify the user that they have received a notification.

If you're not sure, return the All value.

Return MobileNotifications.PresentationModes.All

If your app does not display the notification itself or return a value from this event, the user will never know the notification was received.

Note

Your app may be in the background when a notification is received.

Responding to the user when they acknowledge a notification

When the notification is presented to the user, the ProcessUserResponse event is raised. This is where your app can act upon the user's response to the notification. By default, your app will only know that the user tapped on the notification.

Categories allow users to respond directly to a delivered notification through buttons and text fields which can be created using a NotificationResponseCategory.

In this example, a category created and named "REPLY". A text field with a Send button and a Cancel button are then added to it. This will allow the user to enter text and then press the Send or Cancel buttons:

Var cat as New NotificationResponseCategory("REPLY")

'Create a text field with a action button caption, a hint, a send button caption and the category identifier
Var replyTextField as New NotificationResponseTextField("Reply", "Please type your reply", "Send", "REPLY")
cat.actions.Add(replyTextField)

'Add a button with the caption Cancel and the identifier
cat.actions.Add(New NotificationResponseButton("Cancel", "REPLY"))

'Add the category to the NotificationCenter so it can be used when sending notifications
NotificationCenter.AddResponseCategory(cat)

Once you have this category defined, you can use the "REPLY" category when sending local notifications.

Receiving remote notifications

When your app receives a remote notification, the BackgroundNotificationReceived event is raised.

If your application is not running when the notification is received, your app will be launched in the background and given approximately 30 seconds to retrieve whatever information it needs and must then return a value indicating if it was successful or not.

Warning

During this event, your code should spend very little time in a tight loop as it will make the user's device appear unresponsive for an unknown reason.

Other events

This event is raised if you have specified that your app has its own notifications settings and the user clicks the app's notification settings link in the system notification settings for your app.