Azure Notification Hubs Rich Push
Översikt
För att engagera användare med omedelbart omfattande innehåll kanske ett program vill skicka mer än oformaterad text. Dessa meddelanden främjar användarinteraktioner och presenterar innehåll som URL:er, ljud, bilder/kuponger med mera. Den här självstudien bygger på självstudien Meddela användare och visar hur du skickar push-meddelanden som innehåller nyttolaster (till exempel bilder).
Den här självstudien är kompatibel med iOS 7 och 8.
På hög nivå:
- Appens serverdel:
- Lagrar den omfattande nyttolasten (i det här fallet avbildningen) i serverdelsdatabasen/den lokala lagringen.
- Skickar ID för det här omfattande meddelandet till enheten.
- App på enheten:
- Kontaktar serverdelen som begär den omfattande nyttolasten med det ID som den tar emot.
- Skickar meddelanden till användarna på enheten när datahämtningen är klar och visar nyttolasten direkt när användarna trycker för att lära sig mer.
WebAPI-projekt
I Visual Studio öppnar du det AppBackend-projekt som du skapade i självstudien Meddela användare .
Hämta en avbildning som du vill meddela användare med och placera den i en img-mapp i projektkatalogen.
Klicka på Visa alla filer i Solution Explorer och högerklicka på mappen som ska inkluderas i projektet.
När avbildningen har valts ändrar du dess byggåtgärd i fönstret Egenskaper till Inbäddad resurs.
I
Notifications.cs
lägger du till följandeusing
-instruktion:using System.Reflection;
Notifications
Ersätt klassen med följande kod. Se till att ersätta platshållarna med dina autentiseringsuppgifter för meddelandehubben och bildfilsnamnet: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}"); } }
I
NotificationsController.cs
omdefinierar duNotificationsController
med följande kod. Detta skickar ett första tyst RTF-meddelande-ID till enheten och tillåter hämtning på klientsidan av avbildningen:// 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); }
Distribuera nu om den här appen till en Azure-webbplats för att göra den tillgänglig från alla enheter. Högerklicka på AppBackend-projektet och välj Publicera.
Välj Azure-webbplats som publiceringsmål. Logga in med ditt Azure-konto och välj en befintlig eller ny webbplats och anteckna mål-URL-egenskapen på fliken Anslutning . Vi refererar till den här URL:en som din serverdelsslutpunkt senare i den här självstudien. Välj Publicera.
Ändra iOS-projektet
Nu när du har ändrat appens serverdel så att den bara skickar ID :t för ett meddelande ändrar du iOS-appen för att hantera det ID:t och hämtar det omfattande meddelandet från serverdelen:
Öppna ditt iOS-projekt och aktivera fjärrmeddelanden genom att gå till huvudappens mål i avsnittet Mål .
Välj Funktioner, aktivera bakgrundslägen och markera kryssrutan Fjärrmeddelanden .
Öppna
Main.storyboard
och kontrollera att du har en vykontrollant (kallas styrenhet för hemvy i den här självstudien) från självstudien Meddela användare .Lägg till en navigeringskontrollant i din storyboard och styr-dra startvykontrollanten för att göra den till rotvyn för navigering. Kontrollera att kontrollanten Är inledande vy i attributkontrollen är markerad endast för navigeringskontrollanten.
Lägg till en vykontrollant i storyboarden och lägg till en bildvy. Det här är sidan som användarna ser när de väljer att lära sig mer genom att klicka på meddelandet. Din storyboard bör se ut så här:
Klicka på Kontrollanten för hemvy i storyboarden och kontrollera att den har homeViewController som sin anpassade klass och Storyboard-ID under identitetsinspektören.
Gör samma sak för Image View Controller som imageViewController.
Skapa sedan en ny View Controller-klass med namnet imageViewController för att hantera det användargränssnitt som du nyss skapade.
Lägg till följande kod i kontrollantens gränssnittsdeklarationer i imageViewController.h. Se till att styra-dra från storyboard-bildvyn till dessa egenskaper för att länka de två:
@property (weak, nonatomic) IBOutlet UIImageView *myImage; @property (strong) UIImage* imagePayload;
I
imageViewController.m
lägger du till följande i slutet avviewDidload
:// Display the UI Image in UI Image View [self.myImage setImage:self.imagePayload];
I
AppDelegate.m
importerar du avbildningskontrollanten som du skapade:#import "imageViewController.h"
Lägg till ett gränssnittsavsnitt med följande deklaration:
@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
I
AppDelegate
kontrollerar du att din app registreras för tysta meddelanden iapplication: 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;
Ersätt följande implementering med för
application:didRegisterForRemoteNotificationsWithDeviceToken
att ta hänsyn till ändringarna i storyboard-användargränssnittet:// 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;
Lägg sedan till följande metoder för
AppDelegate.m
att hämta avbildningen från slutpunkten och skicka ett lokalt meddelande när hämtningen är klar. Ersätt platshållaren{backend endpoint}
med serverdelsslutpunkten: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. }
Hantera det tidigare lokala meddelandet genom att öppna bildvisningskontrollanten med
AppDelegate.m
följande metoder:// 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(); }
Kör programmet
- I XCode kör du appen på en fysisk iOS-enhet (push-meddelanden fungerar inte i simulatorn).
- I användargränssnittet för iOS-appen anger du ett användarnamn och lösenord med samma värde för autentisering och klickar på Logga in.
- Klicka på Skicka push så bör du se en avisering i appen. Om du klickar på Mer kommer du till den avbildning som du valde att inkludera i appens serverdel.
- Du kan också klicka på Skicka push och omedelbart trycka på enhetens hemknapp. Om en liten stund får du ett push-meddelande. Om du trycker på den eller klickar på Mer kommer du till din app och det omfattande bildinnehållet.