Sending iOS Push Notifications using curl

Sending iOS Push Notifications using curl

Push notifications are an essential tool for mobile apps to engage with users, deliver important updates, or send personalized alerts.
In iOS, sending push notifications involves interacting with Apple’s Push Notification service (APNs), and this often requires the use of JSON Web Tokens (JWT) for secure communication.

In this article, we will walk through some simple examples that help streamline the process of creating JWTs and sending push notifications to iOS devices.

Understanding the Bash Scripts


We will create 2 scripts to handle sending push notifications:

1. makeJWToken.sh: This script generates the JSON Web Token (JWT) required for authentication with APNs.
2. push.sh: This script sends the actual push notification to the APNs endpoint using the generated JWT.

Setup

# makeJWToken.sh
#!/usr/bin/env bash
TEAMID="YOUR_TEAM_ID"
KEYID="YOUR_KEY_ID"
# Path to the p8 file
SECRET="$KEY_PATH/$KEYID.p8"

# Make input base64 url safe
function base64URLSafe {
  openssl base64 -e -A | tr '+/' '-_' | tr -d =
}

# Sign input with you key file
function sign {
  printf "$1"| openssl dgst -binary -sha256 -sign "$SECRET" | base64URLSafe
}

# now
time=$(date +%s)

#
# e.g.
# {
#   "alg" : "ES256",
#   "kid" : "ABC123DEFG"
# }
header=$(printf '{ "alg": "ES256", "kid": "%s" }' "$KEYID" | base64URLSafe)

#
# e.g.
# {
#   "iss": "DEF123GHIJ",
#   "iat": 1437179036
# }
claims=$(printf '{ "iss": "%s", "iat": %d }' "$TEAMID" "$time" | base64URLSafe)

# Concatenate your header, your claim and a signed version of you header concatenated with your claim
jwt="$header.$claims.$(sign $header.$claims)"
# Write jwt to file
echo $jwt > token.txt

The teamId can be fetched from the developer portal as well https://developer.apple.com/account

To create the JWT we need to generate and download a p8 key file from apples developer portal.
This can be done from here https://developer.apple.com/account/resources/authkeys/list

Sending

# push.sh
# Set the appropriate endpoint
#ENDPOINT=https://api.sandbox.push.apple.com:443 # Only for XCode builds
ENDPOINT=https://api.push.apple.com:443  # For live and TestFlight builds
URLPATH=/3/device/
BUNDLEID="com.example.yourApp"  # Replace with your app's bundle ID
URL=$ENDPOINT$URLPATH$DEVICETOKEN

# Read the previously generated JWT
JWT=$(cat token.txt)

# The device token where the push should be sent to (64 characters)
DEVICE_TOKEN=$1

COLLAPSE_ID="1"
DATA='{"aps": { "alert": {"title":"TITLE","subtitle":"SUBTITLE","body":"BODY"}, "sound": "default", "link_url": "https://example.com", "acme": {}}}'

# Send the push
curl -v \
  --http2 \
  --header "authorization: bearer $JWT" \
  --header "apns-topic: ${BUNDLEID}" \
  --header "apns-collapse-id: ${COLLAPSE_ID}" \
  --data "${DATA}" \
  "${URL}"

The apns-collapse-id is a header used in the Apple Push Notification service (APNs) to manage how multiple notifications sent to the same device are handled.
Its primary purpose is to collapse or replace multiple notifications into a single one, reducing clutter and preventing a device from being overwhelmed by notifications.

Usage

chmod +x makeJWToken.sh # Make the script executable
chmod +x push.sh # Make the script executable
./makeJWToken.sh
./push.sh YOUR_DEVICE_TOKEN

Another easy way to test push notifications is to use apples user interface on the developer console.
This can be found here: https://icloud.developer.apple.com/dashboard/notifications

Subscribe to Max's blog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe