Delen via


Zelfstudie: Pushmeldingen verzenden naar specifieke gebruikers met behulp van Azure Notification Hubs

In deze zelfstudie wordt uitgelegd hoe u met Azure Notification Hubs pushmeldingen kunt verzenden naar een specifieke app-gebruiker op een specifiek apparaat. Een ASP.NET WebAPI-back-end wordt gebruikt om clients te verifiëren en meldingen te genereren, zoals wordt weergegeven in het onderwerp Registreren vanuit uw app-back-end.

In deze zelfstudie voert u de volgende stappen uit:

  • Het WebAPI-project maken
  • Clients verifiëren bij de WebAPI-back-end
  • Registreren voor meldingen met behulp van de WebAPI-back-end
  • Meldingen verzenden vanuit de WebAPI-back-end
  • De nieuwe WebAPI-back-end publiceren
  • Uw iOS-app wijzigen
  • De toepassing testen

Vereisten

In deze zelfstudie wordt ervan uitgegaan dat u uw Notification Hub hebt gemaakt en geconfigureerd, zoals beschreven in Pushmeldingen verzenden naar iOS-apps met behulp van Azure Notification Hubs. Deze zelfstudie is ook de vereiste voor de zelfstudie Secure Push (iOS). Als u Mobile Apps wilt gebruiken als back-endservice, raadpleegt u Aan de slag met Push voor mobiele apps.

Het WebAPI-project maken

In de volgende secties wordt het maken van een nieuwe ASP.NET WebAPI-back-end besproken. Dit proces heeft drie hoofddoelen:

  • Clients verifiëren: er wordt een berichtenhandler toegevoegd voor het verifiëren van aanvragen van clients en het koppelen van de gebruiker aan de aanvraag.
  • Registreren voor meldingen met behulp van de WebAPI-back-end: u voegt een controller toe voor het afhandelen van nieuwe registraties voor een clientapparaat voor het ontvangen van meldingen. De naam van de geverifieerde gebruiker wordt automatisch aan de registratie toegevoegd als een tag.
  • Meldingen verzenden naar clients: u voegt een controller toe om gebruikers een manier te bieden voor het activeren van een beveiligde push naar apparaten en clients die zijn gekoppeld aan de tag.

Maak de nieuwe ASP.NET Core 6.0 web-API-back-end door de volgende acties uit te voeren:

Start Visual Studio om dit te controleren. Selecteer Extensies en updates in het menu Extra. Zoek naar NuGet Package Manager in uw versie van Visual Studio en controleer of u de meest recente versie hebt. Als uw versie niet de nieuwste versie is, verwijdert u deze en installeert u NuGet Package Manager.

Schermopname van het dialoogvenster Extensies en updates met NuGet-pakketbeheer voor het Visual Studio-pakket gemarkeerd.

Notitie

