Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
521 lines (345 sloc) 21.796 kb

Get started with Notification Hubs

[AZURE.INCLUDE notification-hubs-selector-get-started]

Overview

This topic shows you how to use Azure Notification Hubs to send push notifications to an iOS application. In this tutorial you create a blank iOS app that receives push notifications using the Apple Push Notification service (APNs). When complete, you will be able to broadcast push notifications to all the devices running your app using your notification hub.

This tutorial demonstrates the simple broadcast scenario using notification hubs.

Prerequisites

This tutorial requires the following prerequisites:

  • Mobile Services iOS SDK
  • XCode 6
  • An iOS 8 (or later version) capable device
  • iOS Developer Program membership

    [AZURE.NOTE] Because of push notification configuration requirements, you must deploy and test push notifications on an iOS capable device (iPhone or iPad) instead of the Simulator.

Completing this tutorial is a prerequisite for all other notification hub tutorials for iOS apps.

[AZURE.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.

[AZURE.INCLUDE Notification Hubs Enable Apple Push Notifications]

Configure your notification hub

This section walks you through creating and configuring a new notification hub with the push certificate you created. If you want to use a notification hub you have already created, you can skip steps 2-5.

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

    Make a note of the file name and location of the exported certificate.

    [AZURE.NOTE] This tutorial creates a QuickStart.p12 file. Your file name and location might be different.

  2. Log on to the Azure Management Portal, and click +NEW at the bottom of the screen.

  3. Click on App Services, then Service Bus, then Notification Hub, then Quick Create.

  4. Type a name for your notification hub, select your desired region, and then click Create a new Notification Hub.

  5. Click the namespace you just created (usually notification hub name-ns) to open it's dashboard.

  6. Click the Notification Hubs tab at the top, and then click on the notification hub you just created.

  7. Click the Configure tab at the top, and then click the Upload button in the Apple notification settings to upload the certificate thumbprint. Then select the .p12 certificate you exported earlier, and the password for the certificate. Make sure to select whether you want to use the Production (if you want to send push notifications to users that purchased your app from the store) or the Sandbox (during development) push service.

  8. Click the Dashboard tab at the top, and then click View Connection String. Take note of the two connection strings.

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

Connecting your app to the notification hub

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

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

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

  4. Download version 1.2.4 of the Mobile Services iOS SDK 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, then click Add.

  5. Open your AppDelegate.h file add the following import directive:

     #import <WindowsAzureMessaging/WindowsAzureMessaging.h>
    
  6. 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 version prior to 8:

     [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    
  7. In the same file, add the following methods and replace the string literal placeholders with your hub name and the DefaultListenSharedAccessSignature you noted earlier. This code gives the device token to the notification hub so the notification hub can send notifications:

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *) deviceToken {
        SBNotificationHub* hub = [[SBNotificationHub alloc] initWithConnectionString:
                                  @"<Enter your listen connection string>" notificationHubPath:@"<Enter your hub name>"];
    
        [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];
    }
    
  8. In the same file, add the following method to display an 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"]];
    }
    
  9. Build and run the app on your device to verify not failures.

How to Send Notifications

You can test receiving notifications in your app by send notifications in the Azure portal using the debug tab on the notification hub as shown in the screen below.

