Push avanzato degli hub di notifica di AzureAzure Notification Hubs Rich Push

PanoramicaOverview

Per offrire agli utenti contenuti immediati avanzati, in un'applicazione potrebbe essere necessario effettuare il push non solo del testo normale.In order to engage users with instant rich contents, an application might want to push beyond plain text. Queste notifiche promuovono le interazioni con l'utente e presentano contenuti come URL, immagini/buoni e altro ancora.These notifications promote user interactions and present content such as urls, sounds, images/coupons, and more. Questa esercitazione è basata sull'argomento Usare Hub di notifica per inviare notifiche agli utenti e spiega come inviare notifiche push che incorporano payload (ad esempio, immagini).This tutorial builds on the Notify Users topic, and shows how to send push notifications that incorporate payloads (for example, image).

Questa esercitazione è compatibile con iOS 7 e 8.This tutorial is compatible with iOS 7 & 8.

In generale:At a high level:

  1. Il back-end dell'app:The app backend:
    • Archivia il payload avanzato (in questo caso, un'immagine) nell'archivio locale/database back-endStores the rich payload (in this case, image) in the backend database/local storage
    • Invia l'ID di questa notifica avanzata al dispositivoSends ID of this rich notification to the device
  2. L'app sul dispositivo:App on the device:
    • Contatta il back-end che richiede il payload avanzato con l'ID ricevutoContacts the backend requesting the rich payload with the ID it receives
    • Invia agli utenti notifiche sul dispositivo al termine del recupero dei dati e mostra immediatamente il payload quando gli utenti toccano per avere altre informazioniSends users notifications on the device when data retrieval is complete, and shows the payload immediately when users tap to learn more

Progetto WebAPIWebAPI Project

  1. In Visual Studio aprire il progetto AppBackend creato nell'esercitazione sulla creazione di notifiche per gli utenti .In Visual Studio, open the AppBackend project that you created in the Notify Users tutorial.
  2. Acquisire un'immagine con cui inviare una notifica agli utenti e inserirla in una cartella img nella directory del progetto.Obtain an image you would like to notify users with, and put it in an img folder in your project directory.
  3. In Esplora soluzioni fare clic su Mostra tutti i file, quindi fare clic con il pulsante destro del mouse sulla cartella e selezionare Includi nel progetto.Click Show All Files in the Solution Explorer, and right-click the folder to Include In Project.
  4. Con l'immagine selezionata, nella finestra Proprietà impostare Azione di compilazione su Risorsa incorporata.With the image selected, change its Build Action in Properties window to Embedded Resource.

  5. In Notifications.csaggiungere la seguente istruzione using:In Notifications.cs, add the following using statement:

     using System.Reflection;
    
  6. Aggiornare l'intera classe Notifications con il seguente codice.Update the whole Notifications class with the following code. Assicurarsi di sostituire i segnaposto con le credenziali dell'hub di notifica e il nome file di immagine.Be sure to replace the placeholders with your notification hub credentials and image file name.

     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}");
         }
     }
    

    Nota

    (facoltativo) Per altre informazioni su come aggiungere e ottenere le risorse del progetto, fare riferimento a Come incorporare le risorse e accedervi usando Visual C#.(optional) Refer to How to embed and access resources by using Visual C# for more information on how to add and obtain project resources.

  7. In NotificationsController.cs ridefinire NotificationsController con i frammenti di codice riportati di seguito.In NotificationsController.cs, redefine NotificationsController with the following snippets. Questo codice invia un ID notifica avanzata automatica iniziale al dispositivo e consente il recupero lato client dell'immagine:This sends an initial silent rich notification id to device and allows client-side retrieval of image:

     // 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. L'app verrà ora nuovamente distribuita in un sito Web di Azure in modo da renderla accessibile da tutti i dispositivi.Now we will re-deploy this app to an Azure Website in order to make it accessible from all devices. Fare clic con il pulsante destro del mouse sul progetto AppBackend e scegliere Pubblica.Right-click on the AppBackend project and select Publish.
  9. Selezionare un sito Web Azure come destinazione di pubblicazione.Select Azure Website as your publish target. Accedere con l'account di Azure e selezionare un sito Web nuovo o esistente, quindi prendere nota della proprietà URL di destinazione nella scheda Connessione. Si farà riferimento a quest'URL come endpoint back-end più avanti in questa esercitazione.Log in with your Azure account and select an existing or new Website, and make a note of the destination URL property in the Connection tab. We will refer to this URL as your backend endpoint later in this tutorial. Fare clic su Pubblica.Click Publish.

Modifica del progetto iOSModify the iOS project