Controleer of u de Visual Studio Azure SDK voor website-implementatie hebt geïnstalleerd.

  1. Start Visual Studio of Visual Studio Express.

  2. Selecteer Server Explorer en meld u aan bij uw Azure-account. U moet zijn aangemeld om de websiteresources voor uw account te maken.

  3. Selecteer in het menu Bestand van Visual Studio de optie Nieuw>project.

  4. Voer Web-API in het zoekvak in.

  5. Selecteer de projectsjabloon ASP.NET Core Web API en selecteer Volgende.

  6. Geef in het dialoogvenster Uw nieuwe project configureren de naam AppBackend en selecteer Volgende.

  7. In het dialoogvenster Aanvullende informatie :

    • Controleer of het Framework.NET 6.0 (langetermijnondersteuning) is.
    • Controleer of het selectievakje controllers gebruiken (schakel het selectievakje uit om minimale API's te gebruiken) is ingeschakeld.
    • Schakel OpenAPI-ondersteuning inschakelen uit.
    • Selecteer Maken.

De WeatherForecast-sjabloonbestanden verwijderen

  1. Verwijder de voorbeeldbestanden WeatherForecast.cs en Controllers/WeatherForecastController.cs uit het nieuwe AppBackend-project .
  2. Open Properties\launchSettings.json.
  3. Wijzig launchUrl-eigenschappen van weatherforcast in appbackend.

Selecteer een abonnement in het venster Microsoft Azure Web App configureren en voer in de lijst App Service-plan een van de volgende acties uit:

  • Selecteer een Azure App Service plan dat u al hebt gemaakt.
  • Selecteer Een nieuw App Service-plan maken, en maak er vervolgens een.

U hebt geen database nodig voor deze zelfstudie. Nadat u uw App Service-plan hebt geselecteerd, selecteert u OK om het project te maken.

Het venster Microsoft Azure Web App configureren

Als u deze pagina voor het configureren van het App Service-plan niet ziet, gaat u door met de zelfstudie. U kunt het configureren en de app later publiceren.

Clients verifiëren bij de WebAPI-back-end

In deze sectie maakt u een nieuwe berichtenhandlerklasse met de naam AuthenticationTestHandler voor de nieuwe back-end. Deze klasse wordt afgeleid van DelegatingHandler en toegevoegd als een berichtenhandler zodat deze alle aanvragen die de back-end ontvangt, kan verwerken.

  1. Klik in Solution Explorer met de rechtermuisknop op het project AppBackend, selecteer Toevoegen en selecteer vervolgens Klasse.

  2. Geef de nieuwe klasse de naam AuthenticationTestHandler.cs en selecteer Toevoegen om de klasse te genereren. Deze klasse verifieert gebruikers met behulp van Basisverificatie om het eenvoudig te houden. Uw app kan een willekeurig verificatieschema gebruiken.

  3. Voeg in AuthenticationTestHandler.cs de volgende using-instructies toe:

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. Vervang in AuthenticationTestHandler.cs de AuthenticationTestHandler-klassedefinitie door de volgende code:

    Deze handler verifieert de aanvraag wanneer de volgende drie voorwaarden waar zijn:

    • De aanvraag bevat een autorisatieheader.
    • De aanvraag maakt gebruik van basisverificatie.
    • De gebruikersnaamtekenreeks en de wachtwoordtekenreeks zijn dezelfde tekenreeks.

    Anders wordt de aanvraag geweigerd. Deze verificatie is geen bestaande benadering op verificatie en autorisatie. Dit is slechts een eenvoudig voorbeeld voor deze zelfstudie.

    Als het aanvraagbericht is geverifieerd en geautoriseerd door AuthenticationTestHandler, wordt de basisverificatiegebruiker toegevoegd aan de huidige aanvraag in HttpContext. Gebruikersgegevens in HttpContext worden later gebruikt door een andere controller (RegisterController) om een tag toe te voegen aan de aanvraag voor meldingen van registraties.

    public class AuthenticationTestHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authorizationHeader = request.Headers.GetValues("Authorization").First();
    
            if (authorizationHeader != null && authorizationHeader
                .StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
            {
                string authorizationUserAndPwdBase64 =
                    authorizationHeader.Substring("Basic ".Length);
                string authorizationUserAndPwd = Encoding.Default
                    .GetString(Convert.FromBase64String(authorizationUserAndPwdBase64));
                string user = authorizationUserAndPwd.Split(':')[0];
                string password = authorizationUserAndPwd.Split(':')[1];
    
                if (VerifyUserAndPwd(user, password))
                {
                    // Attach the new principal object to the current HttpContext object
                    HttpContext.Current.User =
                        new GenericPrincipal(new GenericIdentity(user), new string[0]);
                    System.Threading.Thread.CurrentPrincipal =
                        System.Web.HttpContext.Current.User;
                }
                else return Unauthorized();
            }
            else return Unauthorized();
    
            return base.SendAsync(request, cancellationToken);
        }
    
        private bool VerifyUserAndPwd(string user, string password)
        {
            // This is not a real authentication scheme.
            return user == password;
        }
    
        private Task<HttpResponseMessage> Unauthorized()
        {
            var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);
            return tsc.Task;
        }
    }
    

    Notitie

    Opmerking over beveiliging: de AuthenticationTestHandler-klasse biedt geen echte verificatie. Het wordt alleen gebruikt om basisverificatie na te bootsen en is niet beveiligd. U moet een veilig verificatiemechanisme implementeren in uw productietoepassingen en -services.

  5. Als u de berichtenhandler wilt registreren, voegt u de volgende code toe aan het einde van de Register methode in het bestand Program.cs :

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. Sla uw wijzigingen op.

Registreren voor meldingen met behulp van de WebAPI-back-end

