4.
Xcode Project Setup
Written by Scott Grosch
Before you start sending and receiving push notifications, you first need to make sure your project is set up to do so!
Open Xcode and create a new iOS App project. Select SwiftUI as the Interface and SwiftUI App for the Life Cycle. You may leave the checkmarks at the bottom of the project creation screen unchecked, as you won’t need Core Data or any tests in your project. In the Bad Ol’ Days, this is the point in which you’d have to set up a custom profile with Apple to enable push notifications. Fortunately, with the current toolchains, this is all automated now.
Adding capabilities
To tell Xcode that you’ll be using push notifications in this project, just follow these four simple steps so that it can handle the registration for you:
- Press ⌘ + 1 (or View ▸ Navigators ▸ Project) to open the Project Navigator and click on the top-most item (i.e. your project).
- Select the target, not the project.
- Open the Signing & Capabilities tab.
- Click the + Capability button.
- Search for and select Push Notifications from the menu that pops up. If you don’t see the Push Notifications capability, you’re not using a paid Apple Developer account. Double-check that you selected the correct Team and check that you have a valid Provisioning Profile for your team and bundle ID.
- Notice the Push Notifications capability added below your signing information.
If you were to go back to the Member Center now and look at your provisioning profiles, you’d see that one has been generated specifically for this project with push notifications enabled. Well, that was so easy that it makes you wonder why Apple didn’t make it this easy from day one!
Registering for notifications
You’ve told Apple that you’re going to use push notifications. Next, you’ll have to add the required code to prepare your app for receiving push notifications. As push notifications are an opt-in feature, you’ll have to request permissions from the user to enable them.
Because users can turn off notifications at any point, you need to check for whether or not they are enabled every time the app starts. The very first time, and only the very first time that your app requests access to push notifications, iOS will display an alert asking the user to accept or reject notifications. If the user accepts, or has previously accepted, you can tell your app to register for notifications.
Create a new Swift file called AppDelegate.swift and replace its contents with the following code:
import UIKit
import UserNotifications
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [
.badge, .sound, .alert
]) { granted, _ in
guard granted else { return }
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
return true
}
}
SwiftUI projects no longer include an app delegate by default. Since you need the push registration code to run at every launch, you’ll have to implement the delegate.
Note: Even though you’re using SwiftUI, the
UIApplicationDelegatecode comes fromUIKit.
Notice the addition of a new import statement to pull in the UserNotifications system framework. It’s a bit hard to read due to the long length of the function name but, essentially, whenever the app starts, you request authorization from the user to send badges, sounds and alerts to the user. If any of those items are granted by the user, you register the app for notifications.
Note: The
requestAuthorization(options:completionHandler)closure is not run on the main thread, so you must dispatch the actual registration method to the main thread of your app using the mainDispatchQueue.
Since SwiftUI lifecycle apps no longer call the app delegate by default, you’ll need to tell SwiftUI to use the app delegate you just created. Open PushNotificationsApp.swift and add these lines as the first statement in the struct:
@UIApplicationDelegateAdaptor(AppDelegate.self)
private var appDelegate
The above code uses the new property wrapper syntax to tell Xcode that it should instantiate an instance of AppDelegate, which you just created, and then wire that up to the appDelegate property.
Please build and run your app now. You’ll see the request to allow notifications.
Since you’re reading this book, you must want to see the notifications, so click on Allow in the alert.
Provisional authorization
An alert like the one above can be somewhat jarring to a user when the app starts up the first time. Why are they being asked for this? What type of data are you going to send? If you talk to your friends and colleagues, you’ll likely find that a surprising number of people, especially older people, simply reject all notifications.
To work around this issue, Apple provides another useful case for the UNAuthorizationOptions enum that you can pass to requestAuthorization during setup. If you include .provisional in the options argument, notifications will automatically be delivered silently to the user’s Notification Center, without asking for permission – there will be no sound or alerts for these provisional notifications.
The benefit of this option is that users who look in Notification Center can see your notifications and decide if they’re interested in them or not. If they are, they simply authorize them from there, resulting in future notifications appearing as regular push notifications.
That’s quite a nice feature to include via a simple flag!
Critical alerts
There’s another type of authorization that you might need to request, depending on the type of app you’re building. If your app has something to do with health and medicine, home security, public safety or anything else that may have the need to present a notification even if the user declined alerts, you can ask Apple to configure critical alerts via the .criticalAlert enum case. Critical alerts will bypass Do Not Disturb and ringer switch settings as well as always play a sound… even a custom sound.
Due to the disruptive nature of critical alerts, you must apply for a special entitlement from Apple to enable them. You can do that through the Apple Developer Portal (apple.co/2JwRvbv).
Getting the device token
If your app successfully registered for notifications, iOS will call another delegate method providing a device token to your app. The token is an opaque data type which is globally unique and identifies one app-device combination with the APNs.
Unfortunately, iOS provides this to you as a Data type instead of a String, so you’ll have to convert it since most push service providers expect a string.
Paste the following code into your AppDelegate:
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.reduce("") { $0 + String(format: "%02x", $1) }
print(token)
}
iOS will call this method once the device has sucessfully registered for push notifications. The token is a set of hex characters; the above code simply turns the token into a hex string. There are multiple methods that you’ll see on the internet for how to convert the Data type to a String. Use whatever method seems most natural to you, but keep in mind that some implementations you find online might be outdated. reduce is a method that combines the elements of a sequence into a single value using the given closure. So, in this case, you’re simply taking each byte and converting it to hex, then appending it to the accumulated value.
Note: Never make an assumption about the length of the token. Many tutorials you find will hardcode the length of a token for efficiency. Apple has already increased the token length once before from 32 to 64 characters. When you store your device tokens in something like a SQL database, be sure to not hardcode a length or you may have issues in the future.
Also, keep in mind that the device token itself can change. Apple will issue a new device token when the user installs the app on another device, restores from an old backup, reinstalls iOS and in some other cases. You should never try and link a token to a specific user.
Build and run the app on a physical device. You should see a device token (a string of random characters) in the Xcode console window:
If you run on the simulator you won’t see any output in the console. As the simulator is not able to receive notifications remotely the delegate method is never called.
If you don’t see the device token, it means that something went wrong during the setup process. To see what the problem is, add the following method to AppDelegate.swift:
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error)
}
iOS will call this method when it fails to register the device for pushes. You can now build and run again to check the error in your console.
Key points
- You must tell Xcode that push notifications will be part of your project; follow the steps in this chapter so that Xcode can handle the registration for you.
- You must add the required code to prepare your app for receiving push notifications.
- Push notifications are an opt-in feature, so you must request permissions from the user to enable them.
- To avoid jarring notifications the first time a user opens an app, use provisional authorization so that notifications are delivered silently to the user’s Notification Center, without asking for permission.
- For critical alerts that override a user’s declined alerts, you must apply for a special entitlement from Apple to enable them, due to their disruptive nature.
- Once you have successfully registered your app for notifications, iOS will call a delegate method, providing a device token to your app. Never make assumptions about the length of your token or try to link the token to a specific user.
- Specify in your
Appstruct implementation that you’re using an app delegate.
Where to go from here?
At this point, you’ve technically done everything necessary to make your app capable of receiving and displaying a push notification. In the next chapter, you’ll get your Authentication Token from Apple so that Apple’s servers will allow you to send notifications and you’ll finally send your first push notification!