Azure Notification Hubs – Részletes leküldés

Áttekintés

Ha azonnali tartalommal szeretné bevonni a felhasználókat, előfordulhat, hogy egy alkalmazás túl szeretne haladni az egyszerű szövegen. Ezek az értesítések elősegítik a felhasználói interakciókat, és tartalmakat, például URL-címeket, hangokat, képeket/kuponokat stb. mutatnak be. Ez az oktatóanyag a Felhasználók értesítése oktatóanyagra épül, és bemutatja, hogyan küldhet hasznos adatokat (például képeket) tartalmazó leküldéses értesítéseket.

Ez az oktatóanyag kompatibilis az iOS 7 és 8 rendszerrel.

Three screenshots: an app screen with a Send Push button, a start screen on a device, and a Windows logo with a Back button.

Magas szinten:

  1. Az alkalmazás háttérrendszere:
    • A gazdag hasznos adatokat (ebben az esetben a rendszerképet) a háttéradatbázisban/helyi tárolóban tárolja.
    • A részletes értesítés azonosítóját elküldi az eszköznek.
  2. Alkalmazás az eszközön:
    • Kapcsolatba lép a háttérrendszerrel, és kéri a részletes hasznos adatokat a kapott azonosítóval.
    • Értesítéseket küld a felhasználóknak az eszközön, amikor az adatlekérés befejeződött, és azonnal megjeleníti a hasznos adatokat, amikor a felhasználók koppintással többet megtudhatnak.

WebAPI-projekt

  1. A Visual Studio nyissa meg a Felhasználók értesítése oktatóanyagban létrehozott AppBackend projektet.

  2. Szerezzen be egy képet, amellyel értesíteni szeretné a felhasználókat, és helyezze egy img mappába a projektkönyvtárban.

  3. Kattintson a Megoldáskezelő minden fájljának megjelenítése parancsra, majd kattintson a jobb gombbal a mappára a Belefoglalás Project.

  4. Ha a kép ki van jelölve, módosítsa az összeállítási műveletet a Tulajdonságok ablakban beágyazott erőforrásra.

    Screenshot of Solution Explorer. The image file is selected, and in its Properties pane, embedded resource is listed as the build action.

  5. Adja Notifications.cshozzá a következő using utasítást:

    using System.Reflection;
    
  6. Cserélje le az Notifications osztályt a következő kódra. Ügyeljen arra, hogy a helyőrzőket cserélje le az értesítési központ hitelesítő adataira és a képfájl nevére:

    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. In NotificationsController.cs, redefine NotificationsController with the következő kód. Ez egy kezdeti csendes részletes értesítési azonosítót küld az eszköznek, és lehetővé teszi a rendszerkép ügyféloldali lekérését:

    // 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. Most helyezze újra üzembe ezt az alkalmazást egy Azure-webhelyen, hogy minden eszközről elérhető legyen. Kattintson jobb gombbal az AppBackend projektre, és válassza a Publish (Közzététel) lehetőséget.

  9. Közzétételi célként válassza ki az Azure-webhelyet . Jelentkezzen be Azure-fiókjával, válasszon ki egy meglévő vagy új webhelyet, és jegyezze fel a Cél URL-cím tulajdonságát a Kapcsolat lapon. Az oktatóanyag későbbi részében erre az URL-címre hivatkozunk háttérbeli végpontként . Válassza a Közzététel lehetőséget.

Az iOS-projekt módosítása

