Sending push notifications to iOS with Azure Notification Hubs

Overview

Note

To complete this tutorial, you must have an active Azure account. If you don't have an account, you can create a free trial account in just a couple of minutes. For details, see Azure Free Trial.

This tutorial shows you how to use Azure Notification Hubs to send push notifications to an iOS application. You'll create a blank iOS app that receives push notifications by using the Apple Push Notification service (APNs).

When you're finished, you'll be able to use your notification hub to broadcast push notifications to all the devices running your app.

Before you begin

The goal of this article is to help you get started using Azure Notification Hubs as quickly as possible. The article presents a very simple broadcast scenario that focuses on the basic concepts of Notification Hubs.

If you are already familiar with Notification Hubs, you might want to select another topic from the left navigation or go to the relevant articles in the "Next steps" section.

We take your feedback seriously. If you have any difficulty completing this topic, or if you have recommendations for improving this content, we invite you to provide feedback at the end of the article.

The completed code for this tutorial can be found on GitHub.

Prerequisites

This tutorial requires the following:

Completing this tutorial is a prerequisite for all other Notification Hubs tutorials for iOS apps.

Generate the Certificate Signing Request file

The Apple Push Notification Service (APNS) uses certificates to authenticate your push notifications. Follow these instructions to create the necessary push certificate to send and receive notifications. For more information on these concepts see the official Apple Push Notification Service documentation.

Generate the Certificate Signing Request (CSR) file, which is used by Apple to generate a signed push certificate.

  1. On your Mac, run the Keychain Access tool. It can be opened from the Utilities folder or the Other folder on the launch pad.
  2. Click Keychain Access, expand Certificate Assistant, then click Request a Certificate from a Certificate Authority....

  3. Select your User Email Address and Common Name , make sure that Saved to disk is selected, and then click Continue. Leave the CA Email Address field blank as it is not required.

  4. Type a name for the Certificate Signing Request (CSR) file in Save As, select the location in Where, then click Save.

    This saves the CSR file in the selected location; the default location is in the Desktop. Remember the location chosen for this file.

Next, you will register your app with Apple, enable push notifications, and upload this exported CSR to create a push certificate.

Register your app for push notifications

To be able to send push notifications to an iOS app, you must register your application with Apple and also register for push notifications.

  1. If you have not already registered your app, navigate to the iOS Provisioning Portal at the Apple Developer Center, log on with your Apple ID, click Identifiers, then click App IDs, and finally click on the + sign to register a new app.

  2. Update the following three fields for your new app and then click Continue:

    • Name: Type a descriptive name for your app in the Name field in the App ID Description section.
    • Bundle Identifier: Under the Explicit App ID section, enter a Bundle Identifier in the form <Organization Identifier>.<Product Name> as mentioned in the App Distribution Guide. The Organization Identifier and Product Name you use must match the organization identifier and product name you will use when you create your XCode project. In the screeshot below NotificationHubs is used as a organization idenitifier and GetStarted is used as the product name. Making sure this matches the values you will use in your XCode project will allow you to use the correct publishing profile with XCode.
    • Push Notifications: Check the Push Notifications option in the App Services section, .

      This generates your App ID and requests you to confirm the information. Click Register to confirm the new App ID.

      Once you click Register, you will see the Registration complete screen, as shown below. Click Done.

  3. In the Developer Center, under App IDs, locate the app ID that you just created, and click on its row.

    Clicking on the app ID will display the app details. Click the Edit button at the bottom.

  4. Scroll to the bottom of the screen, and click the Create Certificate... button under the section Development Push SSL Certificate.

    This displays the "Add iOS Certificate" assistant.

    Note

    This tutorial uses a development certificate. The same process is used when registering a production certificate. Just make sure that you use the same certificate type when sending notifications.

  5. Click Choose File, browse to the location where you saved the CSR file that you created in the first task, then click Generate.

  6. After the certificate is created by the portal, click the Download button, and click Done.

    This downloads the certificate and saves it to your computer in your Downloads folder.

    Note

    By default, the downloaded file a development certificate is named aps_development.cer.

  7. Double-click the downloaded push certificate aps_development.cer.

    This installs the new certificate in the Keychain, as shown below:

    Note

    The name in your certificate might be different, but it will be prefixed with Apple Development iOS Push Services:.

  8. In Keychain Access, right-click the new push certificate that you created in the Certificates category. Click Export, name the file, select the .p12 format, and then click Save.

    Make a note of the file name and location of the exported .p12 certificate. It will be used to enable authentication with APNS.

    Note

    This tutorial creates a QuickStart.p12 file. Your file name and location might be different.