Dopo avere modificato il back-end del app per poter inviare solo l' id di una notifica, si modificherà l'app per iOS per poter gestire tale ID e recuperare il messaggio avanzato dal back-end.Now that you have modified your app backend to send just the id of a notification, you will change your iOS app to handle that id and retrieve the rich message from your backend.

  1. Aprire il progetto iOS e abilitare le notifiche remote andando alla destinazione dell'app principale nella sezione Targets .Open your iOS project, and enable remote notifications by going to your main app target in the Targets section.
  2. Fare clic su Capabilities (Funzionalità), attivare Background Modes (Modalità sfondo), e selezionare la casella di controllo Remote Notifications (Notifiche remote).Click on Capabilities, turn on Background Modes, and check the Remote Notifications checkbox.

  3. Passare a Main.storyboarde verificare che sia presente un elemento View Controller (in questa esercitazione, Home View Controller) creato nell'esercitazione relativa all’ invio di notifiche per gli utenti .Go to Main.storyboard, and make sure you have a View Controller (refered to as Home View Controller in this tutorial) from Notify User tutorial.
  4. Aggiungere un elemento Navigation Controller allo storyboard e trascinarlo tenendo premuto CTRL sull'elemento Home View Controller per impostarlo come visualizzazione radice della navigazione.Add a Navigation Controller to your storyboard, and control-drag to Home View Controller to make it the root view of navigation. Assicurarsi che Is Initial View Controller in Attributes inspector sia selezionato solo per Navigation Controller.Make sure the Is Initial View Controller in Attributes inspector is selected for the Navigation Controller only.
  5. Aggiungere un elemento View Controller allo storyboard e aggiungere un elemento Image View.Add a View Controller to storyboard and add an Image View. Questa sarà la pagina visualizzata dagli utenti quando faranno clic sulla notifica per avere altre informazioni.This is the page users will see once they choose to learn more by clicking on the notifiication. L'aspetto dello storyboard dovrebbe essere simile al seguente:Your storyboard should look as follows:

  6. Fare clic sull'elemento Home View Controller nello storyboard e verificare che abbia homeViewController come Custom Class e Storyboard ID in Identity inspector.Click on the Home View Controller in storyboard, and make sure it has homeViewController as its Custom Class and Storyboard ID under the Identity inspector.
  7. Fare lo stesso per Image View Controller come imageViewController.Do the same for Image View Controller as imageViewController.
  8. Creare quindi una nuova classe View Controller denominata imageViewController per gestire l'interfaccia utente appena creata.Then, create a new View Controller class titled imageViewController to handle the UI you just created.
  9. In imageViewController.h, aggiungere quanto segue alle dichiarazioni di interfaccia del controller.In imageViewController.h, add the following to the controller's interface declarations. Trascinare tenendo premuto CTRL dalla visualizzazione immagine dello storyboard a queste proprietà per collegarle:Make sure to control-drag from the storyboard image view to these properties to link the two:

     @property (weak, nonatomic) IBOutlet UIImageView *myImage;
     @property (strong) UIImage* imagePayload;
    
  10. In imageViewController.m aggiungere quanto segue alla fine di viewDidload:In imageViewController.m, add the following at the end of viewDidload:

    // Display the UI Image in UI Image View
    [self.myImage setImage:self.imagePayload];
    
  11. In AppDelegate.mimportare il controller immagine creato:In AppDelegate.m, import the image controller you created:

    #import "imageViewController.h"
    
  12. Aggiungere una sezione dell'interfaccia con la seguente dichiarazione:Add an interface section with the following declaration:

    @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. In AppDelegate assicurarsi che l'app esegua la registrazione per le notifiche automatiche in application: didFinishLaunchingWithOptions:In AppDelegate, make sure your app registers for silent notifications in 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. Sostituire la seguente implementazione per application:didRegisterForRemoteNotificationsWithDeviceToken per tenere in considerazione le modifiche apportate all'interfaccia utente dello storyboard:Subsitute in the following implementation for application:didRegisterForRemoteNotificationsWithDeviceToken to take the storyboard UI changes into account:

    // 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. Aggiungere quindi i metodi seguenti ad AppDelegate.m per recuperare l'immagine dall'endpoint e inviare una notifica locale al termine del recupero.Then, add the following methods to AppDelegate.m to retrieve the image from your endpoint and send a local notification when retrieval is complete. Assicurarsi di sostituire il segnaposto {backend endpoint} con l'endpoint back-end:Make sure to substitute the placeholder {backend endpoint} with your 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.
    }
    
  16. Gestire la notifica locale precedente aprendo il controller di visualizzazione immagine in AppDelegate.m con i seguenti metodi:Handle the local notification above by opening up the image view controller in AppDelegate.m with the following methods:

    // 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();
    }
    

Eseguire l'applicazioneRun the Application

  1. In XCode eseguire l'app su un dispositivo iOS fisico (le notifiche push non funzioneranno nel simulatore).In XCode, run the app on a physical iOS device (push notifications will not work in the simulator).
  2. Nell'interfaccia utente dell'app per iOS immettere un nome utente e una password con lo stesso valore per l'autenticazione e fare clic su Log In.In the iOS app UI, enter a username and password of the same value for authentication and click Log In.
  3. Fare clic su Send push (Invia push). Verrà visualizzato un avviso nell'app.Click Send push and you should see an in-app alert. Se si fa clic su More (Altro), si passerà all'immagine che si è scelto di includere nel back-end dell'app.If you click on More, you will be brought to the image you chose to include in your app backend.
  4. È anche possibile fare clic su Send push e premere subito il pulsante home del dispositivo.You can also click Send push and immediately press the home button of your device. Dopo alcuni istanti si riceverà una notifica push.In a few moments, you will receive a push notification. Se la si tocca o si fa clic su More, si passerà all'app e al contenuto avanzato dell'immagine.If you tap on it or click More, you will be brought to your app and the rich image content.