Push Notifications with Parse and Swift

Categories:

Update 1/29/2016: Parse announced yesterday in their blog that they will be fully shutting down operations on January 28, 2017. Consider using a service like Amazon.com SNS or Pushover.

Editor’s Note: This is part one in a three part series. The goal in this series is to develop a fully functional (and useful) iOS application that is capable of pushing weather alerts based on your location to your iOS device. The series is broken down as follows:

  • Part One – Developing a Push Notification-capable application with Parse and Swift
  • Part Two – Using CoreLocation with Swift
  • Part Three – Integrating in a Weather Service API

In this first part of our three part series we’ll be developing an application which is capable of receiving iOS push notifications. Rather than invent our own push notification application server, we’ll leverage Parse to provide this capability. Our first warning: this tutorial is rather lengthy and involved, and it requires some knowledge about using the Apple Developer Portal to create certificates, provisioning profiles, and register iOS devices for development. If you’ve never gone through this process before I highly recommend a quick read of this post.

Our Application

There are a number of iOS weather applications on the AppStore. If you think about it, a large number of mobile phone applications mirror the sections of the newspaper you were used to growing up as a kid (because as an adult I’m betting you don’t read the newspaper). The Business section had stocks, the Sports section had all the football scores, and of course the Weather page had the weather and the forecast. The basic information we desire to receive hasn’t changed much; what has changed is how we receive it and how timely and contextual it is. I personally use The Weather Channel application and have my Severe Weather set to Dallas, TX. Whenever there are severe weather alerts for North Texas I receive a push notification to my phone alerting me to the fact.

But what I really want is weather alerts based upon my current location. If I’m traveling across the country, whether by plane, train, or automobile, it would be nice to know if there are sudden weather alerts based upon where I am, not where I live. This is the type of application we’re going to develop in this tutorial, and we’ll do it using very basic iOS development techniques, and we’ll do it all in Swift. At the end of this tutorial you won’t have an application that you’ll be able to rush out and publish to the AppStore, because it won’t have a functional UI (it won’t have a UI at all), but it will give you a framework to build something upon if you choose to do so. What it will provide are all the details necessary to learn how to use Parse for push notifications, CoreLocation for location, and integrating with a REST API for receiving weather alerts posted by NOAA.

Getting Started

To get started let’s create a new project in Xcode (we are using Xcode 6.1). Select the Single View iOS application template, and choose Swift as your language. Name the Product Name weatheralerts. Make note of the bundle identifier, in our case its it.iachieved.weatheralerts, but yours will undoubtedly be different (like com.yourcompany.weatheralerts).

tut_new_project_options

Normally I wouldn’t harp on this, but when dealing with push notifications it is important to ensure that you make note of the bundle identifier. It is important when configuring push notifications in the developer portal that you use the same bundle identifier as what you used in your project.

Since we are going to be using API keys in our application and don’t want to commit them to Github, we’re going to use our documented technique for storing API keys in a property list file. Take a moment to follow our tutorial for creating your ApiKeys.plist and ApiKeys.swift files for this project. The remainder of this tutorial will assume you’ve used this technique.

Signing Up With Parse

We’ll be using Parse for sending push notifications to our application. Parse requires you to sign up to use it’s service, so head on over sign up.

tut_signup_for_parse

Once you’ve signed up browse over to the QuickStart page and create a basic application. Name the application weatheralerts and then select the big Push icon:

tut_hello_push

Select the big iOS icon (they make it so cute), and then select Existing Project.

tut_parse_existing_project

Here you should see a pleasant blue background outlining steps to obtain the Parse SDK, adding it to your application, etc. Follow the instructions for downloading, unzipping, and adding the Parse SDK to your project, but stop at the section titled Connect your app to Parse and instead follow these instructions for using Parse with Swift. To be clear, before proceeding with the next section you should have:

  • Downloaded and unzipped the Parse SDK
  • Dragged and dropped Parse.framework and Bolts.framework into your Xcode project, following the instructions to copy files
  • Added all of the required iOS frameworks as outlined in the Parse instructions (there are quite a few)

Using Parse

To use Parse with our Swift application we’re going to need to create a bridging header. This is due to the fact that Parse is (currently) an Objective-C framework, as is 99% of the established frameworks out there as of this writing. Swift simply hasn’t been around long enough to have a large number of native frameworks. To create a bridging header with Xcode go to File – New – File and in the iOS Source templates choose Header File. Name it bridgingHeader (the name doesn’t matter actually as long as your project is configured properly to use it) and Xcode will place it in your project.

In bridgingHeader.h add #import such that the file looks something like:

[objc]
#ifndef weatheralerts_bridgingHeader_h
#define weatheralerts_bridgingHeader_h

#import <Parse/Parse.h>

#endif
[/objc]

Our bridging header is in place, but you have to configure it in your project. Click on your application target and select the Build Settings tab. In the search box type bridging to find the configuration entry quickly. For the bridging header path you can type in $(SRCROOT)/$(PROJECT_NAME)/bridgingHeader.h.

tut_configure_bridging_header

