Skip to content

Commit c3ddae0

Browse files
authored
Merge pull request #108959 from mikeparker104/patch-1
(AzureCXP) Updated for iOS 13
2 parents 4c62008 + 7239558 commit c3ddae0

File tree

1 file changed

+64
-30
lines changed

1 file changed

+64
-30
lines changed

articles/notification-hubs/notification-hubs-ios-push-notifications-swift-apps-get-started.md

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
---
1+
---
22
title: Send push notifications to Swift iOS apps that use Azure Notification Hubs | Microsoft Docs
33
description: Learn how to push notifications to Swift iOS apps that use Azure Notification Hubs.
44
services: notification-hubs
@@ -38,6 +38,8 @@ This tutorial takes you through the following steps:
3838
> * Connect your iOS app to a notification hub.
3939
> * Test the solution.
4040
41+
The complete code for this tutorial can be found [on GitHub](https://github.com/xamcat/mobcat-samples/tree/master/notification_hub_rest).
42+
4143
## Prerequisites
4244

4345
To follow along, you need:
@@ -110,18 +112,18 @@ In this section, you'll build the iOS app that will connect to the notification
110112

111113
1. Find **Identity** and then set the **Bundle Identifier** value so that it matches `com.<organization>.PushDemo`, which is the value used for the **App ID** from a previous step.
112114

113-
1. Find **Signing**, and then select the appropriate **Team** for your **Apple Developer Account**. The **Team** value should match the one under which you created your certificates and profiles.
115+
1. Find **Signing & Capabilities**, and then select the appropriate **Team** for your **Apple Developer Account**. The **Team** value should match the one under which you created your certificates and profiles.
114116

115-
1. Xcode should automatically pull down the appropriate **Provisioning Profile** value based on the **Bundle Identifier**. If you don't see the new **Provisioning Profile** value, try refreshing the profiles for the **Signing Identity** by selecting **Xcode** > **Preferences** > **Account** > **View Details**. Select **Signing Identity**, and then select the **Refresh** button in the bottom right to download the profiles.
117+
1. Xcode should automatically pull down the appropriate **Provisioning Profile** value based on the **Bundle Identifier**. If you don't see the new **Provisioning Profile** value, try refreshing the profiles for the **Signing Identity** by selecting **Xcode** > **Preferences** > **Account** then select the **Download Manual Profiles** button to download the profiles.
116118

117-
1. Select the **Capabilities** tab and ensure that **push notifications** are enabled.
119+
1. Still on the **Signing & Capabilities** tab, click the **+ Capability** button and double tap on **Push Notifications** from the list to ensure **Push Notifications** are enabled.
118120

119121
1. Open your **AppDelegate.swift** file to implement the **UNUserNotificationCenterDelegate** protocol and add the following code to the top of the class:
120122

121123
```swift
122124
@UIApplicationMain
123125
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
124-
126+
125127
...
126128

127129
var configValues: NSDictionary?
@@ -130,13 +132,12 @@ In this section, you'll build the iOS app that will connect to the notification
130132
var notificationHubKeyName : String?
131133
var notificationHubKey : String?
132134
let tags = ["12345"]
133-
let genericTemplate = PushTemplate(withBody: "{\"aps\":{\"alert\":\"$(message)\"}}")
134-
135+
135136
...
136137
}
137138
```
138139

139-
You'll use these members later. Specifically, you'll use the **tags** and **genericTemplate** members as part of the registration. For more information on tags, see [Tags for registrations](notification-hubs-tags-segment-push-message.md) and [Template registrations](notification-hubs-templates-cross-platform-push-messages.md).
140+
You'll use these members later. Specifically, you'll use the **tags** member as part of the registration using a **custom template**. For more information on tags, see [Tags for registrations](notification-hubs-tags-segment-push-message.md) and [Template registrations](notification-hubs-templates-cross-platform-push-messages.md).
140141

141142
1. In the same file, add the following code to the **didFinishLaunchingWithOptions** function:
142143

@@ -182,7 +183,8 @@ In this section, you'll build the iOS app that will connect to the notification
182183
func showAlert(withText text : String) {
183184
let alertController = UIAlertController(title: "PushDemo", message: text, preferredStyle: UIAlertControllerStyle.alert)
184185
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil))
185-
self.window?.rootViewController?.present(alertController, animated: true, completion: nil)
186+
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
187+
keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
186188
}
187189
```
188190

@@ -208,6 +210,11 @@ In this section, you'll build the iOS app that will connect to the notification
208210

209211
1. Add print statements to the bottom of the **didRegisterForRemoteNotificationsWithDeviceToken** function to verify that **installationId** and **pushChannel** are being assigned values.
210212

213+
```swift
214+
print(installationId)
215+
print(pushChannel)
216+
```
217+
211218
1. Create the **Models**, **Services**, and **Utilities** folders for the foundational components you'll be adding to the project later.
212219

213220
1. Check that the project builds and runs on a physical device. Push notifications can't be tested by using the simulator.
@@ -307,9 +314,9 @@ To add and configure the bridging header:
307314
#endif /* BridgingHeader_h */
308315
```
309316

