iOS Dynamic Push Notifications with AWS Pinpoint

Marvin Mouroum
9 min readSep 8, 2019

Path to Push Notifications

Push Notifications are key to engage your audience with your app. In this tutorial, I will walk over the steps on how I implement push notifications with amazon web services for iOS apps.

In order to follow this series you need to have:

  • Apple Developer Account
  • Amazon Web Services Console Account

The entire code will be in Swift and the IDE is Xcode.

In a nutshell, these are the steps:

  1. Create a signing certificate locally on your mac
  2. Create a Push Notification certificate in your Apple Developer Account
  3. Create an iOS app in AWS’s mobile hub
  4. Add a database & messaging functions to your mobile hub
  5. Upload apple’s push notification certificate to AWS and update your app’s code as well as AWS settings
  6. Build the app, archive it and distribute it for Ad-Hoc
  7. Install it on your phone
  8. Trigger a message, through your app or an external event

Many steps are necessary in order to have the notification pop up in your app. However if you follow this tutorial you will be able to save some time figuring it out by yourself.

Dealing with Certificates

Creating a signing certificate

Before you can do anything you need to create a signing certificate. In order to do so, you need to open your keychain on your mac. Simply search (cmd & space) for “keychain” and it will open up.

Follow these instructions: Keychain Access > Certificate Assistant > Create a Certificate.

Fill out the information and check “save locally on drive”

Once you have saved your certificate you are ready for the next step.

Apple gives pretty straight forward steps on how to create a signing certificate. You can follow this link here if you want to read the original.

Push Notification Certificate

There are two types of Push Notification Certificates:

  1. Sandbox
  2. Sandbox & Production

Don’t bother with the first type for AWS because it’s likely not going to work. Let’s get to it.

Go to your apple developer account and open the certificates section.

chose certificates, Identifiers & Profiles

Click the plus button in order to add a certificate. Chose the only certificate that will work with AWS -> Sandbox & Production.

Chose this certificate

Type in your app’s bundle ID, that is unique for every app and can be found inside your XCode project. When starting a new project the bundle id should be saved and be available inside your developer account to chose. However I’ve made the experience that this won’t always work. If this was the case I would advise you to create an bundle id inside your apple developer account and overwrite the old one inside your XCode project.

Once you’ve created your certificate, download it and save it locally. You will need to upload it later to AWS.

Prepare Push Notifications for AWS

AWS microservices likely give you multiple options to implement push notifications in your app. However the “Mobile Hub” makes building a backend for mobile apps quite easy. This also holds true when implementing push notifications. Since we have already created the iOS push notifications certificate from apple, we can now continue with building the backend. If you read this section and you are developing for android, you can do so, since the next steps are universal.

Search for the “Mobile Hub” in your AWS console.

In order to use push notifications, we need at least two microservices, Messaging & Analytics and Database. These two services are called Amazon Pinpoint and DynamoDB and can be selected from your “Mobile Hub” start screen.

The two microservices needed.

Database

The NoSQL database will be needed to store information about your users, that should receive the push notifications. The most important entry, that we will create, is the device token. This token is the address to the phone, kind of like a phone number, that is used in order to deliver the push notification. If you want to consider the fact that a user might have several devices you might want to save a list of device tokens, based on the devices. Another useful entry could be the type of device e.g. iPhone, iPad, or the OS like iOS 12 or Android.

In order to create a database just click on the NoSQL database button and follow the instructions:

  1. Select Custom
  2. Pick a name
  3. Set it to public
  4. Keep userID or change to username as first column
  5. Add a String List with the name devicetoken
  6. (Optional) instead of the list you could add a dictionary or some type to include the device type
  7. Create the table

Messaging

There are two ways of sending push notifications with AWS. One way is using the Simple Notification Service (SNS) and another way is using amazon Pinpoint. We will use Pinpoint for sending a notification because it is super simple. However, in order to trigger a notification, we will need to use amazon’s REST API. This can be kinda confusing when working in swift. I will write about triggering a notification later in this series.

Again click the button for Messaging & Analytics, chose messaging and follow the steps. In the end, you should upload your certificate from apple (we created earlier). Upload the certificate and see if it was accepted by AWS. If not, try to see where the problem is and maybe even redo the certificate.

Update your App

Now that the backend is ready, you need to connect your app to it. Go back to your “Mobile Hub” start screen for your current app and click on integrate.

Download the Cloud Config and insert it into your XCode project. Download the Swift Modules and insert the DB classes into your XCode project.
Drop the config file here

After you have added the config file and the database class for your device token table, you need to add some code in order for it to work. Amazon gives you clear instructions on how to include the libraries to your project. However, when working with Swift and XCode it is the best to statically insert the libraries to your project. On XCode just click on your project to see the project navigator, go to the General Tab and scroll down to Embedded Libraries. Add all these libraries except for S3.

This is how it should look like when it’s done.

These are the instructions for the necessary code for each element you need.

  1. Database
  2. Push Notifications

Once you’ve added the code you are theoretically good to go. In the next section, I will show you the best way to test your implementation.

Send First Push Notifications with AWS

