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.

Tre skärmbilder: en appskärm med knappen Skicka push, en startskärm på en enhet och en Windows-logotyp med en bakåtknapp.

På hög nivå:

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

  1. I Visual Studio öppnar du det AppBackend-projekt som du skapade i självstudien Meddela användare .

  2. Hämta en avbildning som du vill meddela användare med och placera den i en img-mapp i projektkatalogen.

  3. Klicka på Visa alla filer i Solution Explorer och högerklicka på mappen som ska inkluderas i projektet.

  4. När avbildningen har valts ändrar du dess byggåtgärd i fönstret Egenskaper till Inbäddad resurs.

    Skärmbild av Solution Explorer. Avbildningsfilen är markerad och i fönstret Egenskaper visas den inbäddade resursen som byggåtgärden.

  5. I Notifications.cslägger du till följande using -instruktion:

    using System.Reflection;
    
  6. 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}");
        }
    }
    
  7. I NotificationsController.csomdefinierar du NotificationsController 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);
    }
    
  8. 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.

  9. 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:

  1. Öppna ditt iOS-projekt och aktivera fjärrmeddelanden genom att gå till huvudappens mål i avsnittet Mål .

  2. Välj Funktioner, aktivera bakgrundslägen och markera kryssrutan Fjärrmeddelanden .

    Skärmbild av iOS-projektet som visar skärmen Funktioner. Bakgrundslägen är aktiverade och kryssrutan Fjärrmeddelanden är markerad.

  3. Öppna Main.storyboardoch kontrollera att du har en vykontrollant (kallas styrenhet för hemvy i den här självstudien) från självstudien Meddela användare .

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

  5. 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:

    Skärmbild av en storyboard. Tre appskärmar är synliga: en navigeringsvy, en startvy och en bildvy.

  6. Klicka på Kontrollanten för hemvy i storyboarden och kontrollera att den har homeViewController som sin anpassade klass och Storyboard-ID under identitetsinspektören.

  7. Gör samma sak för Image View Controller som imageViewController.

  8. Skapa sedan en ny View Controller-klass med namnet imageViewController för att hantera det användargränssnitt som du nyss skapade.

  9. 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;
    
  10. I imageViewController.mlägger du till följande i slutet av viewDidload:

    // Display the UI Image in UI Image View
    [self.myImage setImage:self.imagePayload];
    
  11. I AppDelegate.mimporterar du avbildningskontrollanten som du skapade:

    #import "imageViewController.h"
    
  12. 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
    
  13. I AppDelegatekontrollerar du att din app registreras för tysta meddelanden i 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;
    
  14. 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;
    
  15. 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.
    }
    
  16. 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

  1. I XCode kör du appen på en fysisk iOS-enhet (push-meddelanden fungerar inte i simulatorn).
  2. 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.
  3. 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.
  4. 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.