Create a provisioning profile for the app

  1. Back in the iOS Provisioning Portal, select Provisioning Profiles, select All, and then click the + button to create a new profile. This launches the Add iOS Provisiong Profile Wizard

  2. Select iOS App Development under Development as the provisiong profile type, and click Continue.
  3. Next, select the app ID you just created from the App ID drop-down list, and click Continue

  4. In the Select certificates screen, select your usual development certificate used for code signing, and click Continue. This is not the push certificate you just created.

  5. Next, select the Devices to use for testing, and click Continue

  6. Finally, pick a name for the profile in Profile Name, click Generate.

  7. When the new provisioning profile is created click to download it and install it on your Xcode development machine. Then click Done.

Configure your Notification Hub for iOS push notifications

This section walks you through creating a new notification hub and configuring authentication with APNS using the .p12 push certificate that you created. If you want to use a notification hub that you have already created, you can skip to step 5.

  1. Sign in to the Azure portal.

  2. Select New > Web + Mobile > Notification Hub.

    Azure portal - create a notification hub

  3. In the Notification Hub box, type a unique name. Select your Region, Subscription, and Resource Group (if you have one already).

    If you already have a service bus namespace that you want to create the hub in, do the following:

    a. In the Namespace area, select the Select Existing link.

    b. Select Create.

    If you don't already have a service bus namespace, you can use the default name, which is created based on the hub name (if the namespace name is available).

    Azure portal - set notification hub properties

    After you've created the namespace and notification hub, the Azure portal opens.

    Azure portal - notification hub portal page

  4. Select Settings > Access Policies. Note the two connection strings that are available to you. You will need them to handle push notifications later.

    Azure portal - notification hub connection strings

  1. Click the Notification Services button in the Settings blade, then select Apple (APNS). Click on Upload Certificate and select the .p12 file that you exported earlier. Make sure you also specify the correct password.

    Make sure to select Sandbox mode since this is for development. Only use the Production if you want to send push notifications to users who purchased your app from the store.

    Configure APNS in Azure Portal

    Configure APNS certification in Azure Portal

Your notification hub is now configured to work with APNS, and you have the connection strings to register your app and send push notifications.

Connect your iOS app to Notification Hubs

  1. In Xcode, create a new iOS project and select the Single View Application template.

    Xcode - Single View Application

  2. When setting the options for your new project, make sure to use the same Product Name and Organization Identifier that you used when you previously set the bundle ID on the Apple Developer portal.

    Xcode - project options

  3. Under Targets, click your project name, click the Build Settings tab and expand Code Signing Identity, and then under Debug, set your code-signing identity. Toggle Levels from Basic to All, and set Provisioning Profile to the provisioning profile that you created previously.

    If you don't see the new provisioning profile that you created in Xcode, try refreshing the profiles for your signing identity. Click Xcode on the menu bar, click Preferences, click the Account tab, click the View Details button, click your signing identity, and then click the refresh button in the bottom-right corner.

    Xcode - provisioning profile

  4. Download the Mobile Services iOS SDK version 1.2.4 and unzip the file. In Xcode, right-click your project and click the Add Files to option to add the WindowsAzureMessaging.framework folder to your Xcode project. Select Copy items if needed, and then click Add.

    Note

    The notification hubs SDK does not currently support bitcode on Xcode 7. You must set Enable Bitcode to No in the Build Options for your project.

    Unzip Azure SDK

  5. Add a new header file to your project named HubInfo.h. This file will hold the constants for your notification hub. Add the following definitions and replace the string literal placeholders with your hub name and the DefaultListenSharedAccessSignature that you noted earlier.

     #ifndef HubInfo_h
     #define HubInfo_h
    
         #define HUBNAME @"<Enter the name of your hub>"
         #define HUBLISTENACCESS @"<Enter your DefaultListenSharedAccess connection string"
    
     #endif /* HubInfo_h */
    
  6. Open your AppDelegate.h file add the following import directives:

      #import <WindowsAzureMessaging/WindowsAzureMessaging.h> 
      #import "HubInfo.h"
    
  7. In your AppDelegate.m file, add the following code in the didFinishLaunchingWithOptions method based on your version of iOS. This code registers your device handle with APNs:

    For iOS 8:

      UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound |
                                             UIUserNotificationTypeAlert | UIUserNotificationTypeBadge categories:nil];
    
     [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
     [[UIApplication sharedApplication] registerForRemoteNotifications];
    

    For iOS versions prior to 8:

      [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    
  8. In the same file, add the following methods. This code connects to the notification hub using the connection information you specified in HubInfo.h. It then gives the device token to the notification hub so that the notification hub can send notifications:

     - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *) deviceToken {
         SBNotificationHub* hub = [[SBNotificationHub alloc] initWithConnectionString:HUBLISTENACCESS
                                     notificationHubPath:HUBNAME];
    
         [hub registerNativeWithDeviceToken:deviceToken tags:nil completion:^(NSError* error) {
             if (error != nil) {
                 NSLog(@"Error registering for notifications: %@", error);
             }
             else {
                 [self MessageBox:@"Registration Status" message:@"Registered"];
             }
         }];
     }
    
     -(void)MessageBox:(NSString *)title message:(NSString *)messageText
     {
         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:messageText delegate:self
             cancelButtonTitle:@"OK" otherButtonTitles: nil];
         [alert show];
     }
    
  9. In the same file, add the following method to display a UIAlert if the notification is received while the app is active:

     - (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo {
         NSLog(@"%@", userInfo);
         [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]];
     }
    
  10. Build and run the app on your device to verify that there are no failures.