Now, because this is a multipart tutorial that will culminate in an application that can send you NOAA weather alerts, we’re going to go ahead and add things that aren’t necessary for a basic push notification application. The pattern is a useful one, however, and can be adapted for your own specific project needs.

We’re going to use a push notification controller to encapsulate our push notification needs. Go ahead and create a Swift file named PushNotificationController and add the following boilerplate code to it:

[objc]
import Foundation

class PushNotificationController : NSObject {

override init() {
super.init()
}

}
[/objc]

Simple enough. Now we can pick up where we left off with Parse.

The first step in our application is going to be to set Parse’s application ID and client key to those values provided to us. Whereas the Parse tutorial has us placing these values in our application delegate’s didFinishLaunchingWithOptions function, we’re going to place them in the constructor (in other words, the init function) of our PushNotificationController. First, however, we want our keys in our ApiKeys.plist file. We’ll refer to them as PARSE_APPLICATION_ID and PARSE_CLIENT_KEY. Again, we’re using a specific technique for managing API keys outlined here.

tut_parse_api_keys

Using our valueForAPIKey function provided in ApiKeys.swift we can configure Parse as follows:

[objc]
override init() {
super.init()

let parseApplicationId = valueForAPIKey(keyname: "PARSE_APPLICATION_ID")
let parseClientKey = valueForAPIKey(keyname: "PARSE_CLIENT_KEY")

Parse.setApplicationId(parseApplicationId, clientKey: parseClientKey)

}
[/objc]

Now we must switch over to the AppDelegate class and register for push notifications. We want to create an instance of the PushNotificationController in our application delegate, and we can do so by adding:

[objc]
var pushNotificationController:PushNotificationController?
[/objc]

right beneath the var window: UIWindow? declaration, and then in the application(application:didFinishLaunchingWithOptions:) function add:

[objc]
self.pushNotificationController = PushNotificationController()

// Register for Push Notitications, if running iOS 8
if application.respondsToSelector("registerUserNotificationSettings:") {

let types:UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)

application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()

} else {
// Register for Push Notifications before iOS 8
application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}
[/objc]

Note that due to differences between push notification registration in iOS 8 and iOS 7 we have to determine if the new iOS 8 method is available (registerUserNotificationSettings:). If it is we use the iOS 8 method, otherwise iOS 7. See Stackoverflow for additional information.

Finally, in our application delegate (AppDelegate) we’re going to add 3 more functions:

  • didRegisterForRemoteNotificationsWithDeviceToken
  • didFailToRegisterForRemoteNotificationsWithError
  • didReceiveRemoteNotification

It’s important to go ahead and implement didFailToRegisterForRemoteNotificationsWithError because odds are there will be some misconfiguration with your first attempt at push notifications, and it’s helpful to know right away what that might be.

Here’s the implementation for these routines:

[objc]
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
println("didRegisterForRemoteNotificationsWithDeviceToken")

let currentInstallation = PFInstallation.currentInstallation()

currentInstallation.setDeviceTokenFromData(deviceToken)
currentInstallation.saveInBackgroundWithBlock { (succeeded, e) -> Void in
//code
}
}

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println("failed to register for remote notifications: \(error)")
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("didReceiveRemoteNotification")
PFPush.handlePush(userInfo)
}
[/objc]

We’ll look at each of these in turn momentarily. Go ahead and try to run the application as it is on your iPhone. If everything has been configured correctly thus far you should get a popup requesting push notification access.

tut_would_like_to_send

However, even after pressing on OK you will likely see in the console log:

An Aside: If you ever find yourself testing push notifications and would like to trigger the dialog requesting allowance to send push notifications a second time, you’re in for the real treat of changing the time on your iPhone. No kidding.

To actually allow for push notifications to be sent to the device we need to turn to the Apple Developer portal and follow a multi-step process (and in this order):

  • Create a new AppId for our application
  • Enable Push Notifications for our newly created application
  • Create our Push Notification security certificate
  • Create a Provisioning Profile for our application
  • Download and install the Provisioning Profile
  • Configure our project to use our new Provisioning Profile

Provisioning in the Developer Portal

Let’s start with our AppId. Go to the Apple Developer Portal Member Center and navigate to the Certificates, Identifiers & Profiles page. Select Identifiers and choose App Ids.

tut_new_app_id

You should see a plus icon to the right of the title iOS App IDs, select that plus sign to register a new AppId.

tut_create_app_id

There are some key things to note here:

  • The App ID Description can be a plain-text description, such as Weather Alert Application
  • The App ID Prefix is chosen for you based upon what iOS development team you are a member of
  • Select Explicit App ID for this tutorial and ensure your Bundle ID is the same as the bundle id of your application

The last item cannot be stressed enough, if the bundle identifiers do not match you are in for a headache. In our example we used it.iachieved.weatheralerts. Scroll down to the bottom (we are going to ignore App Services for the moment and configure it later) and click Continue. On the Confirm your App ID page click Submit.

Configuring the application for push notifications