310-
1. Update the Target's **Build Settings** to reference the bridging header:
317+
1. Update the Targets **Build Settings** to reference the bridging header:
311318

312-
1. Open the **Building Settings** tab and scroll down to the **Swift Compiler** section.
319+
1. Tap on the **PushDemo** project and scroll down to the **Swift Compiler** section.
313320

314321
1. Ensure that the **Install Objective-C Compatibility Header** option is set to **Yes**.
315322

@@ -388,11 +395,25 @@ To add and configure the bridging header:
388395

389396
The [Azure Storage iOS SDK](https://github.com/Azure/azure-storage-ios/blob/master/Lib/Azure%20Storage%20Client%20Library/Azure%20Storage%20Client%20Library/AZSUtil.m) is an excellent example of how to approach these operations in Objective-C. Further information on Azure Service Bus SAS tokens can be found in the [Azure Service Bus documentation](../service-bus-messaging/service-bus-sas.md).
390397

398+
1. In **AppDelegate.swift**, add the following code to the *didRegisterForRemoteNotificationsWithDeviceToken* function to verify that the **TokenUtility.getSasToken** is generating a valid token
399+
400+
```swift
401+
let baseAddress = "https://<notificaitonHubNamespace>.servicebus.windows.net/<notifiationHubName>"
402+
403+
let tokenData = TokenUtility.getSasToken(forResourceUrl: baseAddress,
404+
withKeyName: self.notificationHubKeyName!,
405+
andKey: self.notificationHubKey!)
406+
407+
print(tokenData.token)
408+
```
409+
410+
Be sure to replace the placeholder values in the **baseAddress** string with your own
411+
391412
### Verify the SAS token
392413

393414
Before you implement the installation service in the client, check that our app is correctly generating the SAS token by using your HTTP utility of choice. For the purposes of this tutorial, our tool of choice will be **Postman**.
394415

395-
Use an appropriately placed print statement or breakpoint to note the **installationId** and the **token** values being generated by the app.
416+
Make a note of the **installationId** and **token** values being generated by the app.
396417

397418
Follow these steps to call the **installations** API:
398419

@@ -451,7 +472,8 @@ class NotificationRegistrationService {
451472
private let keyName : String
452473
private let key : String
453474
private var tokenData : TokenData? = nil
454-
475+
private var tokenExpiryDate : Date? = nil
476+
455477
init(withInstallationId installationId : String,
456478
andPushChannel pushChannel : String,
457479
andHubNamespace hubNamespace : String,
@@ -466,58 +488,67 @@ class NotificationRegistrationService {
466488
self.key = key
467489
self.defaultHeaders = ["Content-Type": "application/json", "x-ms-version": apiVersion]
468490
}
469-
491+
470492
func register(
471493
withTags tags : [String]? = nil,
472494
andTemplates templates : Dictionary<String, PushTemplate>? = nil,
473495
completeWith completion: ((_ result: Bool) -> ())? = nil) {
474-
496+
475497
var deviceInstallation = DeviceInstallation(withInstallationId: installationId, andPushChannel: pushChannel)
476-
498+
477499
if let tags = tags {
478500
deviceInstallation.tags = tags
479501
}
480-
502+
481503
if let templates = templates {
482504
deviceInstallation.templates = templates
483505
}
484-
506+
485507
if let deviceInstallationJson = encodeToJson(deviceInstallation) {
486508
let sasToken = getSasToken()
487509
let requestUrl = String.init(format: tokenizedCreateOrUpdateInstallationRequest, installationId, apiVersion)
488510
let apiEndpoint = "\(getBaseAddress())\(requestUrl)"
489-
511+
490512
var request = URLRequest(url: URL(string: apiEndpoint)!)
491513
request.httpMethod = "PUT"
492-
514+
493515
for (key,value) in self.defaultHeaders {
494516
request.addValue(value, forHTTPHeaderField: key)
495517
}
496-
518+
497519
request.addValue(sasToken, forHTTPHeaderField: "Authorization")
498520
request.httpBody = Data(deviceInstallationJson.utf8)
499-
521+
500522
(self.session.dataTask(with: request) { dat, res, err in
501523
if let completion = completion {
502-
completion(err == nil && (res as! HTTPURLResponse).statusCode == 200)
524+
completion(err == nil &&
525+
(res as! HTTPURLResponse).statusCode == 200)
503526
}
504527
}).resume()
505528
}
506529
}
507-
530+
508531
private func getBaseAddress() -> String {
509532
return String.init(format: tokenizedBaseAddress, hubNamespace, hubName)
510533
}
511-
534+
512535
private func getSasToken() -> String {
513536
if (tokenData == nil ||
514-
Date(timeIntervalSince1970: Double((tokenData?.expiration)!)) < Date(timeIntervalSinceNow: -(5 * 60))) {
515-
self.tokenData = TokenUtility.getSasToken(forResourceUrl: getBaseAddress(), withKeyName: self.keyName, andKey: self.key)
537+
tokenExpiryDate == nil ||
538+
Date() >= tokenExpiryDate!) {
539+
540+
self.tokenData = TokenUtility.getSasToken(
541+
forResourceUrl: getBaseAddress(),
542+
withKeyName: self.keyName,
543+
andKey: self.key)
544+
545+
self.tokenExpiryDate = Date(timeIntervalSinceNow: -(5 * 60))
546+
.addingTimeInterval(TimeInterval(tokenData!.expiration))
516547
}
517548

518549
return (tokenData?.token)!
519550
}
520-
551+
521552
private func encodeToJson<T : Encodable>(_ object: T) -> String? {
522553
do {
523554
let jsonData = try jsonEncoder.encode(object)
@@ -548,10 +579,11 @@ Finally, **encodeToJson** converts the respective model objects into JSON for us
548579

549580
The last step is updating **AppDelegate** to use **NotificationRegistrationService** to register with our **NotificationHub**.
550581

551-
1. Open **AppDelegate.swift** and add a class-level variable to store a reference to the **NotificationRegistrationService**:
582+
1. Open **AppDelegate.swift** and add class-level variables to store a reference to the **NoficiationRegistrationService** and the generic **PushTemplate**:
552583

553584
```swift
554585
var registrationService : NotificationRegistrationService?
586+
let genericTemplate = PushTemplate(withBody: "{\"aps\":{\"alert\":\"$(message)\"}}")
555587
```
556588

557589
1. In the same file, update the **didRegisterForRemoteNotificationsWithDeviceToken** function to initialize the **NotificationRegistrationService** with the requisite parameters, and then call the **register** function.
@@ -614,6 +646,8 @@ You can now make the same request as you did previously by using **Postman** for
614646
}
615647
```
616648

649+
If your previous **SAS token** has expired, you can add a **breakpoint** to **line 24** of the **TokenUtility** class to get a new **SAS token** and update the **Authorization** header with that new value.
650+
617651
### Send a test notification (Azure portal)
618652

619653
The quickest way to test that you can now receive notifications is to browse to the notification hub in the Azure portal:
@@ -688,7 +722,7 @@ You can send notifications via the [REST API](/rest/api/notificationhubs/) by us
688722

689723
1. Select the **Send** button.
690724

691-
You should get a success status code and receive the notification on the client device.
725+
You should get a **201 Created** success status code and receive the notification on the client device..
692726

693727
## Next steps
694728
You now have a basic iOS Swift app connected to a notification hub via the [REST API](/rest/api/notificationhubs/) and can send and receive notifications. For more information, see the following articles:

0 commit comments

Comments
 (0)