Send test push notifications

You can test receiving notifications in your app by sending push notifications in the Azure Portal via the Troubleshooting section in the hub blade (use the Test Send option).

Azure Portal - Test Send

Push notifications are normally sent in a back-end service like Mobile Apps or ASP.NET using a compatible library. You can also use the REST API directly to send notification messages if a library is not available for your back-end.

Here is a list of some other tutorials you may want to review for sending notifications:

In the next section of the tutorial, you will learn how to use the Notification Hub REST interface to send the notification message directly in your app. All registered devices receive the notification sent by any device.

(Optional) Send push notifications from the app

Important

This example of sending notifications from the client app is provided for learning purposes only. Since this will require the DefaultFullSharedAccessSignature to be present on the client app, it exposes your notification hub to the risk that a user may gain access to send unauthorized notifications to your clients.

If you want to send push notifications from within an app, this section provides an example of how to do this using the REST interface.

  1. In Xcode, open Main.storyboard and add the following UI components from the object library to allow the user to send push notifications in the app:

    • A label with no label text. It will be used to report errors in sending notifications. The Lines property should be set to 0 so that it will automatically size constrained to the right and left margins and the top of the view.
    • A text field with Placeholder text set to Enter Notification Message. Constrain the field just below the label as shown below. Set the View Controller as the outlet delegate.
    • A button titled Send Notification constrained just below the text field and in the horizontal center.

      The view should look as follows:

      Xcode designer

  2. Add outlets for the label and text field connected your view, and update your interface definition to support UITextFieldDelegate and NSXMLParserDelegate. Add the three property declarations shown below to help support calling the REST API and parsing the response.

    Your ViewController.h file should look as follows:

     #import <UIKit/UIKit.h>
    
     @interface ViewController : UIViewController <UITextFieldDelegate, NSXMLParserDelegate>
     {
         NSXMLParser *xmlParser;
     }
    
     // Make sure these outlets are connected to your UI by ctrl+dragging
     @property (weak, nonatomic) IBOutlet UITextField *notificationMessage;
     @property (weak, nonatomic) IBOutlet UILabel *sendResults;
    
     @property (copy, nonatomic) NSString *statusResult;
     @property (copy, nonatomic) NSString *currentElement;
    
     @end
    
  3. Open HubInfo.h and add the following constants which will be used for sending notifications to your hub. Replace the placeholder string literal with your actual DefaultFullSharedAccessSignature connection string.

     #define API_VERSION @"?api-version=2015-01"
     #define HUBFULLACCESS @"<Enter Your DefaultFullSharedAccess Connection string>"
    
  4. Add the following #import statements to your ViewController.h file.

     #import <CommonCrypto/CommonHMAC.h>
     #import "HubInfo.h"
    
  5. In ViewController.m add the following code to the interface implementation. This code will parse your DefaultFullSharedAccessSignature connection string. As mentioned in the REST API reference, this parsed information will be used to generate a SaS token for the Authorization request header.

     NSString *HubEndpoint;
     NSString *HubSasKeyName;
     NSString *HubSasKeyValue;
    
     -(void)ParseConnectionString
     {
         NSArray *parts = [HUBFULLACCESS componentsSeparatedByString:@";"];
         NSString *part;
    
         if ([parts count] != 3)
         {
             NSException* parseException = [NSException exceptionWithName:@"ConnectionStringParseException"
                 reason:@"Invalid full shared access connection string" userInfo:nil];
    
             @throw parseException;
         }
    
         for (part in parts)
         {
             if ([part hasPrefix:@"Endpoint"])
             {
                 HubEndpoint = [NSString stringWithFormat:@"https%@",[part substringFromIndex:11]];
             }
             else if ([part hasPrefix:@"SharedAccessKeyName"])
             {
                 HubSasKeyName = [part substringFromIndex:20];
             }
             else if ([part hasPrefix:@"SharedAccessKey"])
             {
                 HubSasKeyValue = [part substringFromIndex:16];
             }
         }
     }
    
  6. In ViewController.m, update the viewDidLoad method to parse the connection string when the view loads. Also add the utility methods, shown below, to the interface implementation.

     - (void)viewDidLoad
     {
         [super viewDidLoad];
         [self ParseConnectionString];
         [_notificationMessage setDelegate:self];
     }
    
     -(NSString *)CF_URLEncodedString:(NSString *)inputString
     {
        return (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)inputString,
             NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8);
     }
    
     -(void)MessageBox:(NSString *)title message:(NSString *)messageText
     {
         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:messageText delegate:self
             cancelButtonTitle:@"OK" otherButtonTitles: nil];
         [alert show];
     }
    
  7. In ViewController.m, add the following code to the interface implementation to generate the SaS authorization token that will be provided in the Authorization header, as mentioned in the REST API Reference.

     -(NSString*) generateSasToken:(NSString*)uri
     {
         NSString *targetUri;
         NSString* utf8LowercasedUri = NULL;
         NSString *signature = NULL;
         NSString *token = NULL;
    
         @try
         {
             // Add expiration
             uri = [uri lowercaseString];
             utf8LowercasedUri = [self CF_URLEncodedString:uri];
             targetUri = [utf8LowercasedUri lowercaseString];
             NSTimeInterval expiresOnDate = [[NSDate date] timeIntervalSince1970];
             int expiresInMins = 60; // 1 hour
             expiresOnDate += expiresInMins * 60;
             UInt64 expires = trunc(expiresOnDate);
             NSString* toSign = [NSString stringWithFormat:@"%@\n%qu", targetUri, expires];
    
             // Get an hmac_sha1 Mac instance and initialize with the signing key
             const char *cKey  = [HubSasKeyValue cStringUsingEncoding:NSUTF8StringEncoding];
             const char *cData = [toSign cStringUsingEncoding:NSUTF8StringEncoding];
             unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
             CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
             NSData *rawHmac = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
             signature = [self CF_URLEncodedString:[rawHmac base64EncodedStringWithOptions:0]];
    
             // Construct authorization token string
             token = [NSString stringWithFormat:@"SharedAccessSignature sig=%@&se=%qu&skn=%@&sr=%@",
                 signature, expires, HubSasKeyName, targetUri];
         }
         @catch (NSException *exception)
         {
             [self MessageBox:@"Exception Generating SaS Token" message:[exception reason]];
         }
         @finally
         {
             if (utf8LowercasedUri != NULL)
                 CFRelease((CFStringRef)utf8LowercasedUri);
             if (signature != NULL)
             CFRelease((CFStringRef)signature);
         }
    
         return token;
     }
    
  8. Ctrl+drag from the Send Notification button to ViewController.m to add an action named SendNotificationMessage for the Touch Down event. Update method with the following code to send the notification using the REST API.

     - (IBAction)SendNotificationMessage:(id)sender
     {
         self.sendResults.text = @"";
         [self SendNotificationRESTAPI];
     }
    
     - (void)SendNotificationRESTAPI
     {
         NSURLSession* session = [NSURLSession
                          sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                          delegate:nil delegateQueue:nil];
    
         // Apple Notification format of the notification message
         NSString *json = [NSString stringWithFormat:@"{\"aps\":{\"alert\":\"%@\"}}",
                             self.notificationMessage.text];
    
         // Construct the message's REST endpoint
         NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@/messages/%@", HubEndpoint,
                                             HUBNAME, API_VERSION]];
    
         // Generate the token to be used in the authorization header
         NSString* authorizationToken = [self generateSasToken:[url absoluteString]];
    
         //Create the request to add the APNs notification message to the hub
         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
         [request setHTTPMethod:@"POST"];
         [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    
         // Signify Apple notification format
         [request setValue:@"apple" forHTTPHeaderField:@"ServiceBusNotification-Format"];
    
         //Authenticate the notification message POST request with the SaS token
         [request setValue:authorizationToken forHTTPHeaderField:@"Authorization"];
    
         //Add the notification message body
         [request setHTTPBody:[json dataUsingEncoding:NSUTF8StringEncoding]];
    
         // Send the REST request
         NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request
             completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
         {
             NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
             if (error || (httpResponse.statusCode != 200 && httpResponse.statusCode != 201))
             {
                 NSLog(@"\nError status: %d\nError: %@", httpResponse.statusCode, error);
             }
             if (data != NULL)
             {
                 xmlParser = [[NSXMLParser alloc] initWithData:data];
                 [xmlParser setDelegate:self];
                    [xmlParser parse];
             }
         }];
         [dataTask resume];
     }
    
  9. In ViewController.m, add the following delegate method to support closing the keyboard for the text field. Ctrl+drag from the text field to the View Controller icon in the interface designer to set the view controller as the outlet delegate.

     //===[ Implement UITextFieldDelegate methods ]===
    
     -(BOOL)textFieldShouldReturn:(UITextField *)textField
     {
         [textField resignFirstResponder];
         return YES;
     }
    
  10. In ViewController.m, add the following delegate methods to support parsing the response by using NSXMLParser.

    //===[ Implement NSXMLParserDelegate methods ]===
    
    -(void)parserDidStartDocument:(NSXMLParser *)parser
    {
        self.statusResult = @"";
    }
    
    -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
        namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
        attributes:(NSDictionary *)attributeDict
    {
        NSString * element = [elementName lowercaseString];
        NSLog(@"*** New element parsed : %@ ***",element);
    
        if ([element isEqualToString:@"code"] | [element isEqualToString:@"detail"])
        {
            self.currentElement = element;
        }
    }
    
    -(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)parsedString
    {
        self.statusResult = [self.statusResult stringByAppendingString:
            [NSString stringWithFormat:@"%@ : %@\n", self.currentElement, parsedString]];
    }
    
    -(void)parserDidEndDocument:(NSXMLParser *)parser
    {
        // Set the status label text on the UI thread
        dispatch_async(dispatch_get_main_queue(),
        ^{
            [self.sendResults setText:self.statusResult];
        });
    }
    
  11. Build the project and verify that there are no errors.