Most, hogy módosította az alkalmazás háttérrendszerét, hogy csak az értesítés azonosítóját küldje el, módosítsa az iOS-alkalmazást az azonosító kezelésére, és kérje le a gazdag üzenetet a háttérrendszerből:

  1. Nyissa meg az iOS-projektet, és engedélyezze a távoli értesítéseket. Ehhez lépjen a fő alkalmazáscélra a Célok szakaszban.

  2. Válassza a Képességek lehetőséget, engedélyezze a háttérmódokat, és jelölje be a Távoli értesítések jelölőnégyzetet.

    Screenshot of the iOS project showing the Capabilities screen. Background Modes is turned on, and the Remote notifications check box is selected.

  3. Nyissa meg Main.storyboard, és győződjön meg arról, hogy rendelkezik a Felhasználó értesítése oktatóanyagban szereplő nézetvezérlővel (ebben az oktatóanyagban Home View Controller néven).

  4. Vegyen fel egy navigációs vezérlőt a vágólapra, és a Control billentyűt lenyomva húzza a Kezdőlap nézet vezérlőt a navigáció gyökérnézeteként . Győződjön meg arról, hogy az Attribútumok vizsgáló kezdeti nézetvezérlője csak a navigációs vezérlőhöz van kiválasztva.

  5. Vegyen fel egy nézetvezérlőt a vágólapra, és adjon hozzá egy Képnézetet. Ez az a lap, amelyet a felhasználók látni fognak, ha úgy döntenek, hogy többet szeretnének megtudni az értesítésre kattintva. A storyboardnak a következőképpen kell kinéznie:

    Screenshot of a storyboard. Three app screens are visible: a navigation view, a home view, and an image view.

  6. Kattintson a kezdőlap nézetvezérlőre a vágólapon, és győződjön meg arról, hogy a homeViewController egyéni osztály - és storyboard-azonosítóval rendelkezik az Identitásfelügyelő alatt.

  7. Végezze el ugyanezt a képnézet-vezérlő esetében is, mint az imageViewController esetében.

  8. Ezután hozzon létre egy imageViewController nevű új Nézetvezérlő osztályt az imént létrehozott felhasználói felület kezeléséhez.

  9. Az imageViewController.h fájlban adja hozzá a következő kódot a vezérlő felületdeklarációihoz. A kettő összekapcsolásához mindenképpen húzza a vezérlőt a vágólap képnézetéből az alábbi tulajdonságokra:

    @property (weak, nonatomic) IBOutlet UIImageView *myImage;
    @property (strong) UIImage* imagePayload;
    
  10. A imageViewController.mkövetkezőt adja hozzá a következő végéhez viewDidload:

    // Display the UI Image in UI Image View
    [self.myImage setImage:self.imagePayload];
    
  11. Importálja AppDelegate.ma létrehozott képvezérlőt:

    #import "imageViewController.h"
    
  12. Adjon hozzá egy felületszakaszt a következő deklarációval:

    @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. Ellenőrizze AppDelegate, hogy az alkalmazás regisztrál-e a csendes értesítésekre a következő helyen 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. Helyettesítse be a következő implementációt application:didRegisterForRemoteNotificationsWithDeviceToken , hogy figyelembe vegye a történet felhasználói felületének változásait:

    // 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. Ezután adja hozzá a következő metódusokat AppDelegate.m a rendszerkép végpontról való lekéréséhez, és küldjön helyi értesítést a lekérés befejezésekor. Ügyeljen arra, hogy a helyőrzőt {backend endpoint} helyettesítse a háttérbeli végponttal:

    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. Az előző helyi értesítés kezeléséhez nyissa meg a képnézet-vezérlőt AppDelegate.m a következő módszerekkel:

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

Az alkalmazás futtatása

  1. Az XCode-ban futtassa az alkalmazást egy fizikai iOS-eszközön (a leküldéses értesítések nem működnek a szimulátorban).
  2. Az iOS-alkalmazás felhasználói felületén adjon meg egy azonos értékű felhasználónevet és jelszót a hitelesítéshez, majd kattintson a Bejelentkezés gombra.
  3. Kattintson a Küldés leküldésre , és megjelenik egy alkalmazáson belüli riasztás. Ha az Egyebek gombra kattint, a rendszer megjeleníti az alkalmazás háttérrendszerében szerepeltetni kívánt képet.
  4. A Küldés leküldéses gombra is kattinthat, és azonnal lenyomhatja az eszköz kezdőlap gombját. Néhány pillanat múlva leküldéses értesítést fog kapni. Ha rákoppint, vagy az Egyebek gombra kattint, a rendszer megjeleníti az alkalmazást és a gazdag képtartalmat.