What are iOS Push Notifications ?
Push notifications are messages sent from your application’s server to the Apple Push Notification Service (APNS) server, which then delivers the notification to the specified device. This method is particularly useful if you’re planing on sending data from your server to your app users. For example, a messaging app users push notifications to alert uses whenever new messages arrive.
In this process, you have complete control over when to send notifications to the user. To initiate this, you’ll need a unique device token, the data you want to send, and the necessary notification permissions granted by the user.
You’re responsible for configuring the provider server and sending a request to the APNs. Apple takes care of all other aspects , including delivering the notification to the device.
In this tutorial, we’ll walkthrough the entire process of delivering a notification to the user.
Let’s start by creating an Xcode Project. Once the project has been initialized, go to “Signing & Capabilities” after selecting your app as the target. Then, click on “+ Capability” and search for and select “Push Notifications.”
First off, we need permission from the user to send notifications, this can be done using the requestAuthorization
method of UNUserNotificationCenter
. The getNotificationSettings
method of UNUserNotificationCenter
, will retrieve the authorization status of your application. For example, the following code will retrieve the current authorization status of the application and initiates a permission request if the status is not authorised.
import SwiftUI
import UserNotifications
struct ContentView: View {
var body: some View {
VStack {
}
.padding()
.onAppear {
let center = UNUserNotificationCenter.current()
center.getNotificationSettings {settings in
if settings.authorizationStatus == .authorized {
print("allowed")
}else {
center.requestAuthorization(options:[.alert, .badge, .sound]) {granted, error in
if let error = error {
//Handle error
}else {
print("No error")
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
To send notifications to a specific device, a unique device token is required. To generate a unique device token for each device, we must utilize the registerForRemoteNotifications()
method provided by UIApplication
. This method should be called within the AppDelegate
. Once a device is successfully registered for remote notifications, the device token becomes available within the AppDelegate
. To use this functionality within a SwiftUI App, create a class named AppDelegate
. Inside the App struct, use the UIApplicationDelegateAdapter
to trigger the AppDelegate
. By default, when you register a device for remote notifications, you receive a device token in the form of Data
. You’ll need to convert this device token into a hexadecimal string format before passing it to APIs or web applications.
import SwiftUI
@main
struct NotifyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: Data) {
let token = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(token)
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError
error: Error) {
// Error handling.
}
}
To send notifications, the APNs server must establish either token-based or certificate-based connection with APNs. In this article, we’ll focus on token-based connection.
Token-based connection.
JSON Token based connections are used to secure the communications between your provider server and APNs. This token must be provided while making a request with the APNs. To create a token the following pieces are required.
kid : The key ID, which is generated from your Apple Developer account. We’ll go through the steps to create this key shortly.
iss : Issuer key, a 10-character team ID, which can be found in your developer account.
alg : APNs supports the ES256 algorithm.
iat : The timestamp indicating when the token is generated.
The header of the token contains the kid
and alg
, while the payload of the token contains iss
and iat
.
HEADER
{
"alg" : "ES256",
"kid" : "ABC123DEFG"
}
PAYLOAD
{
"iss": "DEF123GHIJ",
"iat": 1437179036
}
All these pieces must be signed using a token signing key, which is generated from the developer account.
For the token-based connection method, start by logging into your Apple Developer account. Next, navigate to the “Keys” section and generate a new key, as shown in the following image.
Once the key has been generated, proceed by clicking “Continue” and then “Register” to finalize the process. Apple will supply you with a key ID and a token signing key file. Store both of these items securely as they are required to generate a JWT(JSON Web Token).
The following python code can be used to create a JWT(JSON web token). Replace the path, key ID, and issuer key with the ones generated from developer portal.
Before running the code, make sure to install the JWT package using the following command.
pip3 install pyjwt
import jwt
import time
now = time.time()
pathToPrivateKey = 'Path of your private key file(.p8)'
header = {
'alg': 'ES256',
'kid': 'key ID'
}
payload = {
'iss': 'Developer account team ID',
'iat': int(now)
}
with open(pathToPrivateKey, 'r+b') as keyfile:
secret = keyfile.read()
print(jwt.encode(payload, secret, algorithm="ES256", headers = header))
A JWT is printed on the console after running the code. Store the JWT to a variable, by using the below command.
AUTHENTICATION_TOKEN=authentication token value
Wrapping Up.
Xcode simulator is not capable of receiving push notifications, so a real device is required to test the application. Connect a real device(iPhone or iPad) to your Mac using a USB cable. In Xcode, select your connected device from the dropdown menu and select it as the destination.
Run the Xcode project and click “Allow” when notification permission is prompted. Once the permissions have been granted, a device token is printed on the Xcode’s console.
Now that you have both the device token and the JWT (JSON Web Token) that was generated earlier, you’re all set to send push notifications to your real device. To complete this, execute the following curl
command. Be sure to replace <BUNDLE-IDENTIFIER>
with your app's bundle identifier (in reverse domain format, such as "com.ihemanth.Notifier") and <DEVICE-TOKEN-HERE>
with the device token you obtained earlier
curl -v \
--header "authorization: bearer ${AUTHENTICATION_TOKEN}" \
--header "apns-topic: <BUNDLE-IDENTIFIER>" \
--header "apns-push-type: alert" \
--header "apns-priority: 5" \
--header "apns-expiration: 0" \
--data '{"aps":{"alert":{"title":"title","subtitle":"subtitle","body":"body"}}}' \
--http2 https://api.development.push.apple.com:443/3/device/<DEVICE-TOKEN-HERE>
Ensure that you close the app to receive notifications, and also confirm that your device is not in low power mode.
By following these steps, you can test your push notification functionality on a real iOS device.