Note

If you encounter a build error in Xcode7 about bitcode support, you should change the Build Settings > Enable Bitcode (ENABLE_BITCODE) to NO in Xcode. The Notification Hubs SDK does not currently support bitcode.

You can find all the possible notification payloads in the Apple Local and Push Notification Programming Guide.

Checking if your app can receive push notifications

To test push notifications on iOS, you must deploy the app to a physical iOS device. You cannot send Apple push notifications by using the iOS Simulator.

  1. Run the app and verify that registration succeeds, and then press OK.

    iOS App Push Notification Registration Test

  2. You can send a test push notification from the Azure Portal, as described above. If you added code for sending push notifications in the app, touch inside the text field to enter a notification message. Then press the Send button on the keyboard or the Send Notification button in the view to send the notification message.

    iOS App Push Notification Send Test

  3. The push notification is sent to all devices that are registered to receive the notifications from the particular Notification Hub.

    iOS App Push Notification Receive Test

Next steps

In this simple example, you broadcasted push notifications to all your registered iOS devices. We suggest as a next step in your learning that you proceed to the Azure Notification Hubs Notify Users for iOS with .NET backend tutorial, which will walk you through creating a backend to send push notifications using tags.

If you want to segment your users by interest groups, you can additionally move on to the Use Notification Hubs to send breaking news tutorial.

For general information about Notification Hubs, see Notification Hubs Guidance.