iOS Push with Amazon's AWS Simple Notifications Service (SNS) and Swift Made Easy

Thabo David Klass
9 min readAug 28, 2017

--

An example of a notification from PicShip

Push is an incredible and necessary feature in any mobile application. Amazon's AWS provides a push service for mobile through it's amazing Simple Notifications Service (SNS). I personally found implementing push on iOS with Swift and SNS a bit difficult, largely because there is no simplified, step-by-step documentation on the subject. This tutorial is just that: a simple step-by-step tutorial on implementing push notifications on iOS with Swift and SNS. We have incorporated what you're going to learn below into our app Tymr available HERE. This tutorial intends to hold your hand EVERY STEP OF THE WAY. We are going to create a Swift/SNS push application.

PLEASE NOTE: the 2023, iOS 16+ and SwiftUI update of this tutorial is now available HERE.

  1. First create a single page application: open up XCode and create a single page application. You may call the application whatever you like, but make sure that the name is unique.
  2. Create a p12 certificate: create your app ID, push enabled certificate and p12 file for your new application. Here is a very good tutorial to do just that: CLICK HERE.
  3. a) Create a new platform application: Log into your AWS and go to the SNS dashboard. Click the "Create platform application" link.

b) Enter the platform application details: enter your application's name (your unique name). The push notification platform should be "Apple development".

4. Finish creating the platform application: select "iOS push certificate" as the push certificate type in the drop-down menu. Click the "Choose file" button and select the p12 certificate file you created in step 2. Click the "Load credentials from file" button and enter your password if you created one for the certificate. If you didn't have a password, leave it blank. When everything is done, click the "Create platform application" button.

Copy the application ARN for further use in your XCode application

5. Insert the SNS ARN into your app delegate: open your AppDelegate.swift file and insert the SNS platform application ARN as the first variable of the app delegate. Naturally, your application ARN will be different from the string below.

/// The SNS Platform application ARNlet SNSPlatformApplicationArn = “arn:aws:sns:us-east-1:203525439813:app/APNS_SANDBOX/SpreebieSNSExample”

IMPORTANT NOTE — Code pertaining to AppDelegate.swift is explained in a non-linear way so that you can understand the SNS concepts. There is also source code available HERE. When your are done with this tutorial, this is what your AppDelegate.swift code should look like:

6. Download the AWS SDK for iOS: go to the AWS SDK for iOS page here and download the SDK or CLICK HERE to download.

7. a) Unzip the SDK files and drag them into your project: Unzip the SDK you downloaded and add the AWSCore.framework, AWSCognito.framework and AWSSNS.framework files to your project.

b) Embed the frameworks: embed the frameworks you just added to the project by going to YourProject -> Targets -> General -> Embedded Binaries. Add AWSCore.framework, AWSCognito.framework and AWSSNS.framework.

8. Import AWSSNS into you app delegate: import the AWSSNS framework into you AppDelegate.swift.

import AWSSNS

9. a) Create a bridging header: since the AWS SDK is written in Objective-C, you will need to create a bridging header to make it work with Swift. Click File -> New -> New file. Make your file a header file and name it YourProjectName-Bridging-Header.h.

b) Add the bridging header to your build settings: add the bridging header to your project by going to YourProject -> Targets -> Build Settings -> Swift Compiler-General. Under the section Swift Compiler-General, double-click Objective -C Bridging Header for a popup to appear. Open Finder and drag your bridging header file into the popup. If your bridging header file is in the same directory as your XCode project file, just type in the name of your bridging header instead (NOTE: include the file extension as well).

Should you have any trouble creating a bridging header, CLICK HERE for further information.

10. Import modules into your bridging header: open up your bridging header file and add AWSCore and AWSCognito. Your code should resemble the code sample below:

11. Create an application endpoint in the app delegate: inside your AppDelegate.swift file, write code for the didRegisterForRemoteNotificationsWithDeviceToken delegate method. The code does two things:-

a) Gets the device token and saves it to your user defaults.

b) Creates an application endpoint and saves it to your user defaults as well.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {/// Attach the device token to the user defaultsvar token = “”for i in 0..<deviceToken.count {token = token + String(format: “%02.2hhx”, arguments: [deviceToken[i]])}print(token)UserDefaults.standard.set(token, forKey: “deviceTokenForSNS”)/// Create a platform endpoint. In this case, the endpoint is a/// device endpoint ARNlet sns = AWSSNS.default()let request = AWSSNSCreatePlatformEndpointInput()request?.token = tokenrequest?.platformApplicationArn = SNSPlatformApplicationArnsns.createPlatformEndpoint(request!).continueWith(executor: AWSExecutor.mainThread(), block: { (task: AWSTask!) -> AnyObject! inif task.error != nil {print(“Error: \(String(describing: task.error))”)} else {let createEndpointResponse = task.result! as AWSSNSCreateEndpointResponseif let endpointArnForSNS = createEndpointResponse.endpointArn {print(“endpointArn: \(endpointArnForSNS)”)UserDefaults.standard.set(endpointArnForSNS, forKey: “endpointArnForSNS”)}}return nil})}func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {print(error.localizedDescription)}

12. Create an identity pool with Cognito: AWS Cognito manages authentication and gives you security clearance to make API calls. So, for our application to make SNS API calls, it has to have an identity pool listing the allowed functionality.

a) Go to Cognito: go to the main AWS dashboard and open Cognito.