In deze sectie voegen we een nieuwe controller toe aan de WebAPI-back-end om aanvragen voor het registreren van een gebruiker en een apparaat voor meldingen af te handelen met behulp van de clientbibliotheek voor notification hubs. De controller voegt een gebruikerstag toe voor de gebruiker die door AuthenticationTestHandler is geverifieerd en gekoppeld aan HttpContext. De tag heeft de indeling van de tekenreeks, "username:<actual username>".

  1. Klik in Solution Explorer met de rechtermuisknop op het project AppBackend en selecteer vervolgens NuGet-pakketten beheren.

  2. Selecteer in het linkerdeelvenster Online en typ Microsoft.Azure.NotificationHubs in het vak Zoeken.

  3. Selecteer Microsoft Azure Notification Hubs in de lijst met resultaten en selecteer vervolgens Installeren. Voltooi de installatie en sluit vervolgens het venster Nuget Package Manager.

    Met deze actie wordt een verwijzing toegevoegd aan de Azure Notification Hubs-SDK met het Microsoft.Azure.Notification Hubs NuGet-pakket.

  4. Maak een nieuw klassebestand waarmee de verbinding met de notification hub die wordt gebruikt voor het verzenden van meldingen. Klik in Solution Explorer met de rechtermuisknop op de map Modellen en selecteer achtereenvolgens Toevoegen en Klasse. Noem de nieuwe klasse Notifications.cs en selecteer vervolgens Toevoegen om de klasse te genereren.

    Het venster Nieuw Item toevoegen

  5. Voeg in Notifications.cs de volgende using-instructie toe aan het begin van het bestand:

    using Microsoft.Azure.NotificationHubs;
    
  6. Vervang de Notifications-klassedefinitie door de volgende code en vervang de twee tijdelijke aanduidingen door de verbindingsreeks (met volledige toegang) voor uw notification hub en de naam van de hub (beschikbaar in Azure Portal):

    public class Notifications
    {
        public static Notifications Instance = new Notifications();
    
        public NotificationHubClient Hub { get; set; }
    
        private Notifications() {
            Hub = NotificationHubClient.CreateClientFromConnectionString("<your hub's DefaultFullSharedAccessSignature>",
                                                                            "<hub name>");
        }
    }
    

    Belangrijk

    Voer de naam en de DefaultListenSharedAccessSignature van uw hub in voordat u verdergaat.

  7. Maak vervolgens een nieuwe controller met de naam RegisterController. Klik in Solution Explorer met de rechtermuisknop op de map Controllers en selecteer achtereenvolgens Toevoegen en Controller.

  8. Selecteer API Controller - Leeg en selecteer vervolgens Toevoegen.

  9. Typ in het vak ControllernaamRegisterController als naam voor de nieuwe klasse en selecteer vervolgens Toevoegen.

    Het venster Controller toevoegen.

  10. Voeg in RegisterController.cs de volgende using-instructies toe:

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Voeg de volgende code in de RegisterController-klassedefinitie. In deze code voegt u een gebruikerstag toe voor de gebruiker die is gekoppeld aan HttpContext. De gebruiker is geverifieerd en gekoppeld aan HttpContext door het berichtenfilter dat u hebt toegevoegd, AuthenticationTestHandler. U kunt ook optionele controles toevoegen om te controleren of de gebruiker rechten heeft voor het registreren voor de aangevraagde tags.

    private NotificationHubClient hub;
    
    public RegisterController()
    {
        hub = Notifications.Instance.Hub;
    }
    
    public class DeviceRegistration
    {
        public string Platform { get; set; }
        public string Handle { get; set; }
        public string[] Tags { get; set; }
    }
    
    // POST api/register
    // This creates a registration id
    public async Task<string> Post(string handle = null)
    {
        string newRegistrationId = null;
    
        // make sure there are no existing registrations for this push handle (used for iOS and Android)
        if (handle != null)
        {
            var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
    
            foreach (RegistrationDescription registration in registrations)
            {
                if (newRegistrationId == null)
                {
                    newRegistrationId = registration.RegistrationId;
                }
                else
                {
                    await hub.DeleteRegistrationAsync(registration);
                }
            }
        }
    
        if (newRegistrationId == null) 
            newRegistrationId = await hub.CreateRegistrationIdAsync();
    
        return newRegistrationId;
    }
    
    // PUT api/register/5
    // This creates or updates a registration (with provided channelURI) at the specified id
    public async Task<HttpResponseMessage> Put(string id, DeviceRegistration deviceUpdate)
    {
        RegistrationDescription registration = null;
        switch (deviceUpdate.Platform)
        {
            case "mpns":
                registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "wns":
                registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "apns":
                registration = new AppleRegistrationDescription(deviceUpdate.Handle);
                break;
            case "fcm":
                registration = new FcmRegistrationDescription(deviceUpdate.Handle);
                break;
            default:
                throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    
        registration.RegistrationId = id;
        var username = HttpContext.Current.User.Identity.Name;
    
        // add check if user is allowed to add these tags
        registration.Tags = new HashSet<string>(deviceUpdate.Tags);
        registration.Tags.Add("username:" + username);
    
        try
        {
            await hub.CreateOrUpdateRegistrationAsync(registration);
        }
        catch (MessagingException e)
        {
            ReturnGoneIfHubResponseIsGone(e);
        }
    
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    // DELETE api/register/5
    public async Task<HttpResponseMessage> Delete(string id)
    {
        await hub.DeleteRegistrationAsync(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
    {
        var webex = e.InnerException as WebException;
        if (webex.Status == WebExceptionStatus.ProtocolError)
        {
            var response = (HttpWebResponse)webex.Response;
            if (response.StatusCode == HttpStatusCode.Gone)
                throw new HttpRequestException(HttpStatusCode.Gone.ToString());
        }
    }
    
  12. Sla uw wijzigingen op.

Meldingen verzenden vanuit de WebAPI-back-end

In deze sectie voegt u een nieuwe domeincontroller toe die clientapparaten een manier biedt om een melding te verzenden. De melding is gebaseerd op de gebruikersnaamtag die gebruikmaakt van de Azure Notification Hubs .NET-bibliotheek in de ASP.NET WebAPI-back-end.

  1. Maak nog een nieuwe controller met de naam NotificationsController op dezelfde manier als u RegisterController in de vorige sectie hebt gemaakt.

  2. Voeg in NotificationsController.cs de volgende using-instructies toe:

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. Voeg de volgende methode toe aan de klasse NotificationsController:

    Met deze code wordt een meldingstype verzonden die is gebaseerd op de pns-parameter (Platform Notification Service, PNS). De waarde van to_tag wordt gebruikt om de tag gebruikersnaam in te stellen in het bericht. Deze tag moet overeenkomen met een gebruikersnaamtag van een actieve notification hub-registratie. Het meldingsbericht wordt opgehaald uit de hoofdtekst van de POST-aanvraag en geformatteerd voor de doel-PNS.

    Afhankelijk van de PNS die uw ondersteunde apparaten gebruiken om meldingen te ontvangen, worden de meldingen met verschillende indelingen ondersteund. Bijvoorbeeld op Windows-apparaten kunt u een pop-upmelding met WNS gebruiken die niet rechtstreeks wordt ondersteund door een andere PNS. In een dergelijk geval moet uw back-end de melding in een ondersteunde melding indelen voor de PNS van apparaten die u wilt ondersteunen. Gebruik vervolgens de juiste API voor verzending in de NotificationHubClient-klasse.

    public async Task<HttpResponseMessage> Post(string pns, [FromBody]string message, string to_tag)
    {
        var user = HttpContext.Current.User.Identity.Name;
        string[] userTag = new string[2];
        userTag[0] = "username:" + to_tag;
        userTag[1] = "from:" + user;
    
        Microsoft.Azure.NotificationHubs.NotificationOutcome outcome = null;
        HttpStatusCode ret = HttpStatusCode.InternalServerError;
    
        switch (pns.ToLower())
        {
            case "wns":
                // Windows 8.1 / Windows Phone 8.1
                var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">" + 
                            "From " + user + ": " + message + "</text></binding></visual></toast>";
                outcome = await Notifications.Instance.Hub.SendWindowsNativeNotificationAsync(toast, userTag);
                break;
            case "apns":
                // iOS
                var alert = "{\"aps\":{\"alert\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendAppleNativeNotificationAsync(alert, userTag);
                break;
            case "fcm":
                // Android
                var notif = "{ \"data\" : {\"message\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendFcmNativeNotificationAsync(notif, userTag);
                break;
        }
    
        if (outcome != null)
        {
            if (!((outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Abandoned) ||
                (outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Unknown)))
            {
                ret = HttpStatusCode.OK;
            }
        }
    
        return Request.CreateResponse(ret);
    }
    
  4. Selecteer de toets F5 om de toepassing uit te voeren en om de juistheid van uw werk tot nu toe te controleren. De app opent een webbrowser en deze wordt weergegeven met de startpagina van ASP.NET.

De nieuwe WebAPI-back-end publiceren

U gaat de app nu implementeren op een Azure-website zodat deze toegankelijk is vanaf alle apparaten.

  1. Klik met de rechtermuisknop op het project AppBackend en selecteer Publiceren.

  2. Selecteer Microsoft Azure App Service als publicatiedoel en selecteer vervolgens \*\*Publiceren. Het venster App Service maken wordt geopend. Hier kunt u alle benodigde Azure-resources maken die nodig zijn om de ASP.NET-web-app in Azure uit te voeren.

    De tegel Microsoft Azure App Service

  3. Selecteer uw Azure-account in het venster App Service maken. Selecteer Type wijzigen>Web App. Houd de standaard Web App-naam en selecteer het Abonnement, de Resourcegroep en het App Service-plan.

  4. Selecteer Maken.

  5. Noteer de Site-URL-eigenschap in de sectie Samenvatting. Deze URL is het eindpunt van uw back-end verderop in de zelfstudie.

  6. Selecteer Publiceren.

Nadat u de wizard hebt voltooid, wordt de ASP.NET-web-app naar Azure gepubliceerd. Daarna wordt de app geopend in de standaardbrowser. Uw toepassing is zichtbaar in Azure App Services.

De URL gebruikt de naam van de web-app die u eerder hebt opgegeven, met de indeling http://< app_name.azurewebsites.net>.

Uw iOS-app wijzigen

  1. Open de app Weergave met één pagina die u hebt gemaakt in de zelfstudie Pushmeldingen verzenden naar iOS-apps met behulp van Azure Notification Hubs .

    Notitie

    In deze sectie wordt ervan uitgegaan dat uw project is geconfigureerd met een lege organisatienaam. Als dat niet het beste is, moet u de naam van uw organisatie vooraf laten gaan door alle klassennamen.

  2. Voeg in het Main.storyboard bestand de onderdelen toe die worden weergegeven in de schermopname van de objectbibliotheek.

    Storyboard bewerken in Xcode Interface Builder

    • Gebruikersnaam: een UITextField met tijdelijke tekst, Voer gebruikersnaam in, direct onder het label resultaten verzenden en beperkt tot de linker- en rechtermarges en onder het label resultaten verzenden.

    • Wachtwoord: een UITextField met tijdelijke tekst, Wachtwoord invoeren, direct onder het tekstveld gebruikersnaam en beperkt tot de linker- en rechtermarges en onder het tekstveld gebruikersnaam. Schakel de optie Beveiligde tekstinvoer in de kenmerkcontrole in onder Retoursleutel.

    • Aanmelden: een UIButton direct onder het wachtwoordtekstveld en de optie Ingeschakeld uitschakelen in de kenmerkcontrole, onder Control-Content

    • WNS: labelen en overschakelen om het verzenden van de melding Windows Notification Service in te schakelen als deze is ingesteld op de hub. Zie de zelfstudie voor Windows Aan de slag.

    • GCM: Label en schakel over om het verzenden van de melding naar Google Cloud Messaging in te schakelen als deze is ingesteld op de hub. Zie Zelfstudie voor Android Aan de slag.

    • APNS: labelen en overschakelen om het verzenden van de melding naar de Apple Platform Notification Service in te schakelen.

    • Gebruikersnaam van ontvanger:een UITextField met tijdelijke aanduiding tekst, de tag Ontvanger gebruikersnaam, direct onder het GCM-label en beperkt tot de linker- en rechtermarges en onder het GCM-label.

      Sommige onderdelen zijn toegevoegd in de zelfstudie Pushmeldingen verzenden naar iOS-apps met behulp van Azure Notification Hubs .

  3. Houd Ctrl ingedrukt van de onderdelen in de weergave naar ViewController.h en voeg deze nieuwe uitgangen toe:

    @property (weak, nonatomic) IBOutlet UITextField *UsernameField;
    @property (weak, nonatomic) IBOutlet UITextField *PasswordField;
    @property (weak, nonatomic) IBOutlet UITextField *RecipientField;
    @property (weak, nonatomic) IBOutlet UITextField *NotificationField;
    
    // Used to enable the buttons on the UI
    @property (weak, nonatomic) IBOutlet UIButton *LogInButton;
    @property (weak, nonatomic) IBOutlet UIButton *SendNotificationButton;
    
    // Used to enabled sending notifications across platforms
    @property (weak, nonatomic) IBOutlet UISwitch *WNSSwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *GCMSwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *APNSSwitch;
    
    - (IBAction)LogInAction:(id)sender;
    
  4. Voeg ViewController.hin het volgende #define toe na uw importinstructies. Vervang de <Your backend endpoint> tijdelijke aanduiding door de doel-URL die u in de vorige sectie hebt gebruikt om de back-end van uw app te implementeren. Bijvoorbeeld http://your_backend.azurewebsites.net:

    #define BACKEND_ENDPOINT @"<Your backend endpoint>"
    
  5. Maak in uw project een nieuwe Cocoa Touch-klasse met de naam RegisterClient voor interface met de ASP.NET back-end die u hebt gemaakt. Maak de klasse die wordt overgenomen van NSObject. Voeg vervolgens de volgende code toe in de RegisterClient.h:

    @interface RegisterClient : NSObject
    
    @property (strong, nonatomic) NSString* authenticationHeader;
    
    -(void) registerWithDeviceToken:(NSData*)token tags:(NSSet*)tags
        andCompletion:(void(^)(NSError*))completion;
    
    -(instancetype) initWithEndpoint:(NSString*)Endpoint;
    
    @end
    
  6. Werk in de RegisterClient.mde sectie bij @interface :

    @interface RegisterClient ()
    
    @property (strong, nonatomic) NSURLSession* session;
    @property (strong, nonatomic) NSURLSession* endpoint;
    
    -(void) tryToRegisterWithDeviceToken:(NSData*)token tags:(NSSet*)tags retry:(BOOL)retry
                andCompletion:(void(^)(NSError*))completion;
    -(void) retrieveOrRequestRegistrationIdWithDeviceToken:(NSString*)token
                completion:(void(^)(NSString*, NSError*))completion;
    -(void) upsertRegistrationWithRegistrationId:(NSString*)registrationId deviceToken:(NSString*)token
                tags:(NSSet*)tags andCompletion:(void(^)(NSURLResponse*, NSError*))completion;
    
    @end
    
  7. Vervang de @implementation sectie in RegisterClient.m door de volgende code:

    @implementation RegisterClient
    
    // Globals used by RegisterClient
    NSString *const RegistrationIdLocalStorageKey = @"RegistrationId";
    
    -(instancetype) initWithEndpoint:(NSString*)Endpoint
    {
        self = [super init];
        if (self) {
            NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
            _session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
            _endpoint = Endpoint;
        }
        return self;
    }
    
    -(void) registerWithDeviceToken:(NSData*)token tags:(NSSet*)tags
                andCompletion:(void(^)(NSError*))completion
    {
        [self tryToRegisterWithDeviceToken:token tags:tags retry:YES andCompletion:completion];
    }
    
    -(void) tryToRegisterWithDeviceToken:(NSData*)token tags:(NSSet*)tags retry:(BOOL)retry
                andCompletion:(void(^)(NSError*))completion
    {
        NSSet* tagsSet = tags?tags:[[NSSet alloc] init];
    
        NSString *deviceTokenString = [[token description]
            stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
        deviceTokenString = [[deviceTokenString stringByReplacingOccurrencesOfString:@" " withString:@""]
                                uppercaseString];
    
        [self retrieveOrRequestRegistrationIdWithDeviceToken: deviceTokenString
            completion:^(NSString* registrationId, NSError *error) {
            NSLog(@"regId: %@", registrationId);
            if (error) {
                completion(error);
                return;
            }
    
            [self upsertRegistrationWithRegistrationId:registrationId deviceToken:deviceTokenString
                tags:tagsSet andCompletion:^(NSURLResponse * response, NSError *error) {
                if (error) {
                    completion(error);
                    return;
                }
    
                NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
                if (httpResponse.statusCode == 200) {
                    completion(nil);
                } else if (httpResponse.statusCode == 410 && retry) {
                    [self tryToRegisterWithDeviceToken:token tags:tags retry:NO andCompletion:completion];
                } else {
                    NSLog(@"Registration error with response status: %ld", (long)httpResponse.statusCode);
    
                    completion([NSError errorWithDomain:@"Registration" code:httpResponse.statusCode
                                userInfo:nil]);
                }
    
            }];
        }];
    }
    
    -(void) upsertRegistrationWithRegistrationId:(NSString*)registrationId deviceToken:(NSData*)token
                tags:(NSSet*)tags andCompletion:(void(^)(NSURLResponse*, NSError*))completion
    {
        NSDictionary* deviceRegistration = @{@"Platform" : @"apns", @"Handle": token,
                                                @"Tags": [tags allObjects]};
        NSData* jsonData = [NSJSONSerialization dataWithJSONObject:deviceRegistration
                            options:NSJSONWritingPrettyPrinted error:nil];
    
        NSLog(@"JSON registration: %@", [[NSString alloc] initWithData:jsonData
                                            encoding:NSUTF8StringEncoding]);
    
        NSString* endpoint = [NSString stringWithFormat:@"%@/api/register/%@", _endpoint,
                                registrationId];
        NSURL* requestURL = [NSURL URLWithString:endpoint];
        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL];
        [request setHTTPMethod:@"PUT"];
        [request setHTTPBody:jsonData];
        NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@",
                                                self.authenticationHeader];
        [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"];
        [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
        NSURLSessionDataTask* dataTask = [self.session dataTaskWithRequest:request
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
        {
            if (!error)
            {
                completion(response, error);
            }
            else
            {
                NSLog(@"Error request: %@", error);
                completion(nil, error);
            }
        }];
        [dataTask resume];
    }
    
    -(void) retrieveOrRequestRegistrationIdWithDeviceToken:(NSString*)token
                completion:(void(^)(NSString*, NSError*))completion
    {
        NSString* registrationId = [[NSUserDefaults standardUserDefaults]
                                    objectForKey:RegistrationIdLocalStorageKey];
    
        if (registrationId)
        {
            completion(registrationId, nil);
            return;
        }
    
        // request new one & save
        NSURL* requestURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/api/register?handle=%@",
                                _endpoint, token]];
        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL];
        [request setHTTPMethod:@"POST"];
        NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@",
                                                self.authenticationHeader];
        [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"];
    
        NSURLSessionDataTask* dataTask = [self.session dataTaskWithRequest:request
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
        {
            NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
            if (!error && httpResponse.statusCode == 200)
            {
                NSString* registrationId = [[NSString alloc] initWithData:data
                    encoding:NSUTF8StringEncoding];
    
                // remove quotes
                registrationId = [registrationId substringWithRange:NSMakeRange(1,
                                    [registrationId length]-2)];
    
                [[NSUserDefaults standardUserDefaults] setObject:registrationId
                    forKey:RegistrationIdLocalStorageKey];
                [[NSUserDefaults standardUserDefaults] synchronize];
    
                completion(registrationId, nil);
            }
            else
            {
                NSLog(@"Error status: %ld, request: %@", (long)httpResponse.statusCode, error);
                if (error)
                    completion(nil, error);
                else {
                    completion(nil, [NSError errorWithDomain:@"Registration" code:httpResponse.statusCode
                                userInfo:nil]);
                }
            }
        }];
        [dataTask resume];
    }
    
    @end
    

    Deze code implementeert de logica die wordt uitgelegd in het richtlijnenartikel Registreren vanuit uw app-back-end met behulp van NSURLSession om REST-aanroepen uit te voeren naar uw app-back-end en NSUserDefaults om de registrationId die wordt geretourneerd door de Notification Hub lokaal op te slaan.

    Voor deze klasse moet de eigenschap authorizationHeader zijn ingesteld om goed te kunnen werken. Deze eigenschap wordt ingesteld door de ViewController klasse na de aanmelding.

  8. Voeg ViewController.hin een #import -instructie toe voor RegisterClient.h. Voeg vervolgens een declaratie toe voor het apparaattoken en een verwijzing naar een RegisterClient exemplaar in de @interface sectie:

    #import "RegisterClient.h"
    
    @property (strong, nonatomic) NSData* deviceToken;
    @property (strong, nonatomic) RegisterClient* registerClient;
    
  9. Voeg in ViewController.m een declaratie van een persoonlijke methode toe in de @interface sectie:

    @interface ViewController () <UITextFieldDelegate, NSURLConnectionDataDelegate, NSXMLParserDelegate>
    
    // create the Authorization header to perform Basic authentication with your app back-end
    -(void) createAndSetAuthenticationHeaderWithUsername:(NSString*)username
                    AndPassword:(NSString*)password;
    
    @end
    

    Notitie

    Het volgende codefragment is geen beveiligd verificatieschema. Vervang de implementatie van de createAndSetAuthenticationHeaderWithUsername:AndPassword: door uw specifieke verificatiemechanisme dat een verificatietoken genereert dat moet worden gebruikt door de clientklasse voor registratie, bijvoorbeeld OAuth, Active Directory.

  10. Voeg vervolgens in de @implementation sectie van de volgende code toe, waarmee de implementatie wordt toegevoegd voor het instellen van ViewController.mhet apparaattoken en de verificatieheader.

    -(void) setDeviceToken: (NSData*) deviceToken
    {
        _deviceToken = deviceToken;
        self.LogInButton.enabled = YES;
    }
    
    -(void) createAndSetAuthenticationHeaderWithUsername:(NSString*)username
                    AndPassword:(NSString*)password;
    {
        NSString* headerValue = [NSString stringWithFormat:@"%@:%@", username, password];
    
        NSData* encodedData = [[headerValue dataUsingEncoding:NSUTF8StringEncoding] base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
    
        self.registerClient.authenticationHeader = [[NSString alloc] initWithData:encodedData
                                                    encoding:NSUTF8StringEncoding];
    }
    
    -(BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        [textField resignFirstResponder];
        return YES;
    }
    

    U ziet hoe de knop Aanmelden wordt ingeschakeld als u het apparaattoken instelt. Dit komt doordat als onderdeel van de aanmeldingsactie de weergavecontroller zich registreert voor pushmeldingen bij de back-end van de app. U wilt niet dat de actie Aanmelden toegankelijk is totdat het apparaattoken correct is ingesteld. U kunt de aanmelding loskoppelen van de pushregistratie zolang de eerste plaatsvindt voordat de laatste plaatsvindt.

  11. Gebruik in ViewController.m de volgende codefragmenten om de actiemethode voor de knop Aanmelden te implementeren en een methode om het meldingsbericht te verzenden met behulp van de back-end ASP.NET.

    - (IBAction)LogInAction:(id)sender {
        // create authentication header and set it in register client
        NSString* username = self.UsernameField.text;
        NSString* password = self.PasswordField.text;
    
        [self createAndSetAuthenticationHeaderWithUsername:username AndPassword:password];
    
        __weak ViewController* selfie = self;
        [self.registerClient registerWithDeviceToken:self.deviceToken tags:nil
            andCompletion:^(NSError* error) {
            if (!error) {
                dispatch_async(dispatch_get_main_queue(),
                ^{
                    selfie.SendNotificationButton.enabled = YES;
                    [self MessageBox:@"Success" message:@"Registered successfully!"];
                });
            }
        }];
    }
    
    - (void)SendNotificationASPNETBackend:(NSString*)pns UsernameTag:(NSString*)usernameTag
                Message:(NSString*)message
    {
        NSURLSession* session = [NSURLSession
            sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil
            delegateQueue:nil];
    
        // Pass the pns and username tag as parameters with the REST URL to the ASP.NET backend
        NSURL* requestURL = [NSURL URLWithString:[NSString
            stringWithFormat:@"%@/api/notifications?pns=%@&to_tag=%@", BACKEND_ENDPOINT, pns,
            usernameTag]];
    
        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL];
        [request setHTTPMethod:@"POST"];
    
        // Get the mock authenticationheader from the register client
        NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@",
            self.registerClient.authenticationHeader];
        [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"];
    
        //Add the notification message body
        [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding]];
    
        // Execute the send notification REST API on the ASP.NET Backend
        NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
        {
            NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
            if (error || httpResponse.statusCode != 200)
            {
                NSString* status = [NSString stringWithFormat:@"Error Status for %@: %d\nError: %@\n",
                                    pns, httpResponse.statusCode, error];
                dispatch_async(dispatch_get_main_queue(),
                ^{
                    // Append text because all 3 PNS calls may also have information to view
                    [self.sendResults setText:[self.sendResults.text stringByAppendingString:status]];
                });
                NSLog(status);
            }
    
            if (data != NULL)
            {
                xmlParser = [[NSXMLParser alloc] initWithData:data];
                [xmlParser setDelegate:self];
                [xmlParser parse];
            }
        }];
        [dataTask resume];
    }
    
  12. Werk de actie voor de knop Melding verzenden bij om de back-end van de ASP.NET te gebruiken en te verzenden naar alle PNS's die zijn ingeschakeld door een switch.

    - (IBAction)SendNotificationMessage:(id)sender
    {
        //[self SendNotificationRESTAPI];
        [self SendToEnabledPlatforms];
    }
    
    -(void)SendToEnabledPlatforms
    {
        NSString* json = [NSString stringWithFormat:@"\"%@\"",self.notificationMessage.text];
    
        [self.sendResults setText:@""];
    
        if ([self.WNSSwitch isOn])
            [self SendNotificationASPNETBackend:@"wns" UsernameTag:self.RecipientField.text Message:json];
    
        if ([self.GCMSwitch isOn])
            [self SendNotificationASPNETBackend:@"gcm" UsernameTag:self.RecipientField.text Message:json];
    
        if ([self.APNSSwitch isOn])
            [self SendNotificationASPNETBackend:@"apns" UsernameTag:self.RecipientField.text Message:json];
    }
    
  13. Voeg in de ViewDidLoad functie het volgende toe om het RegisterClient exemplaar te instantiëren en de gemachtigde voor uw tekstvelden in te stellen.

    self.UsernameField.delegate = self;
    self.PasswordField.delegate = self;
    self.RecipientField.delegate = self;
    self.registerClient = [[RegisterClient alloc] initWithEndpoint:BACKEND_ENDPOINT];
    
  14. Verwijder nu in AppDelegate.malle inhoud van de methode application:didRegisterForPushNotificationWithDeviceToken: en vervang deze door het volgende (om ervoor te zorgen dat de weergavecontroller het meest recente apparaattoken bevat dat is opgehaald uit APNs):

    // Add import to the top of the file
    #import "ViewController.h"
    
    - (void)application:(UIApplication *)application
                didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    {
        ViewController* rvc = (ViewController*) self.window.rootViewController;
        rvc.deviceToken = deviceToken;
    }
    
  15. Controleer ten slotte in AppDelegate.mof u de volgende methode hebt:

    - (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo {
        NSLog(@"%@", userInfo);
        [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]];
    }
    

De toepassing testen

  1. Voer in XCode de app uit op een fysiek iOS-apparaat (pushmeldingen werken niet in de simulator).

  2. Voer in de gebruikersinterface van de iOS-app dezelfde waarde in voor zowel gebruikersnaam als wachtwoord. Klik vervolgens op Aanmelden.

    iOS-testtoepassing

  3. Als het goed is, ziet u een pop-upvenster met de melding dat de registratie is geslaagd. Klik op OK.

    iOS-testmelding weergegeven

  4. Voer in het tekstveld *Recipient username tag de tag gebruikersnaam in die is gebruikt voor de registratie vanaf een ander apparaat.

  5. Voer een meldingsbericht in en klik op Melding verzenden. Alleen de apparaten met een registratie met de gebruikersnaamtag van de ontvanger ontvangen het meldingsbericht. Deze wordt alleen naar deze gebruikers verzonden.

    Melding met tag voor iOS-test

Volgende stappen

In deze zelfstudie hebt u geleerd hoe u pushmeldingen kunt verzenden naar specifieke gebruikers door een tag te koppelen aan hun registraties. Als u wilt weten hoe u locatiegebaseerde pushmeldingen kunt verzenden, gaat u verder met de volgende zelfstudie: