Notifications, the whole shebang using only iOS

I should start this article with a disclaimer, it based on iOS 13, Swift 5 and Xcode 11.x. If you reading this and those numbers look dated, be forewarned.

I should also warn you that notifications, principally remote ones involve Apple’s infrastructure which means you will need an Apple Developers account to use them.

To business. You will find quite a few articles on coding notifications under Swift, although you soon discover that they’re all incomplete.

No, I kid you not. In my view incomplete, cause they’re missing a chapter explaining how post remote notifications under iOS. I have never come across a tutorial that tells how to post notifications in Swift. They all tell you to use third party utilities.

Is it a missing link or a conspiracy. No matter I am going to try and cover the whole story in this short collection of medium articles.

Ok, to boot. What are notifications. Well they come in two flavours, local and remote. Local notifications you create and post in the same app. Remote notification get created on a server or on a second iOS device and sent to the same and/or other iOS devices.

They are very special pieces in the iOS armoury. Special because they run both in the foreground and the background.

There are a number types of notifications under iOS13, although we’re only going to focus on a subset. We’re looking at local & remote alerts, badges and sounds and if I have time custom remote alerts. What they all do, we will explore in code.

Their default behaviour is also influenced by the presence of app that they’re sent to. Again let’s explore what and how they behave in code.

Local notifications although not guaranteed will almost always arrive. Remote notifications are inherently less reliable. Local notifications also have no limitations in numbers, but remote notifications do.

One aspect that they both have in common in linked to duplicates, by default they never arrive. So if you send the same notification twice, it will only show once.

Enough theory already, lets start by creating a new application. I am going to call it Noob. You should use SwiftUI too since I am going to :)

We start with permissions of course, which come in two levels. At the top you can can enable/disable all notifications. One level down you enable/disable different types of notifications.

Ok, the first thing we need to do in our code is to ask permission to use notifications. We do so with this code in the app Delegate.swift file.

func registerForNotifications() {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
// center.requestAuthorization(options: [.provisional]) { (granted, error) in
if error == nil{
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
}

A few important points that are iOS13 specific. One obvious, one not. Firstly under iOS13 you need to run the registration line on the main thread, you app will crash if you don’t.

Secondly, you may have spotted one in comments. Namely provisional. Oddly enough if ask for permission to deliver provisional notifications, nothing will popup, which won’t matter if provisional is all you want, but won’t be too useful if you want others. If you planning on using both, you will need to register them seperately.

Next create a new class, lets call it LocalNotification.swift and add this code to it.

class LocalNotifications: NSObject {
func doNotification() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
let status = settings.authorizationStatus
if status == .denied || status == .notDetermined {
DispatchQueue.main.async {
print("What the foobar, notifcation permissions ",status)
}
}
let content = UNMutableNotificationContent()
content.title = "What, where, when, how"
content.body = "No it cannot be true"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 4.0, repeats: false)
let id = "rien"
let request = UNNotificationRequest(identifier: id, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
print("error ",error)
}
}
}
}

Firstly you need to check to make sure notifications are allowed, your app will definatively fail its app review if you fail to put this code in. Assuming they are you call the code to create you notification and fire it. Now move across to the ContentView.swift and change the code so it looks like this.

import SwiftUI
let notify = LocalNotifications()
struct ContentView: View {
var body: some View {
Button(action: {
notify.doNotification()
}) {
Text("local")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

This will create an instance of our local notification method and then put in place a button so that we can fire it. If your done, run it and see what happens…

OK … Now if you leave you app in foreground, nothing will happen. At least it will seem that way. If you fire the notification and then immediately suspend it, you’ll see your notification pop up.

It’s in intential behaviour of iOS. Notifications are not intended to be things that you bring up while your app is in foreground. Ok, but wait, maybe you really want your alerts to show while your app is in the foreground. To make that happen add this code to the appDelegate.swift.

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}

Enough said, I don’t want to focus too much on local notifications since there is already quite a few very good tutorials with more detail behind these beasts online. Please read on.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store