Testing push notifications on the iOS simulator

Testing push notifications in the iOS simulator make it a lot easier to add support for remote notifications. You often need to iterate a lot to verify that your code is working as expected.

Up until Xcode 11.4, we had to work with 3rd party applications like NWPusher and an actual device to test features like Rich Notifications. Although that worked quite well, it’s always nicer to iterate fast on the iOS simulator. Xcode 11.4 makes this possible with a newly added simctl command. Let’s dive in!

Enable permission to use push notifications

Before we start diving into the testing of remote push notifications it’s important to make sure you’ve got the right permissions for receiving notifications on the iOS simulator.

Otherwise, you could end up debugging to figure out why the notification is not showing up only realizing it’s caused due to missing permissions.

let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { granted, error in
    // If `granted` is `true`, you're good to go!
}

Sending a push notification to the iOS simulator from the terminal

The easiest way of testing simple push notifications is by making use of Poes. It’s a simple command-line tool that adds a wrapper around the new simctl push command.

You can install Poes using Mint:

$ mint install AvdLee/Poes

After which you can easily send a notification as follows:

$ Poes --bundle-identifier com.wetransfer.app --verbose
Generated payload:

{
  "aps" : {
    "alert" : {
      "title" : "Default title",
      "body" : "Default body"
    },
    "mutable-content" : false
  }
}

Sending push notification...
Push notification sent successfully

This takes away the hassle of creating a payload JSON file yourself and allows you to iterate fast while testing push notifications in your app.

Poes makes use of the new xcrun simctl push command and adds a small wrapper around it to generate the JSON payload based on input parameters. To fully understand what this means, I’ll explain to you how you could be testing push notifications without Poes.

Testing push notifications using the Xcode command-line tools

The Xcode command-line tools allow you to work with the simulator from the terminal. You can launch simulators, trigger universal links, and more. One of those commands allows you to send a push notification to the iOS simulator:

$ xcrun simctl push --help
Send a simulated push notification
Usage: simctl push <device> [<bundle identifier>] (<json file> | -)

	bundle identifier
	     The bundle identifier of the target application
	     If the payload file contains a 'Simulator Target Bundle' top-level key this parameter may be omitted.
	     If both are provided this argument will override the value from the payload.
	json file
	     Path to a JSON payload or '-' to read from stdin. The payload must:
	       - Contain an object at the top level.
	       - Contain an 'aps' key with valid Apple Push Notification values.
	       - Be 4096 bytes or less.

Only application remote push notifications are supported. VoIP, Complication, File Provider, and other types are not supported.

The command requires you to pass in a few arguments:

  • <device>
    Simply set this to booted to use the open simulator. You can also use a device identifier which you could get with the xcrun simctl list devices | grep Booted command.
  • <bundle identifier>
    Set this to the bundle identifier of the app you’re testing push notifications for.
  • <json file>
    This should point to a JSON file on disk containing the push notification details. You could also use stdin to provide the JSON content.

An example of execution could look as follows:

$ xcrun simctl push booted com.wetransfer.app payload.json 
Notification sent to 'com.wetransfer.app'
Testing push notifications on the iOS simulator
Testing push notifications on the iOS simulator

In this example, we’re using the following JSON saved to a payload.json file:

{
    "aps": {
        "alert": {
            "body": "Gerard added something new - take a look",
            "title": "Photos"
        }
    }
}

You can read more about the possibilities and the structure of a payload JSON on the official Apple documentation page Creating the Remote Notification Payload.

Testing push notifications using an APNS file

Another option for testing push notifications on the iOS simulator is by dragging an APNS file into the iOS simulator.

This APNS file looks almost the same as the JSON payload file but adds a Simulator Target Bundle key describing the bundle identifier to use:

{
    "Simulator Target Bundle": "com.wetransfer.app",
    "aps": {
        "alert": {
            "body": "Gerard added something new - take a look",
            "title": "Photos"
        }
    }
}

Sharing APNS files in your repository

Committing APNS files to your repository makes it easy for you and your colleagues to test common push notifications for your app. You can save a configuration for each type of notification. For example, we decided to save a configuration for the Collect by WeTransfer app to send a push notification containing an image:

{
    "Simulator Target Bundle": "com.wetransfer.app",
    "aps": {
        "alert": {
            "body": "Gerard added something new - take a look",
            "title": "Photos"
        },
        "category": "file_added",
        "mutable-content": 1
    },
    "image_url": "https://assets.website-files.com/5e1c6cdadb4d52399503394c/5e31fc43e7c7eca12dd4228d_5e1c6cdadb4d527592033a11_Hero%402x%20(1).png",
    "event_type": "file_added"
}

Every time we need to test this specific push notification we can simply drag the APNS file into the simulator. Note that we’re making use of Rich Notifications here of which the details are explained in the Rich notifications on iOS explained in Swift blog post.

Conclusion

Testing push notifications on the iOS simulator have now become a simple thing to do. There are three different ways of triggering a remote push notification:

  • Using the Poes command-line tool to easily generate the JSON payload
  • Referencing a local JSON payload file
  • Dragging an APNS file into the simulator

Poes can be really easy for quick testing while an APNS file added to your repository could make it easy to iterate on common push notifications for your app.

If you like to improve your workflow, even more, check out the workflow category page. Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback.

Thanks!