Properly fill in the Certificate Information and make sure you save the .certSigningRequest file at an easy-to-find place because then you need to upload it here:

Upload CSR file screen

Do that. Then you will get this screen:

Download .cer file screen

Download the generated Certificate, double-click the .cer file and find it it installed in your Keychain Access:

This step was a long one but worth it. Follow these steps again Certificates, IDs & Profiles -> Identifiers -> App IDs and you should see that Push Notifications are now enabled for Development:

Developer Push Notifications enabled

Step 4, some code finally: Lengthy configuration, I know, but as mentioned earlier, security is security. Time to code!

Go back to the project and open the AppDelegate.swift file. This is where we are going to ask the user for a permission to receive notifications from us before we try sending some 🦄.

On top of your AppDelegate.swift file, first:

import UserNotifications

Then within the AppDelegate class, add this function:

registerForPushNotifications function and what it does with comments.

Well, what is the code above actually doing? It is quite straightforward — we access the instance of the UserNotificationCenter, and then ask it to authorize us to send push notifications to the user in the form of alerts, sounds and badge app numbers. If granted, we call the registerForRemoteNotifications() function of the shared application instance on the main thread. We need to explicitly do it on the main thread or else, we would get the annoying error saying that we are calling the function on a background thread 😅.

Then we call registerForPushNotifications() function at the end of application(_:didFinishLaunchingWithOptions:) but before the return true statement, like this:

Calling registerForPushNotifications in the proper place.

In that way, we make sure the user is asked to register for push notifications at the start of the application. Run the project to see this:

Notification Authorization within App

The picture is quite self-explanatory, so, do press Allow, and voila, notifications will be received when sent! However, there is a pitfall to bear in mind in general — a user can always disallow push notifications authorization in the phone’s settings. We are not going to think about it now but such situation should be handled in a production app!

Ok, lets continue. There’s two more delegate functions (whose purpose is obvious I believe — one gets us the device token, the other one checks for errors if any) to implement before we see any Push Notification action:

Converting the device token or printing out an error code.

The code in the didRegister … function may seem weird at first but all it does is stringify the token for us so we can use it within the Pusher App.

Step 5, sending a notification finally: Open Pusher after installing it:

Default start-up for Pusher

There is a drop-down menu where Pusher automatically detects what Push Certificates you already have in your Keychain Access. Click it and pick the one that corresponds to your app, like this:

Example Push Certificate

Then in the next field, paste in your Device Token which you should see in the Xcode console on every start-up of your app when permission to send PNs is granted (Please note that a device token may change when you delete and re-install the app on your device). What I got for a token in my console is this:

Example Device Token

Luckily, Pusher comes with a super-simple default payload which is just a JSON dictionary with specific Apple-defined keys (no worries, they can be more than three). What do Pusher’s given JSON keys mean?

the alert key is going to display just a standart alert with a message saying “Testing ….”.

key is going to display just a standart alert with a message saying “Testing ….”. the badge key will just modify the badge of your app icon, this time to the number 1(it can be any number, indeed).

key will just modify the badge of your app icon, this time to the number 1(it can be any number, indeed). the sound key is quite obvious, the notification will just play the default sound.

All right, the app is built and running on our real device, the needed certificate is added, the device token too, lets press the Push Button in Pusher and see some magic happen:

Testing simple notification

Yey, it works. Not very impressive because of no unicorns present. Eh, we will get there! (If you want to know what a notification payload can carry, read here and here.)

Adding media attachments

Well, well, we made it to actually sending a notification with some alert in it. Not bad but surely, most of us have received more sophisticated notifications (pictures, gifs, etc.), right? So, how to do that? I have two words for you — Service Extension. A Service Extension intercepts push payloads from apps, and gives you the chance to change content in the notification before it is presented.

As it is written on the Apple website:

App extensions give users access to your app’s functionality and content throughout iOS and macOS.

And that is what the Service Extension will do for us and our notifications — it will help us give users notifications with fancier appearance 🎊.

Enough jibber-jabber and more work! In Xcode, go to File->New->Target… like this:

File->New->Target… selection

Then in the next menu, under iOS, Filter “service” and choose Notification Service Extension like so:

Filtering Notification Service Extension

Click the Next Button and give it a name of your choosing. I am going to name mine NotificationService. Click Finish. What we are going to get is a new group of two files created for us:

Notification Service file group

Go ahead and open the NotificationService.swift file. Do take the time to checkout the code written for us by Xcode. The didReceive(_:withContentHandler:) function is the one that is the more important because that is where we can modify the notification to our liking.

Before that, we need to go to our payload aps dictionary and make sure we add this key-value pair if we actually want to use a notification extension of any kind:

“mutable-content”:1

It signifies that the OS should initiate the service extension of the app and do some extra processing.

The other thing that I will add to the payload now is an example unicorn image URL. I will imagine that someone took a picture of a unicorn and uploaded it to the server and that is why I, as a user, am getting notified. This is the final payload:

Now it is time to go back to the NotificationService.swift file and switch it up a bit. Apple team did provide some code ready for us but I would like to change it so that it handles the transformation of just a URL to an image attachment properly. For that I will need from this particular function (comments added on the side so it makes sense a bit more):

A helper function to download an image from the internet using a url and return it as a notification attachment.

Well, we do have the function that will do the magic for us. Well, let’s use it in the didReceive(_:withContentHandler:) method. This is what it should look like:

Implementing the download function within the didReceive method and attaching the downloaded image.

All these steps may seem magical at first so do take the time to make sure you understand them — all they do is just dig into the aps dictionary to extract the values. Then indeed, do test it to see a cool unicorn image show up in the notification 😏 🦄, like below:

Testing notification with image.

Adding custom actions

Well, good job till now I would say. Still, we want to make things even more fancier, like adding some custom actions? What I have in mind are a Like and a Save actions — for liking a picture and for saving a picture respectively.

Ok, go back to the NotificationService.swift file and between // 4. and // 5, add a // 6. like this:

Adding actions.

All that is done here is creating the two actions wanted and adding them under a common category(“unicorning”, so original!). That same common category will go in the aps Notification payload we send from Pusher. And that is how the Notification Service would know what notification actions to show! Simple, right?

Alright, try it out! If you do, you will see that when you use the force touch or pull down to see the bigger notification, you will see the custom actions show up there too, like this:

Testing notification with actions.

To be honest, we are not ready yet, because if you think about it, we are not handling these custom actions anywhere. The place to do that is in the AppDelegate.swift file. Just add this optional func before closing the AppDelegate class:

func userNotificationCenter(_ center: UNUserNotificationCenter , didReceive response: UNNotificationResponse , withCompletionHandler completionHandler: @escaping () -> Void )

What it does is intercept the notification response for us. Within the response, we can check whether the user chose any of the custom actions provided and proceed with app logics based on that. The way I handled the actions, for demo purposes only, is just by printing out statements on the console, like so:

Code for demo handling of custom actions

Go ahead, test it out and see some not so fancy prints showing up on the console and the concept I am explaining proven! Indeed, in a real app, you would want to have some real and thoughtful logics happen when a user chooses your custom actions.

Printing on the console.

Conclusion

After so much work done, probably it is best to go for a short conclusion, right? That is, I hope I not only helped you familiarize yourselves with APNs but also got you to put “Digging deeper in the APNs and playing with some ideas” topic on your bucket list! Because trust me, there is so much more to it 😃.