Although after creating the application ID the portal tells us This App ID is now registered to your account and can be used in your provisioning profiles. we need to actually configure it for push notifications. Go back to the App IDs page and select your application. Scroll to the bottom of the Application Services list and click on the Edit button.

Scroll down again until you find the Push Notifications service and click on the checkbox to the left to enable it, and then click on Create Certificate in the section marked Development SSL Certificate.

tut_enable_push_notifications

If you have never created a Certificate Signing Request the process is not difficult, but it is cumbersome and requires a number of manual steps. Before continuing further I suggest you read in detail the text on the developer portal page that is presented to you. That is, the page that begins with To manually generate a Certificate Signing Request…. As the page instructs you need to open KeyChain Access and use the Request a Certificate from a Certificate Authority feature.

As depicted below enter your e-mail address, and choose a Common Name that is descriptive for the purposes that this certificate will serve. In our case I chose WeatherAlertsDevelopmentPush to remind me what I’m using this certificate for. Choose Saved to Disk.

tut_request_cert

Continue the prompts in Keychain Access and once you’ve saved your certificate request to disk, click Continue in the development portal and then Choose File… to upload the request to the portal. Once the file is uploaded click Generate. The developer portal will then generate your certificate and prompt you to Download, Install and Backup. Click Download.

tut_download_and_install

The file downloaded will be named something like aps_development.cer and placed in your Downloads folder. Navigate to the file and open it. Keychain Access will import the file and match it against the private key used by the certificate signing request. In Keychain Access click on My Certificates and you can use the search field to find your new certificate:

tut_push_certificate

If you thought you were finished with push notification configuration, you are mistaken! We told you there were a lot of steps involved. Continuing in the portal we need to create our application provisioning profile.

Creating a Provisioning Profile

Select Development under Provisioning Profiles and click the plus icon to the right of iOS Provisioning Profiles. When prompted choose a Development provisioning profile (the type used for installing development apps on test devices):

tut_what_type_of_pp

Click Continue to select the App ID of the application we will use with this provisioning profile. In particular, select the application that matches the one you just created for weatheralerts.

tut_select_app_id

Now choose the developer certificate(s) you want to be able to use with this provisioning profile. It is important to choose a Development certificate here, and one that you have already set up. Finally, choose all the devices that you want to be able to run the application on.

tut_name_pp

Name the profile (I chose WeatherAlerts Development) and click Generate.

tut_download_and_install_pp

Download and install the provisioning profile using the instructions on the screen.

Now that your provisioning profile is downloaded and installed go to your application target in Xcode, and choose Build Settings. In the Code Signing section, choose your code signing identity (which matches the certificate you chose to use for the provisioning profile),

tut_codesigning_identity

If everything is configured correctly this time, you should see didRegisterForRemoteNotificationsWithDeviceToken in your console log.

Configuring Your Application in Parse

To allow Parse to push notifications to your app, you first have to configure it with your application’s push notification certificate. This is the private key and certificate you created above in Keychain Access. Locate the certificate in Keychain Access by selecting My Certificates and the search field. Right-click the row that the certificate is on and choose Export “Apple Development IOS Push Services:…”. Name the file WeatherAlertsDevPushCert and ensure that the file format for the export is Personal Information Exchange. Save it to your Desktop, and do not enter a password to protect the exported items (this is important!). Keychain Access may prompt you for your login keychain password to export the certificate.

Go to your application’s Push Settings in your Parse console. The screen should look something like this:

tut_parse

In the section title Apple Push Certificates click on Select your certificate and choose the WeatherAlertsDevPushCert.p12 file you just created. You should now see something like this in your Parse portal.

tut_devpushcert_uploaded

Now, let’s send a test push notification. Again, the only way this will work is if all of the previous steps have been followed correctly. In your Parse portal, select the Push menu item for your application.

tut_send_test_push

Click Send a push and keep the Parse defaults with the exception of writing This is a test push notification in the field marked for writing your message. Scroll all the way to the bottom of the page and select Send now.

If your application was running in the foreground when you sent the test push, Parse did you the kind favor of creating an alert dialog box with given text. If your application was running in the background you should have received a standard iOS push notification dialog box. An example of our push notification received while the application is in the background:

tut_push_in_background

An example of receiving a push notification while the application is in the foreground:

tut_push_in_foreground

Bitbucket Xcode Project

The work done thus far is available on Bitbucket on a branch named part1. To use the project you can directly download the zip file and open the enclosed Xcode project. There are a few steps you’ll need to complete to use the project:

  • Sign up for Parse and obtain your own API keys
  • Change the Bundle Identifier to reflect your organization (that is, change it.iachieved. to com.yourcompany)
  • Create and add your own ApiKeys.plist file and use your Parse API keys
  • Create and configure your own provisioning profile

To get the full experience, however, I recommend creating your project from scratch and working through the tutorial one step at a time.

Part Two

Part two of this series will introduce using the CoreLocation capabilities of iOS to receive location information. This location information will in turn be used in Part Three to lookup whether or not there are any weather alerts in the area. Stay tuned!

Leave a Reply

Your email address will not be published. Required fields are marked *