b) Manage federated identities: click the "Manage Federated Identities" button to open your identity pools page.

c) Create a new identity pool: create a new identity pool for your application.

d) Populate identity pool data: enter the name of you identity pool and check the "Enable access to unauthenticated identities" checkbox.

NOTE: Make sure to accept the defaults for the Identity and Access Management (IAM) step.

e) Allow access to resources: make sure to click the "Allow" button when your Cognito requires access to resources.

13. Copy sample Cognito code: open the sample code link of your new identity pool and copy the identity pool ID. This will be used in all non-authenticated API calls to your SNS application.

14. Add Cognito ID to your app delegate: add Cognito code containing your identity pool ID to the didFinishLaunchingWithOptions delegate method of your AppDelegate.swift file.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {// Override point for customization after application launch./// Setup AWS Cognito credentialslet credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityPoolId: “us-east-1:7d5b4064-d730–44ae-a1c3-bdc3d8bdf195”)let defaultServiceConfiguration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)AWSServiceManager.default().defaultServiceConfiguration = defaultServiceConfigurationreturn true}

15. Enable push capability: enable push notifications in YourProject -> Target -> Capabilities.

16. Register for push notifications: add a line of code that registers your app for push notifications. In the didFinishLaunchingWithOptions delegate method of your AppDelegate.swift file, insert this line of code before returning the true boolean.

registerForPushNotifications(application: application)

17. Implement push notifications for the application:

a) Import the native UserNofications package: import the iOS's native UserNotifications package in order to turn your app into a notification center.

import UserNotifications

b) Make your app delegate a subclass of UNUserNotificationCenterDelegate: make your application a subclass of UNUserNotificationCenterDelegate in order to implement delegate methods that enable push notifications.

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

c) Implement the registerForPushNotifications method: implement the registerForPushNotifications method you included earlier in step 16.

func registerForPushNotifications(application: UIApplication) {/// The notifications settingsif #available(iOS 10.0, *) {UNUserNotificationCenter.current().delegate = selfUNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert], completionHandler: {(granted, error) inif (granted){UIApplication.shared.registerForRemoteNotifications()}else{//Do stuff if unsuccessful…}})} else {let settings = UIUserNotificationSettings(types: [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound], categories: nil)application.registerUserNotificationSettings(settings)application.registerForRemoteNotifications()}}

d) Implement the userNotificationCenter delegate methods: implement the userNofificationCenter methods that make the notification center work.

// Called when a notification is delivered to a foreground app.@available(iOS 10.0, *)func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {print(“User Info = “,notification.request.content.userInfo)completionHandler([.alert, .badge, .sound])}// Called to let your app know which action was selected by the user for a given notification.@available(iOS 10.0, *)func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {print(“User Info = “,response.notification.request.content.userInfo)completionHandler()}

18. Enable SNS ability in the role you created: enable SNS capability for the role you created in step 12.

a) Go to IAM: go to the AWS dashboard and click "IAM" under "Security, Identity & Compliance".

b) Click on "Roles": click on "Roles" to see the authorized and unauthorized roles that have been created for your application.

c) Click on the unauthenticated role of your application: open the unauthenticated role of you application. The role will be named Cognito_<Indentity Pool Name>Unauth_Role.

d) Attach a policy to the role: attach a new policy to the role. We want a policy that enables SNS. Click the "Attach Policy" button.

e) Attach the SNS policy: Attach the "AmazonSNSFullAccess" policy by ticking the checkbox beside it and then clicking the "Attach Policy" button.

19. Run your app and see the endpoint: After completing all these steps, you can now run your app on XCode in order to record an endpoint on your SNS backend. Connect you iPhone to your computer and run your app on it via Xcode. This will create a unique endpoint for that particular phone. Go to AWS Dashboard -> SNS -> Applications -> YourApplication. If the process was successful, you will see a new endpoint. Now, select that endpoint and click "Publish to Endpoint".

20. Send a notification to your phone: Now you can FINALLY send a notification to your app on your phone using SNS. Type your first SNS message and send it. You should receive a push notification on your phone, :).

Success!!! You have finished the SNS backend for your application! You can download the source code by CLICKING HERE and you can see an implementation of this tutorial in production mode on our Spreebie app by following this LINK.

Thabo David Klass is a coder and co-founder at Spreebie, creator of Majeshi, PicShip, Kascada, Precious Kargo and the Spreebie app.

If you found this tutorial helpful, please click the clap 👏 button below a few times to show your support! Thank you, :). ⬇⬇

--

--

Thabo David Klass
Thabo David Klass

Written by Thabo David Klass

Coder @ Hooligan Development and indie dev @ BadaBoop (https://badaboop.com)

Responses (19)