Azure 通知中心豐富內容推播
概述
為了與使用者進行即時豐富內容交流,應用程式可能會想要推播純文字以外的內容。 這些通知可提高使用者互動,並呈現 URL、音效、影像/優待券等內容。 本教學課程以通知使用者教學課程為基礎,說明如何傳送包含承載 (如影像) 的推播通知。
本教學課程適用於 iOS 7 和 8。
概括而言:
- 應用程式後端:
- 在後端資料庫/本機儲存體儲存豐富的承載 (在此案例中為影像)。
- 將此豐富通知的識別碼傳送給裝置。
- 裝置上的應用程式:
- 連絡後端,要求所收到識別碼的豐富承載。
- 完成資料擷取時,在裝置上傳送使用者通知,並在使用者點選深入了解時立即顯示承載。
WebAPI 專案
在 Visual Studio 中,開啟您在 [通知使用者] 教學課程中所建立的 AppBackend 專案。
取得您想要用來通知使用者的影像,並將它放在專案目錄的 img 資料夾中。
按一下 [方案總管] 中的 [顯示所有檔案],然後以滑鼠右鍵按一下資料夾以 [加入至專案]。
選取影像後,在 [屬性] 視窗中的 [建置動作] 變更為 [內嵌資源]。
在
Notifications.cs
中,新增下列using
陳述式:using System.Reflection;
使用下列程式碼取代
Notifications
類別。 請務必使用您的通知中樞認證和影像檔名稱,以取代預留位置:public class Notification { public int Id { get; set; } // Initial notification message to display to users public string Message { get; set; } // Type of rich payload (developer-defined) public string RichType { get; set; } public string Payload { get; set; } public bool Read { get; set; } } public class Notifications { public static Notifications Instance = new Notifications(); private List<Notification> notifications = new List<Notification>(); public NotificationHubClient Hub { get; set; } private Notifications() { // Placeholders: replace with the connection string (with full access) for your notification hub and the hub name from the Azure Classics Portal Hub = NotificationHubClient.CreateClientFromConnectionString("{conn string with full access}", "{hub name}"); } public Notification CreateNotification(string message, string richType, string payload) { var notification = new Notification() { Id = notifications.Count, Message = message, RichType = richType, Payload = payload, Read = false }; notifications.Add(notification); return notification; } public Stream ReadImage(int id) { var assembly = Assembly.GetExecutingAssembly(); // Placeholder: image file name (for example, logo.png). return assembly.GetManifestResourceStream("AppBackend.img.{logo.png}"); } }
在
NotificationsController.cs
中,使用下列程式碼重新定義NotificationsController
。 這會將初始無訊息的豐富通知識別碼傳送至裝置,以便用戶端擷取影像:// Return http response with image binary public HttpResponseMessage Get(int id) { var stream = Notifications.Instance.ReadImage(id); var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new StreamContent(stream); // Switch in your image extension for "png" result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/{png}"); return result; } // Create rich notification and send initial silent notification (containing id) to client public async Task<HttpResponseMessage> Post() { // Replace the placeholder with image file name var richNotificationInTheBackend = Notifications.Instance.CreateNotification("Check this image out!", "img", "{logo.png}"); var usernameTag = "username:" + HttpContext.Current.User.Identity.Name; // Silent notification with content available var aboutUser = "{\"aps\": {\"content-available\": 1, \"sound\":\"\"}, \"richId\": \"" + richNotificationInTheBackend.Id.ToString() + "\", \"richMessage\": \"" + richNotificationInTheBackend.Message + "\", \"richType\": \"" + richNotificationInTheBackend.RichType + "\"}"; // Send notification to apns await Notifications.Instance.Hub.SendAppleNativeNotificationAsync(aboutUser, usernameTag); return Request.CreateResponse(HttpStatusCode.OK); }
現在請將此應用程式重新部署至 Azure 網站,以供所有裝置存取。 以滑鼠右鍵按一下 AppBackend 專案,然後選取 [發佈]。
選取 Azure 網站作為您的發行目標。 使用 Azure 帳戶來登入,選取現有或新的網站,並記下 [連線] 索引標籤中的 [目的地 URL] 屬性。稍後在本教學課程中,我們會將此 URL 稱為您的後端端點。 選取 [發佈] 。
修改 iOS 專案
既然您已將應用程式後端修改為只傳送通知識別碼,請變更 iOS 應用程式以處理該識別碼,並從後端擷取豐富訊息:
開啟 iOS 專案,然後移至 [目標] 區段中的主要應用程式目標,以啟用遠端通知。
選取 [功能],啟用 [背景模式],並勾選 [遠端通知] 核取方塊。
開啟
Main.storyboard
,並確定您有通知使用者教學課程中的 [檢視控制器] (在本教學課程中稱為 [首頁檢視控制器])。將 [導覽控制器] 新增至您的腳本,並按住 Control 再拖曳至 [首頁檢視控制器],作為瀏覽的根目錄檢視。 在 [屬性] 檢查程式中,請確定只針對 [導覽控制器] 選取 [為初始檢視控制器]。
將 [檢視控制器] 新增至腳本,並新增 [影像檢視]。 這是使用者選擇要深入了解,在按一下通知之後會看到的頁面。 您的腳本應如下所示:
按一下腳本中的 [首頁檢視控制器],並確定其 [自訂類別] 為 homeViewController,且 [腳本識別碼] 位於 [身分識別檢查程式] 下方。
針對類別為 imageViewController 的 [影像檢視控制器] 執行相同動作。
接著,建立新的檢視控制器類別 (名稱為 imageViewController ),以處理剛建立的 UI。
在 imageViewController.h中,將下列程式碼新增至控制器的介面宣告。 請務必按住 Ctrl 再從腳本影像檢視拖曳到這些屬性,以連結兩者:
@property (weak, nonatomic) IBOutlet UIImageView *myImage; @property (strong) UIImage* imagePayload;
在
imageViewController.m
中,於viewDidload
結尾處新增下列項目:// Display the UI Image in UI Image View [self.myImage setImage:self.imagePayload];
在
AppDelegate.m
中,匯入您建立的影像控制器:#import "imageViewController.h"
使用下列宣告新增介面區段:
@interface AppDelegate () @property UIImage* imagePayload; @property NSDictionary* userInfo; @property BOOL iOS8; // Obtain content from backend with notification id - (void)retrieveRichImageWithId:(int)richId completion: (void(^)(NSError*)) completion; // Redirect to Image View Controller after notification interaction - (void)redirectToImageViewWithImage: (UIImage *)img; @end
在
AppDelegate
中,請確定您的應用程式已註冊application: didFinishLaunchingWithOptions
中的無訊息通知:// Software version self.iOS8 = [[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)] && [[UIApplication sharedApplication] respondsToSelector:@selector(registerForRemoteNotifications)]; // Register for remote notifications for iOS8 and previous versions if (self.iOS8) { NSLog(@"This device is running with iOS8."); // Action UIMutableUserNotificationAction *richPushAction = [[UIMutableUserNotificationAction alloc] init]; richPushAction.identifier = @"richPushMore"; richPushAction.activationMode = UIUserNotificationActivationModeForeground; richPushAction.authenticationRequired = NO; richPushAction.title = @"More"; // Notification category UIMutableUserNotificationCategory* richPushCategory = [[UIMutableUserNotificationCategory alloc] init]; richPushCategory.identifier = @"richPush"; [richPushCategory setActions:@[richPushAction] forContext:UIUserNotificationActionContextDefault]; // Notification categories NSSet* richPushCategories = [NSSet setWithObjects:richPushCategory, nil]; UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge categories:richPushCategories]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } else { // Previous iOS versions NSLog(@"This device is running with iOS7 or earlier versions."); [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeNewsstandContentAvailability]; } return YES;
在下列實作中替代
application:didRegisterForRemoteNotificationsWithDeviceToken
,以考量該腳本 UI 的變更:// Access navigation controller which is at the root of window UINavigationController *nc = (UINavigationController *)self.window.rootViewController; // Get home view controller from stack on navigation controller homeViewController *hvc = (homeViewController *)[nc.viewControllers objectAtIndex:0]; hvc.deviceToken = deviceToken;
接著,將下列方法加入至
AppDelegate.m
,以擷取您的端點影像,並在擷取完成時傳送本機通知。 請務必以後端端點取代預留位置{backend endpoint}
:NSString *const GetNotificationEndpoint = @"{backend endpoint}/api/notifications"; // Helper: retrieve notification content from backend with rich notification id - (void)retrieveRichImageWithId:(int)richId completion: (void(^)(NSError*)) completion { UINavigationController *nc = (UINavigationController *)self.window.rootViewController; homeViewController *hvc = (homeViewController *)[nc.viewControllers objectAtIndex:0]; NSString* authenticationHeader = hvc.registerClient.authenticationHeader; // Check if authenticated if (!authenticationHeader) return; NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil delegateQueue:nil]; NSURL* requestURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%d", GetNotificationEndpoint, richId]]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL]; [request setHTTPMethod:@"GET"]; NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@", authenticationHeader]; [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"]; NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response; if (!error && httpResponse.statusCode == 200) { // From NSData to UIImage self.imagePayload = [UIImage imageWithData:data]; completion(nil); } else { NSLog(@"Error status: %ld, request: %@", (long)httpResponse.statusCode, error); if (error) completion(error); else { completion([NSError errorWithDomain:@"APICall" code:httpResponse.statusCode userInfo:nil]); } } }]; [dataTask resume]; } // Handle silent push notifications when id is sent from backend - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler { self.userInfo = userInfo; int richId = [[self.userInfo objectForKey:@"richId"] intValue]; NSString* richType = [self.userInfo objectForKey:@"richType"]; // Retrieve image data if ([richType isEqualToString:@"img"]) { [self retrieveRichImageWithId:richId completion:^(NSError* error) { if (!error){ // Send local notification UILocalNotification* localNotification = [[UILocalNotification alloc] init]; // "5" is arbitrary here to give you enough time to quit out of the app and receive push notifications localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5]; localNotification.userInfo = self.userInfo; localNotification.alertBody = [self.userInfo objectForKey:@"richMessage"]; localNotification.timeZone = [NSTimeZone defaultTimeZone]; // iOS8 categories if (self.iOS8) { localNotification.category = @"richPush"; } [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; handler(UIBackgroundFetchResultNewData); } else{ handler(UIBackgroundFetchResultFailed); } }]; } // Add "else if" here to handle more types of rich content such as url, sound files, etc. }
使用下列方法開啟
AppDelegate.m
中的影像檢視控制器,即可處理上述本機通知:// Helper: redirect users to image view controller - (void)redirectToImageViewWithImage: (UIImage *)img { UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController; UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil]; imageViewController *imgViewController = [mainStoryboard instantiateViewControllerWithIdentifier: @"imageViewController"]; // Pass data/image to image view controller imgViewController.imagePayload = img; // Redirect [navigationController pushViewController:imgViewController animated:YES]; } // Handle local notification sent above in didReceiveRemoteNotification - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { if (application.applicationState == UIApplicationStateActive) { // Show in-app alert with an extra "more" button UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notification" message:notification.alertBody delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"More", nil]; [alert show]; } // App becomes active from user's tap on notification else { [self redirectToImageViewWithImage:self.imagePayload]; } } // Handle buttons in in-app alerts and redirect with data/image - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { // Handle "more" button if (buttonIndex == 1) { [self redirectToImageViewWithImage:self.imagePayload]; } // Add "else if" here to handle more buttons } // Handle notification setting actions in iOS8 - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler { // Handle richPush related buttons if ([identifier isEqualToString:@"richPushMore"]) { [self redirectToImageViewWithImage:self.imagePayload]; } completionHandler(); }
執行應用程式
- 在 XCode 中,在實體 iOS 裝置上執行應用程式 (推播通知無法在模擬器中運作)。
- 在 iOS 應用程式 UI 中,輸入與驗證相同值的使用者名稱和密碼,然後按一下 [登入] 。
- 按一下 [傳送推播] ,您應該會看到一則應用程式內部警示。 如果您按一下 [詳細說明] ,將會顯示您選擇要包含在應用程式後端的影像。
- 您也可以按一下 [傳送推播] ,並立即按下裝置的主畫面按鈕。 在幾分鐘的時間內,您就會收到推播通知。 如果您點選該通知或按一下 [詳細說明],則會顯示您的應用程式以及豐富的影像內容。