[AZURE.INCLUDE notification-hubs-sending-notifications-from-the-portal]

  1. In XCode, open your Main.storyboard and add the following UI components from the object library to allow the user to send push notifications.

    • A Label with no label text. It will be used to report errors sending notifications. Lines property should be set to 0 so it will auto size constrained to 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 Return Key to Send and set the View Controller as the outlet delegate.
    • A Button titled Send Notification centered and constrained just below the text field.

    The view should look as follows:

  2. Open your ViewController.h file and add the following #import and #define statements. Replace the placeholder string literal with your actual DefaultFullSharedAccessSignature connection string and hub name.

    #import <CommonCrypto/CommonHMAC.h>
    
    #define API_VERSION @"?api-version=2015-01"
    #define HUBFULLACCESS @"<Enter Your DefaultFullSharedAccess Connection string>"
    #define HUBNAME @"<Enter the name of your hub>"
    
  3. Add outlets for the label and text field in your view and update your interface definition to support UITextFieldDelegate, NSURLConnectionDataDelegate, 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>
    #import <CommonCrypto/CommonHMAC.h>
    
    #define API_VERSION @"?api-version=2015-01"
    #define HUBFULLACCESS @"<Enter Your DefaultFullSharedAccess Connection string>"
    #define HUBNAME @"<Enter the name of your hub>"
    
    @interface ViewController : UIViewController <UITextFieldDelegate, NSURLConnectionDataDelegate, NSXMLParserDelegate>
    {
        NSURLConnection *currentConnection;
        NSXMLParser *xmlParser;
    }
    
    @property (weak, nonatomic) IBOutlet UITextField *notificationMessage;
    @property (weak, nonatomic) IBOutlet UILabel *sendResults;
    
    @property (retain, nonatomic) NSMutableData *apiReturnXMLData;
    @property (copy, nonatomic) NSString *statusResult;
    @property (copy, nonatomic) NSString *currentElement;
    
    @end
    
  4. Open ViewController.m and add the following code to 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 *HuSasKeyValue;
    
    -(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];
            }
        }
    }
    
  5. In ViewController.m, update the viewDidLoad method to parse the connection string when the view loads. Also add the utility methods shown below.

    - (void)viewDidLoad 
    {
        [super viewDidLoad];
        [self ParseConnectionString];
    }
    
    -(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];
    }
    
  6. In ViewController.m, add the following code 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 sr=%@&sig=%@&se=%qu&skn=%@",
                targetUri, signature, expires, HubSasKeyName];
        }
        @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;
    }
    
  7. Add an action for the Send Notification button that executes the following code.

    - (IBAction)SendNotificationMessage:(id)sender {
        NSString *json = [NSString stringWithFormat:@"{\"aps\":{\"alert\":\"%@\"}}", self.notificationMessage.text];
    
        self.sendResults.text = @"";
    
        NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@/messages/%@", HubEndpoint, HUBNAME, API_VERSION]];
    
        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"];
        [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]];
    
        if (currentConnection)
        {
            [currentConnection cancel];
            currentConnection = NULL;
            self.apiReturnXMLData = NULL;
        }
    
        currentConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    
        self.apiReturnXMLData = [NSMutableData data];
    }
    
  8. In ViewController.m, add the following delegate method to support the Send keyboard button for the text field.

    //===[ Implement UITextFieldDelegate methods ]===
    
    -(BOOL)textFieldShouldReturn:(UITextField *)notificationMessage 
    {
        [notificationMessage resignFirstResponder];
        [self SendNotificationMessage:NULL];
    
        return YES;
    }
    
  9. In ViewController.m, add the following delegate methods to support calling the REST API using the NSURLConnection.

    //===[ Implement NSURLConnectionDataDelegate methods ]===
    
    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        [self MessageBox:@"POST Request Failed" message:[error localizedDescription]];
    }
    
    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        [self.apiReturnXMLData appendData:data];
    }
    
    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        [self.apiReturnXMLData setLength:0];
    }
    
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        xmlParser = [[NSXMLParser alloc] initWithData:self.apiReturnXMLData];
        [xmlParser setDelegate:self];
        [xmlParser parse];
    
        currentConnection = NULL;
    }
    
  10. In ViewController.m, add the following delegate methods to support parsing the response 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
    {
        [self.sendResults setText:self.statusResult];
    }
    
  11. Build the project and verify no errors.

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

Testing Your App

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

  1. Run the app and verify registrations succeeds then press OK.

  2. 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.

  3. The notification is sent to all devices registered to receive the notification.

If you have any problems or recommendations for improving this tutorial for all readers, please leave us a comment in the Disqus section below.

Next steps

In this simple example you broadcast notifications to all your iOS devices. In order to target specific users refer to the tutorial Use Notification Hubs to push notifications to users, while if you want to segment your users by interest groups you can read Use Notification Hubs to send breaking news. Learn more about how to use Notification Hubs in Notification Hubs Guidance.

Jump to Line
Something went wrong with that request. Please try again.