After creating our certificates and preparing the backend, we can now start and send some notifications 👏

To send a notification we need the device token of our device. This token can be read by adding this piece of code in your app’s AppDelegate. Before continuing with dynamic sending, let’s test if the service works.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {pinpoint!.notificationManager.interceptDidRegisterForRemoteNotifications(withDeviceToken: deviceToken)let tokenString = deviceToken.reduce(“”, {$0 + String(format: “%02X”, $1)})var deviceToken = deviceToken.hexEncodedString()print(“deviceToken: \(deviceToken.hexEncodedString())”)}

Make sure that you implemented the code that asks whether the app can send notifications. Put this code inside the viewDidLoad of your start viewController.

center.requestAuthorization(options: options) { (success, error) inif success{print(“user granted permission”)}else {print(“user denied permission”)}}

Run your app on your device. The simulator won’t work. Accept the pop up that asks for permission for notifications. Save the device token and go to the AWS Pinpoint Console. Inside the “Mobile Hub” in your app’s start screen on the top right there are two links — analytics and resources. Click on resources and then on Pinpoint (or the link presented under pinpoint). Chose your app and go to test messaging. Chose Push Notification, enter your device token and a test message. Close your app, since it won’t receive any notification if it’s in the foreground. Now click send and watch your first Push Notification appear. Sometimes, this notification is silent. Dropdown your Notification Center and see if it might be present, in the case you didn’t see it coming after one minute.

Notification Center Example

If you have received the message, you are ready for the next step!

Send Push Notifications dynamically

Sending push notifications needs to happen dynamically. In order to do this, we need to call the REST API from AWS Pinpoint. The device token that you collected in the previous step won’t be the same one you will have when deploying the app. And the REST API will not send any notification to a sandbox device. Therefore we need to create a production version and load it to the phone in order to receive push notifications. This is tricky because we can not print out the device token in a production version. 🤔

Luckily we have created our DynamoDB database! And now it’s time to use it. We will store the new device token inside our user table.

  1. Save the token as a global variable inside your app’s delegate
  2. Create a userItem and set it’s token variable to your token. userItem._token = appDel.deviceToken
  3. In case you have a String List insert it into the existing list.
  4. create a db entry by calling the following code.
//Save a new itemdynamoDbObjectMapper.save(userItem, completionHandler: {(error: Error?) -> Void inif let error = error {print(“Amazon DynamoDB Save Error: \(error)”)return}print(“User \(userItem._userName!) has been updated”)})

Start the app and check whether something was written to your table.

In order to send notifications through the API, you will need your secretAccessKey and accessKeyId from aws. You can download them once in your personal account space in the Identity and Access Management (IAM) section.

This guy did a great job writing the code for us. Go check it out and use it. Your graphqURL can be constructed explained in the AWSDocumentation. The device token should be retrieved through your apps logic, e.g. fetching a user from the DB and inserted into this function together with the intended message.

private static func create_APNS_Body(_ address:String,_ message:PushNotificationInfo)->String {let context = “\n\”Context\”:{}”let addresse = “\n\”Addresses\”:{\”\(address)\”:{\”ChannelType\”:\”APNS\”}}”let Endpoints = “\n\”Endpoints\”:{}”let apnsBody = “\n\”Body\”:\”\(message.text)\””let apnsSubs = “\n\”Substitutions\”:{}”let apnsTitle = “\n\”Title\”:\”\(message.title)\””let apnsAction = “\n\”Action\”:\”OPEN_APP\””let apnsUrl = “\n\”Url\”:\”string\””let apnsSilentPush = “\n\”SilentPush\”:false”let apnsData = “\n\”Data\”:{}”let apnsBatch = “\n\”Badge\”:0"let apnsSound = “\n\”Sound\”:\”default\””let APNSMessage = “\n\”APNSMessage\”:”let MessageConfiguration = “\n\”MessageConfiguration\”:”let open = “{“let close = “}”let comma = “,”let body = open + context + comma + MessageConfiguration + open + APNSMessage + open + apnsBody + comma + apnsSubs + comma + apnsTitle + comma + apnsAction + comma + apnsUrl + comma + apnsSilentPush + comma + apnsData + comma + apnsBatch + comma + apnsSound + close + close + comma + addresse + comma + Endpoints + closereturn body}

Insert the result from this function to the HttpUtils function

HttpUtils.makeSignedRequestToGraphql(query: body) { (result) inprint(result)}

And hope for a 200 result :)

You will probably get an error because you first need to deploy your app.

  1. Build it for your phone
  2. Achive it
  3. Distribute it as Ad-Hoc
  4. Upload it to https://www.diawi.com
  5. Delete the old version of your phone
  6. Scan the QR code from diawi and install it as a distributed version.
  7. Run the app to make sure the device token is saved and notifications are accepted.
  8. Run your logic on another device (can be simulator) and trigger a push notification.

Now you should receive a push notification.

Let me know if this post was helpful. I would also love to discuss better ways to do it. :)

--

--

Marvin Mouroum

From Berlin, Computer Vision Engineer — Writing about technical innovation in IoT and Deep Learning.