Tutorial:使用 Azure 通知中心 (Legacy API) 向 iOS 应用发送推送通知
本教程演示如何使用适用于 Apple Legacy API 的 Azure 通知中心 SDK 和 Azure 通知中心向 iOS 应用程序发送推送通知。
本教程涵盖以下步骤:
- 创建示例 iOS 应用。
- 将 iOS 应用连接到 Azure 通知中心。
- 发送测试推送通知。
- 验证应用是否可以接收通知。
可以从 GitHub 下载本教程的完整代码。
先决条件
要完成本教程,需要具备以下先决条件:
在继续操作之前,请务必完成上一篇教程,了解如何开始使用适用于 iOS 应用的 Azure 通知中心,并在通知中心设置和配置推送凭据。 即使没有 iOS 开发经验,也应该能够按照这些步骤操作。
注意
由于推送通知的配置要求,必须在物理 iOS 设备(iPhone 或 iPad)而不是在 iOS 仿真器上部署和测试推送通知。
将 iOS 应用连接到通知中心
在 Xcode 中,创建新的 iOS 项目,然后选择“单视图应用程序”模板 。
设置新项目的选项时,请务必使用在 Apple 开发人员门户中设置捆绑标识符时使用的同一产品名称和组织标识符。
在“项目导航器”的“目标”下选择项目名称,然后选择“签名和功能”选项卡。确保为 Apple 开发人员帐户选择适当的“团队”。 XCode 会根据捆绑标识符自动下拉以前创建的预配配置文件。
如果屏幕未显示在 Xcode 中创建的新预配配置文件,请尝试刷新签名标识的配置文件。 单击菜单栏上的“Xcode”,再依次单击“首选项”、“帐户”选项卡、“查看详细信息”按钮、签名标识,然后单击右下角的刷新按钮。
在“签名和功能”选项卡中,选择“+ 功能”。 双击“推送通知”以启用它。
添加 Azure 通知中心 SDK 模块。
可以将 Azure 通知中心 SDK 集成到应用,方法是使用 Cocoapods 或者手动将二进制文件添加到项目。
通过 Cocoapods 集成:将以下依赖项添加到 podfile,以便将 Azure 通知中心 SDK 包含到应用中:
pod 'AzureNotificationHubs-iOS'
运行 pod 安装,安装新定义的 pod 并打开 .xcworkspace。
如果在运行 pod 安装时看到错误(例如找不到 AzureNotificationHubs-iOS 的规范),请运行
pod repo update
以从 Cocoapods 存储库获取最新的 pod,然后运行 pod 安装。
通过 Carthage 集成:将以下依赖项添加到 Cartfile,以便将 Azure 通知中心 SDK 包含到应用中:
github "Azure/azure-notificationhubs-ios"
- 接下来,更新生成依赖项:
$ carthage update
有关使用 Carthage 的详细信息,请参阅 Carthage GitHub 存储库。
通过将二进制文件复制到项目中进行集成:可以通过将二进制文件复制到项目中来进行集成,如下所示:
下载以 zip 文件形式提供的 Azure 通知中心 SDK 框架,然后将其解压缩。
在 Xcode 中,右键单击项目,然后单击“将文件添加到”选项,将 WindowsAzureMessaging.framework 文件夹添加到 Xcode 项目。 选择“选项”,确保选中“根据需要复制项目”,然后单击“添加”。
在相应的
<string></string>
部分中添加连接到 Azure 通知中心的信息。 将字符串字面量占位符--HUB-NAME--
和--CONNECTION-STRING--
分别替换为之前从门户中获取的中心名称和 DefaultListenSharedAccessSignature:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>HUB_NAME</key> <string>--HUB-NAME--</string> <key>CONNECTION_STRING</key> <string>--CONNECTION-STRING--</string> </dict> </plist>
打开项目 AppDelegate.h 文件,并将其内容替换为以下代码:
#import <UIKit/UIKit.h> #import <WindowsAzureMessaging/WindowsAzureMessaging.h> #import <UserNotifications/UserNotifications.h> @interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate> @property (strong, nonatomic) UIWindow *window; - (void)handleRegister; - (void)handleUnregister; @end
在项目 AppDelegate.m 文件中,添加以下
import
语句:#import "NotificationDetailViewController.h"
此外,在 AppDelegate.m 文件中,根据 iOS 版本在
didFinishLaunchingWithOptions
方法中添加以下代码行。 此代码将向 APNs 注册设备句柄:[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
在同一 AppDelegate.m 文件中,将
didFinishLaunchingWithOptions
后面的所有代码替换为以下代码:// Tells the app that a remote notification arrived that indicates there is data to be fetched. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { NSLog(@"Received remote (silent) notification"); [self logNotificationDetails:userInfo]; // // Let the system know the silent notification has been processed. // completionHandler(UIBackgroundFetchResultNoData); } // Tells the delegate that the app successfully registered with Apple Push Notification service (APNs). - (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSMutableSet *tags = [[NSMutableSet alloc] init]; // Load and parse stored tags NSString *unparsedTags = [[NSUserDefaults standardUserDefaults] valueForKey:NHUserDefaultTags]; if (unparsedTags.length > 0) { NSArray *tagsArray = [unparsedTags componentsSeparatedByString: @","]; [tags addObjectsFromArray:tagsArray]; } // Register the device with the Notification Hub. // If the device has not already been registered, this will create the registration. // If the device has already been registered, this will update the existing registration. // SBNotificationHub* hub = [self getNotificationHub]; [hub registerNativeWithDeviceToken:deviceToken tags:tags completion:^(NSError* error) { if (error != nil) { NSLog(@"Error registering for notifications: %@", error); } else { [self showAlert:@"Registered" withTitle:@"Registration Status"]; } }]; } // UNUserNotificationCenterDelegate methods // // Asks the delegate how to handle a notification that arrived while the app was running in the foreground. - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { NSLog(@"Received notification while the application is in the foreground"); // The system calls this delegate method when the app is in the foreground. This allows the app to handle the notification // itself (and potentially modify the default system behavior). // Handle the notification by displaying custom UI. // [self showNotification:notification.request.content.userInfo]; // Use 'options' to specify which default behaviors to enable. // - UNNotificationPresentationOptionsBadge: Apply the notification's badge value to the app’s icon. // - UNNotificationPresentationOptionList: Show in the Notification Center // - UNNotificationPresentationOptionsSound: Play the sound associated with the notification. // completionHandler(UNNotificationPresentationOptionsBadge | UNNotificationPresentationOptionsSound); } // Asks the delegate to process the user's response to a delivered notification. // - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler { NSLog(@"Received notification while the application is in the background"); // The system calls this delegate method when the user taps or responds to the system notification. // Handle the notification response by displaying custom UI // [self showNotification:response.notification.request.content.userInfo]; // Let the system know the response has been processed. // completionHandler(); } // App logic and helpers - (SBNotificationHub *)getNotificationHub { NSString *path = [[NSBundle mainBundle] pathForResource:@"DevSettings" ofType:@"plist"]; NSDictionary *configValues = [NSDictionary dictionaryWithContentsOfFile:path]; NSString *connectionString = [configValues objectForKey:@"CONNECTION_STRING"]; NSString *hubName = [configValues objectForKey:@"HUB_NAME"]; return [[SBNotificationHub alloc] initWithConnectionString:connectionString notificationHubPath:hubName]; } - (void)handleRegister { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; UNAuthorizationOptions options = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; [center requestAuthorizationWithOptions:(options) completionHandler:^(BOOL granted, NSError * _Nullable error) { if (error != nil) { NSLog(@"Error requesting for authorization: %@", error); } if (granted) { NSLog(@"Authorization granted"); } }]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } - (void)handleUnregister { // // Unregister the device with the Notification Hub. // SBNotificationHub *hub = [self getNotificationHub]; [hub unregisterNativeWithCompletion:^(NSError* error) { if (error != nil) { NSLog(@"Error unregistering for push: %@", error); } else { [self showAlert:@"Unregistered" withTitle:@"Registration Status"]; } }]; } - (void)logNotificationDetails:(NSDictionary *)userInfo { if (userInfo != nil) { UIApplicationState state = [UIApplication sharedApplication].applicationState; BOOL background = state != UIApplicationStateActive; NSLog(@"Received %@notification: \n%@", background ? @"(background) " : @"", userInfo); } } - (void)showAlert:(NSString *)message withTitle:(NSString *)title { if (title == nil) { title = @"Alert"; } UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:alert animated:YES completion:nil]; } - (void)showNotification:(NSDictionary *)userInfo { [self logNotificationDetails:userInfo]; NotificationDetailViewController *notificationDetail = [[NotificationDetailViewController alloc] initWithUserInfo:userInfo]; [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:notificationDetail animated:YES completion:nil]; } @end
此代码使用在 Constants.h 中指定的连接信息连接到通知中心。 然后,它向通知中心提供设备令牌,使中心能够发送通知。
创建 NotificationDetailViewController 头文件
与之前的说明类似,添加另一个名为 NotificationDetailViewController.h 的头文件。 将新的头文件的内容替换为以下代码:
#import <UIKit/UIKit.h> NS_ASSUME_NONNULL_BEGIN @interface NotificationDetailViewController : UIViewController @property (strong, nonatomic) IBOutlet UILabel *titleLabel; @property (strong, nonatomic) IBOutlet UILabel *bodyLabel; @property (strong, nonatomic) IBOutlet UIButton *dismissButton; @property (strong, nonatomic) NSDictionary *userInfo; - (id)initWithUserInfo:(NSDictionary *)userInfo; @end NS_ASSUME_NONNULL_END
添加实现文件 NotificationDetailViewController.m。 将该文件的内容替换为以下代码,此代码可实现 UIViewController 方法:
#import "NotificationDetailViewController.h" @interface NotificationDetailViewController () @end @implementation NotificationDetailViewController - (id)initWithUserInfo:(NSDictionary *)userInfo { self = [super initWithNibName:@"NotificationDetail" bundle:nil]; if (self) { _userInfo = userInfo; } return self; } - (void)viewDidLayoutSubviews { [self.titleLabel sizeToFit]; [self.bodyLabel sizeToFit]; } - (void)viewDidLoad { [super viewDidLoad]; NSString *title = nil; NSString *body = nil; NSDictionary *aps = [_userInfo valueForKey:@"aps"]; NSObject *alertObject = [aps valueForKey:@"alert"]; if (alertObject != nil) { if ([alertObject isKindOfClass:[NSDictionary class]]) { NSDictionary *alertDict = (NSDictionary *)alertObject; title = [alertDict valueForKey:@"title"]; body = [alertObject valueForKey:@"body"]; } else if ([alertObject isKindOfClass:[NSString class]]) { body = (NSString *)alertObject; } else { NSLog(@"Unable to parse notification content. Unexpected format: %@", alertObject); } } if (title == nil) { title = @"<unset>"; } if (body == nil) { body = @"<unset>"; } self.titleLabel.text = title; self.bodyLabel.text = body; } - (IBAction)handleDismiss:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } @end
ViewController
在项目 ViewController.h 文件中,添加以下
import
语句:#import <WindowsAzureMessaging/WindowsAzureMessaging.h> #import <UserNotifications/UserNotifications.h>
此外,在 ViewController.h 中,在
@interface
声明后添加以下属性声明:@property (strong, nonatomic) IBOutlet UITextField *tagsTextField; @property (strong, nonatomic) IBOutlet UIButton *registerButton; @property (strong, nonatomic) IBOutlet UIButton *unregisterButton;
在项目的 ViewController.m 实现文件中,将该文件的内容替换为以下代码:
#import "ViewController.h" #import "AppDelegate.h" static NSString *const kNHUserDefaultTags = @"notification_tags"; @interface ViewController () @end @implementation ViewController // UIViewController methods - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // Simple method to dismiss keyboard when user taps outside of the UITextField. [self.view endEditing:YES]; } - (void)viewDidLoad { [super viewDidLoad]; // Load raw tags text from storage and initialize the text field self.tagsTextField.text = [[NSUserDefaults standardUserDefaults] valueForKey:kNHUserDefaultTags]; } - (IBAction)handleRegister:(id)sender { // Save raw tags text in storage [[NSUserDefaults standardUserDefaults] setValue:self.tagsTextField.text forKey:kNHUserDefaultTags]; // Delegate processing the register action to the app delegate. [[[UIApplication sharedApplication] delegate] performSelector:@selector(handleRegister)]; } - (IBAction)handleUnregister:(id)sender { [[[UIApplication sharedApplication] delegate] performSelector:@selector(handleUnregister)]; } @end
若要验证是否没有故障,请在设备上生成并运行应用。
发送测试推送通知
可以在 Azure 门户中使用“测试性发送”选项,在应用中测试通知的发送。 它会向设备发送测试性的推送通知。
通常,推送通知是在后端服务(例如,移动应用,或者使用兼容库的 ASP.NET)中发送的。 如果后端没有可用库,也可使用 REST API 直接发送通知消息。
下面是可能需要查看的有关发送通知的其他教程列表:
- Azure 移动应用:有关如何从通知中心集成的移动应用后端发送通知的示例,请参阅将推送通知添加到 iOS 应用。
- ASP.NET:使用通知中心向用户发送推送通知。
- Azure 通知中心 Java SDK:有关从 Java 发送通知的信息,请参阅 如何通过 Java 使用通知中心 。 这种方法已在 Eclipse for Android 开发环境中进行测试。
- PHP: 如何通过 PHP 使用通知中心。
验证应用可以接收推送通知
要在 iOS 上测试推送通知,必须将应用部署到物理 iOS 设备。 不能使用 iOS 模拟器发送 Apple 推送通知。
运行应用并验证注册是否成功,并按“确定”。
如上一部分所述,接下来可以从 Azure 门户发送测试推送通知。
该推送通知会从给定通知中心发送到所有已注册接收通知的设备。
后续步骤
在这个简单的示例中,已将推送通知广播到所有已注册的 iOS 设备。 要了解如何向特定 iOS 设备发送推送通知,请转到以下教程:
有关详细信息,请参阅以下文章: