Oktatóanyag: Leküldéses értesítések küldése adott felhasználóknak az Azure Notification Hubs használatával

Az oktatóanyag bemutatja, hogy hogyan küldhetők leküldéses értesítések adott alkalmazásfelhasználónak, adott eszközre az Azure Notification Hubs használatával. A ASP.NET WebAPI-háttérrendszer az ügyfelek hitelesítésére és értesítések létrehozására szolgál, ahogyan az alkalmazás háttérrendszeréből való regisztráció című útmutatóban látható.

Ebben az oktatóanyagban a következő lépéseket hajtja végre:

  • A WebAPI-projekt létrehozása
  • Ügyfelek hitelesítése a WebAPI háttérrendszeren
  • Regisztráció értesítésekre a WebAPI háttérrendszer használatával
  • Értesítések küldése a WebAPI háttérrendszerről
  • Az új WebAPI háttérrendszer közzététele
  • Az iOS-alkalmazás módosítása
  • Az alkalmazás tesztelése

Előfeltételek

Ez az oktatóanyag feltételezi, hogy létrehozta és konfigurálta az értesítési központot az Azure Notification Hubs használatával leküldéses értesítések küldése iOS-alkalmazásokba című szakaszban leírtak szerint. Ez az oktatóanyag a Biztonságos leküldés (iOS) oktatóanyag előfeltétele is. Ha a Mobile Apps szolgáltatást szeretné háttérszolgáltatásként használni, tekintse meg a Mobile Apps Első lépések a Leküldéses szolgáltatással.

A WebAPI-projekt létrehozása

Az alábbi szakaszok az új ASP.NET WebAPI hátterrendszer létrehozását ismertetik. E folyamat három fő célja:

  • Ügyfelek hitelesítése: Az ügyfélkérések hitelesítéséhez és a kérés adott felhasználóhoz való hozzárendeléséhez egy üzenetkezelőt fog hozzáadni a rendszerhez.
  • Regisztrálás értesítésekre a WebAPI háttérrendszer használatával: Annak érdekében, hogy az ügyféleszközön értesítéseket lehessen fogadni, egy vezérlőt fog hozzáadni az új regisztrációk kezeléséhez. A rendszer címke formájában automatikusan hozzáadja a hitelesített felhasználó nevét a regisztrációhoz.
  • Értesítések küldése az ügyfeleknek: Egy vezérlőt is hozzá fog adni annak érdekében, hogy a felhasználók biztonságos leküldést indíthassanak az eszközökre és a címkéhez társított ügyfelek számára.

Hozza létre az új ASP.NET Core 6.0 webes API-háttérrendszert a következő műveletek végrehajtásával:

Az ellenőrzéshez indítsa el a Visual Studiót. Az Eszközök menüben válassza a Bővítmények és frissítések pontot. Keresse meg az Ön által használt Visual Studio-verzióhoz tartozó NuGet-csomagkezelőt, és ellenőrizze, hogy a legfrissebb verzió van-e telepítve a gépén. Ha nem a legfrissebb verzió van telepítve a gépén, távolítsa el, és telepítse újra a NuGet-csomagkezelőt.

Screenshot of the Extensions and Updates dialog box with the NuGet Package manage for Visual Studios package highlighted.

Megjegyzés

Győződjön meg arról, hogy telepítette a webhely üzembe helyezéséhez szükséges Visual Studio Azure SDK-t.

  1. Indítsa el a Visual Studiót vagy a Visual Studio Expresst.

  2. Kattintson a Server Explorer (Kiszolgálókezelő) elemre, és jelentkezzen be az Azure-fiókjába. Be kell jelentkeznie ahhoz, hogy a fiókban létrehozhassa a webhelyerőforrásokat.

  3. Visual Studio Fájl menüjében válassza az Új>Project lehetőséget.

  4. Írja be a webes API-t a keresőmezőbe.

  5. Válassza ki a ASP.NET Core Webes API-projektsablont, és válassza a Tovább gombot.

  6. Az új projekt konfigurálása párbeszédpanelen nevezze el a projektet AppBackend néven, és válassza a Tovább gombot.

  7. A További információk párbeszédpanelen:

    • Győződjön meg arról, hogy a keretrendszer.NET 6.0 (hosszú távú támogatás).
    • Ellenőrizze, hogy be van-e jelölve a Vezérlők használata jelölőnégyzet (törölje a jelölést a minimális API-k használatához).
    • Törölje az OpenAPI-támogatás engedélyezésének jelölését.
    • Válassza a Létrehozás lehetőséget.

A WeatherForecast sablonfájljainak eltávolítása

  1. Távolítsa el a WeatherForecast.cs és a Controllers/WeatherForecastController.cs példafájlokat az új AppBackend projektből.
  2. Nyissa meg a Properties\launchSettings.json fájlt.
  3. A launchUrl tulajdonságainak módosítása weatherforcastrólappbackendre.

A Configure Microsoft Azure Web App (Microsoft Azure-webalkalmazás konfigurálása) ablakban válasszon ki egy előfizetést, majd az App Service plan (App Service-csomag) listában végezze el az alábbi műveletek valamelyikét:

  • Válasszon ki egy már létrehozott Azure App Service csomagot.
  • Válassza a Create a new app service plan (Új App Service-csomag létrehozása) lehetőséget is, és hozzon létre egy új csomagot.

Az oktatóanyag elvégzéséhez nincs szükség adatbázisra. Az App Service-csomag kiválasztása után kattintson az OK gombra a projekt létrehozásához.

The Configure Microsoft Azure Web App window

Ha nem látja ezt a lapot az App Service-csomag konfigurálásához, folytassa az oktatóanyaggal. Ezt később is konfigurálhatja az alkalmazás közzétételekor.

Ügyfelek hitelesítése a WebAPI háttérrendszeren

Ebben a szakaszban egy új, AuthenticationTestHandler nevű üzenetkezelő-osztályt fog létrehozni az új háttérrendszer számára. A rendszer ezt az osztályt a DelegatingHandler kezelőből származtatja, és üzenetkezelőként adja hozzá, így az képes a háttérrendszerhez beérkező összes kérés feldolgozására.

  1. A Solution Explorer (Megoldáskezelő) ablakában kattintson a jobb gombbal az AppBackend projektre, válassza az Add (Hozzáadás) parancsot, majd a Class (Osztály) elemet.

  2. Nevezze el az új osztályt AuthenticationTestHandler.cs néven, majd kattintson az Add (Hozzáadás) gombra az osztály létrehozásához. Az egyszerűség kedvéért a rendszer ezt az osztályt fogja használni a felhasználók alapszintű hitelesítéséhez. Az alkalmazás bármilyen hitelesítési séma használatára képes.

  3. Az AuthenticationTestHandler.cs osztályban adja hozzá a következő using-utasításokat:

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. Az AuthenticationTestHandler.cs osztályban cserélje le az AuthenticationTestHandler osztálydefiníciót az alábbi kódra:

    A kezelő akkor engedélyezi a kérést, ha teljesül a következő három feltétel:

    • A kérés tartalmaz engedélyezési fejlécet.
    • A kérés alapszintű hitelesítést használ.
    • A felhasználónév és a jelszó sztring azonos.

    Ellenkező esetben a kérést a rendszer elutasítja. Ez nem egy valós hitelesítési és engedélyezési megközelítés, csak egy egyszerű példa ehhez az oktatóanyaghoz.

    Ha az AuthenticationTestHandler hitelesíti és engedélyezi a kérésüzenetet, az alapszintű hitelesítést használó felhasználót a rendszer hozzákapcsolja az aktuális kéréshez a HttpContext felületén. A HttpContext felhasználói adatait a későbbiekben egy másik vezérlő (RegisterController) fogja használni egy címke az értesítésregisztrációs kéréshez való hozzáadásához.

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

    Megjegyzés

    Biztonsági megjegyzés: Az AuthenticationTestHandler osztály nem biztosít valós hitelesítést. A rendszer azt csak az alapszintű hitelesítés utánzására használja, és nem tekinthető biztonságosnak. Az éles alkalmazásokban és szolgáltatásokban implementálnia kell egy biztonságos hitelesítési mechanizmust.

  5. Az üzenetkezelő regisztrálásához adja hozzá a következő kódot a Register metódus végén a Program.cs fájlban:

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. Mentse a módosításokat.

Regisztráció értesítésekre a WebAPI háttérrendszer használatával

Ebben a szakaszban egy új vezérlőt fog hozzáadni a WebAPI háttérrendszerhez a felhasználók és az eszközök értesítés-regisztrációs kéréseinek kezeléséhez az értesítési központ ügyfélkönyvtárával. A vezérlő hozzáad egy felhasználói címkét a hitelesített és az AuthenticationTestHandler által a HttpContext elemhez kapcsolt felhasználóhoz. A címke "username:<actual username>" sztringformátumú lesz.

  1. A Solution Explorer (Megoldáskezelő) ablakában kattintson a jobb gombbal az AppBackend projektre, majd kattintson a Manage NuGet Packages (NuGet-csomagok kezelése) parancsra.

  2. A bal oldali ablaktáblán válassza az Online elemet, majd a keresőmezőbe írja be a Microsoft.Azure.NotificationHubs kifejezést.

  3. Az eredmények listájából válassza ki a Microsoft Azure Notification Hubs elemet, majd az Install (Telepítés) lehetőséget. Fejezze be a telepítést, majd zárja be a NuGet-csomagkezelő ablakát.

    Ez a művelet hozzáad egy, az Azure Notification Hubs SDK-ra mutató hivatkozást a Microsoft.Azure.Notification Hubs NuGet-csomag használatával.

  4. Hozzon létre egy új osztályfájlt, amely az értesítések küldésére használt értesítési központtal való kapcsolatot jelöli. A Solution Explorer (Megoldáskezelő) ablakában kattintson a jobb gombbal a Models (Modellek) mappára, kattintson az Add (Hozzáadás) parancsra, majd kattintson a Class (Osztály) gombra. Nevezze el az új osztályt Notifications.cs néven, majd kattintson az Add (Hozzáadás) gombra az osztály létrehozásához.

    The Add New Item window

  5. Adja hozzá a következő using-utasítást a Notifications.cs fájl elejéhez:

    using Microsoft.Azure.NotificationHubs;
    
  6. Cserélje le a Notifications osztálydefiníciót a következő kódra, a két helyőrzőt pedig az értesítési központ kapcsolati sztringjére (teljes hozzáféréssel) és a központ nevére (az Azure Portalon érhető el):

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

    Fontos

    A továbblépés előtt adja meg a központ nevét és DefaultFullSharedAccessSignature értékét.

  7. A következő lépésben hozzon létre egy új vezérlőt RegisterController néven. A Solution Explorer (Megoldáskezelő) ablakában kattintson a jobb gombbal a Controllers (Vezérlők) mappára, kattintson az Add (Hozzáadás) parancsra, majd kattintson a Controller (Vezérlő) gombra.

  8. Válassza az API Controller – Üres lehetőséget, majd a Hozzáadás lehetőséget.

  9. A Controller name (Vezérlő neve) mezőben nevezze el az új osztályt RegisterController néven, majd kattintson az Add (Hozzáadás) gombra.

    The Add Controller window.

  10. Adja hozzá a következő using-utasításokat a RegisterController.cs fájlhoz:

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Adja hozzá a következő kódot a(z) RegisterController osztálydefiníciójához: Ebben a kódban felhasználói címkét fog hozzáadni a HttpContexthez csatolt felhasználóhoz. A felhasználó hitelesítését és a HttpContexthez való csatolását az Ön által hozzáadott üzenetszűrő (AuthenticationTestHandler) végezte. További választható ellenőrzéseket is hozzáadhat, amelyekkel ellenőrizheti, hogy a felhasználó jogosult-e a kért címkékre történő regisztráláshoz.

    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. Mentse a módosításokat.

Értesítések küldése a WebAPI háttérrendszerről

Ebben a szakaszban egy új vezérlőt ad hozzá, amely értesítés küldését teszi lehetővé az ügyféleszközök számára. A rendszer az értesítést az ASP.NET WebAPI-háttérrendszeren lévő Azure Notification Hubs .NET Libraryt használó felhasználónév-címke alapján hozza létre.

  1. Hozzon létre egy másik új, NotificationsController nevű vezérlőt. Ennek során ugyanúgy járjon el, mint az előző szakaszban a RegisterController vezérlő esetében.

  2. Adja hozzá a következő using-utasításokat a NotificationsController.cs fájlhoz:

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. Adja hozzá a következő metódust a NotificationsController osztályhoz:

    Ez a kód egy értesítéstípust fog küldeni a platformértesítési szolgáltatás (PNS) pns paramétere alapján. A(z) to_tag értékét a rendszer az üzenet felhasználónév-címkéjének beállítására használja. A címkének egyeznie kell egy aktív értesítésiközpont-regisztráció felhasználónév-címkéjével. Az értesítési üzenetet a rendszer a POST-kérés törzséből nyeri ki, és a cél PNS-nek megfelelően formázza.

    A támogatott eszközök által az értesítések fogadására használt PNS-től függően az értesítések különböző formátumok használatával támogatottak. Windows rendszerű eszközökön például használhat bejelentési értesítéseket a WNS formátummal, amelyet egy másik PNS nem támogat közvetlenül. Ebben az esetben a háttérrendszernek a támogatni kívánt eszközök PNS-e által támogatott formátum szerint kell formáznia az értesítést. Ezt követően használja a megfelelő küldési API-t a NotificationHubClient osztályon.

    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. Nyomja le az F5 billentyűt az alkalmazás futtatásához, valamint eddigi munkája pontosságának ellenőrzéséhez. Az alkalmazás megnyit egy webböngészőt, amelyen az ASP.NET kezdőlapja jelenik meg.

Az új WebAPI háttérrendszer közzététele

A következőkben üzembe fogja helyezni ezt az alkalmazást egy Azure-webhelyen, hogy minden eszközről elérhető legyen.

  1. Kattintson a jobb gombbal az AppBackend projektre, és válassza a Publish (Közzététel) lehetőséget.

  2. Közzétételi célként válassza a Microsoft Azure App Service lehetőséget, majd kattintson a \*\*Publish (Közzététel) gombra. Ekkor megnyílik a Create App Service (App Service létrehozása) ablak. Itt létrehozhatja az összes, az ASP.NET-webalkalmazás Azure-ban való futtatásához szükséges Azure-erőforrást.

    The Microsoft Azure App Service tile

  3. A Create App Service (App Service létrehozása) ablakban válassza ki az Azure-fiókját. Válassza a Change TypeWeb App (Típuswebalkalmazás>módosítása) lehetőséget. Tartsa meg az alapértelmezett webalkalmazásnevet, majd válassza a Subscription (Előfizetés), Resource Group (Erőforráscsoport) és App Service Plan (App Service-csomag) elemeket.

  4. Válassza a Létrehozás lehetőséget.

  5. Jegyezze fel a Summary (Összegzés) szakaszban lévő Site URL (Webhely URL-címe) tulajdonságot. Ezt az URL-címet az oktatóanyag későbbi részében fogja használni háttérvégpontként.

  6. Válassza a Közzététel lehetőséget.

Miután a varázsló befejeződött, közzéteszi az ASP.NET-webalkalmazást az Azure-on, majd megnyitja azt az alapértelmezett böngészőben. Az alkalmazását az Azure App Servicesben tekintheti meg.

Az URL-cím a korábban megadott webalkalmazás-nevet használja http://< app_name.azurewebsites.net> formátumban.

Az iOS-alkalmazás módosítása

  1. Nyissa meg a Leküldéses értesítések küldése iOS-alkalmazásokba az Azure Notification Hubs oktatóanyagával létrehozott egyoldalas nézetalkalmazást.

    Megjegyzés

    Ez a szakasz feltételezi, hogy a projekt üres szervezetnévvel van konfigurálva. Ha nem, a szervezet nevét az összes osztálynévre fel kell függesztetnie.

  2. A fájlban Main.storyboard adja hozzá a képernyőképen látható összetevőket az objektumtárból.

    Edit storyboard in Xcode interface builder

    • Felhasználónév: Egy helyőrző szöveggel rendelkező UITextField, írja be a felhasználónevet, közvetlenül az eredmények küldése címke alatt, a bal és jobb margókra korlátozva, valamint a küldési eredmények címkéje alatt.

    • Jelszó: Egy helyőrző szöveggel rendelkező UITextField, írja be a jelszót, közvetlenül a felhasználónév szövegmezője alatt, a bal és jobb margókra korlátozva, valamint a felhasználónév szövegmezője alatt. Ellenőrizze a Biztonságos szövegbevitel lehetőséget az Attribútumfelügyelő Visszatérési kulcs területén.

    • Bejelentkezés: A jelszó szövegmezője alatt közvetlenül felcímkézett UIButton, és törölje az Attribútumfelügyelő Engedélyezett jelölőnégyzetének jelölését a Control-Content területen.

    • WNS: Címkézzen és váltson úgy, hogy engedélyezze az értesítés küldését Windows értesítési szolgáltatásnak, ha az a központban van beállítva. Tekintse meg a Windows Első lépések oktatóanyagot.

    • GCM: Címkézés és váltás az értesítés Google Cloud Messaging szolgáltatásba való küldésének engedélyezéséhez, ha az már be van állítva a központban. Tekintse meg az Android Első lépések oktatóanyagát.

    • APNS: Címke és váltás az értesítés Apple Platform Notification Service-nek való küldéséhez.

    • Címzett felhasználóneve:Egy helyőrző szöveggel ellátott UITextField mező, a címzett felhasználónév címkéje, közvetlenül a GCM-címke alatt, a bal és jobb margókra korlátozva, valamint a GCM-címke alatt.

      Az Azure Notification Hubs oktatóanyaga néhány összetevőt tartalmazott a Leküldéses értesítések küldése iOS-alkalmazásokba című oktatóanyagban.

  3. A nézetben ViewController.h lévő összetevőkből a Ctrl billentyű lenyomásával felveheti az alábbi új aljzatokat:

    @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. Adja ViewController.hhozzá a következőt #define az importálási utasítások után. Helyettesítse be a <Your backend endpoint> helyőrzőt az előző szakaszban az alkalmazás háttérrendszerének üzembe helyezéséhez használt cél URL-címmel. Például http://your_backend.azurewebsites.net:

    #define BACKEND_ENDPOINT @"<Your backend endpoint>"
    
  5. A projektben hozzon létre egy új Cocoa Touch-osztályt, amely a létrehozott ASP.NET háttérrendszerrel való interfészhez van elnevezveRegisterClient. Hozza létre a következőtől NSObjectöröklő osztályt: . Ezután adja hozzá a következő kódot a következőhez 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. RegisterClient.mA szakaszban frissítse a szakaszt@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. Cserélje le a @implementation RegisterClient.m szakaszt a következő kódra:

    @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
    

    Ez a kód implementálja az útmutatóban ismertetett logikát, amely az alkalmazás háttérrendszeréből történő regisztrációt az NSURLSession használatával hajtja végre az alkalmazás háttérrendszeréhez irányuló REST-hívások végrehajtásához, az NSUserDefaults pedig helyileg tárolja az értesítési központ által visszaadott regisztrációs azonosítót.

    Ennek az osztálynak a tulajdonságát authorizationHeader be kell állítani a megfelelő működéshez. Ezt a tulajdonságot az ViewController osztály állítja be a bejelentkezés után.

  8. In ViewController.h, add a #import statement for RegisterClient.h. Ezután adjon hozzá egy deklarációt az eszköz jogkivonatához, és hivatkozzon egy RegisterClient példányra a @interface szakaszban:

    #import "RegisterClient.h"
    
    @property (strong, nonatomic) NSData* deviceToken;
    @property (strong, nonatomic) RegisterClient* registerClient;
    
  9. A ViewController.m fájlban adjon hozzá egy privátmetódus-deklarációt a @interface szakaszhoz:

    @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
    

    Megjegyzés

    Az alábbi kódrészlet nem biztonságos hitelesítési séma. A implementációt createAndSetAuthenticationHeaderWithUsername:AndPassword: az adott hitelesítési mechanizmussal kell helyettesítenie, amely létrehoz egy hitelesítési jogkivonatot, amelyet a regisztrációs ügyfélosztály (pl. OAuth, Active Directory) használ fel.

  10. Ezután a szakaszba ViewController.mírja be a @implementation következő kódot, amely hozzáadja az eszközjogkivonat és a hitelesítési fejléc beállításának implementációját.

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

    Figyelje meg, hogy az eszköz jogkivonatának beállítása engedélyezi a Bejelentkezés gombot. Ennek az az oka, hogy a bejelentkezési művelet részeként a nézetvezérlő leküldéses értesítésekre regisztrál az alkalmazás háttérrendszerével. Nem szeretné, hogy a bejelentkezési művelet elérhető legyen, amíg az eszköz jogkivonata nincs megfelelően beállítva. A bejelentkezést leválaszthatja a leküldéses regisztrációról, ha az előbbi az utóbbi előtt történik.

  11. A ViewController.m-ben az alábbi kódrészletekkel implementálhatja a Bejelentkezési gomb műveletmetódusát, és egy metódust, a ASP.NET háttérrendszer használatával küldi el az értesítési üzenetet.

    - (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. Frissítse az Értesítés küldése gomb műveletét a ASP.NET háttérrendszer használatához, és küldje el a kapcsoló által engedélyezett PNS-nek.

    - (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. A függvényben ViewDidLoad adja hozzá a következőket a példány példányának RegisterClient létrehozásához, és állítsa be a delegáltat a szövegmezőkhöz.

    self.UsernameField.delegate = self;
    self.PasswordField.delegate = self;
    self.RecipientField.delegate = self;
    self.registerClient = [[RegisterClient alloc] initWithEndpoint:BACKEND_ENDPOINT];
    
  14. AppDelegate.mMost távolítsa el a metódus application:didRegisterForPushNotificationWithDeviceToken: összes tartalmát, és cserélje le a következőre (győződjön meg arról, hogy a nézetvezérlő tartalmazza az APN-ekből lekért legújabb eszközjogkivonatot):

    // 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. AppDelegate.mVégül győződjön meg arról, hogy rendelkezik a következő módszerrel:

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

Az alkalmazás tesztelése

  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 adja meg ugyanazt az értéket a felhasználónévhez és a jelszóhoz is. Ezután kattintson a Bejelentkezés gombra.

    iOS test application

  3. Megjelenik egy előugró ablak, amely tájékoztatja a regisztráció sikerességéről. Kattintson az OK gombra.

    iOS test notification displayed

  4. A *Címzett felhasználónév címkéje szövegmezőbe írja be a regisztrációhoz használt felhasználónevet egy másik eszközről.

  5. Adjon meg egy értesítési üzenetet, és kattintson az Értesítés küldése gombra. Csak azok az eszközök kapják meg az értesítési üzenetet, amelyek rendelkeznek a címzett felhasználóneve címkével rendelkező regisztrációval. A rendszer csak ezeknek a felhasználóknak küldi el.

    iOS test tagged notification

Következő lépések

Ebben az oktatóanyagban elsajátította, hogy hogyan küldhet leküldéses értesítéseket olyan adott felhasználóknak, akik a regisztrációjukhoz társított címkével rendelkeznek. Ha szeretné megtudni, hogy hogyan küldhet helyalapú értesítéseket, lépjen tovább a következő oktatóanyagra: