Zelfstudie: Pushmeldingen verzenden naar Flutter-apps met behulp van Azure Notification Hubs via een back-endservice
Het voorbeeld downloaden
In deze zelfstudie gebruikt u Azure Notification Hubs om pushmeldingen te verzenden naar een Flutter-toepassing die is gericht op Android- en iOS-.
Een ASP.NET Core Web-API back-end wordt gebruikt voor het afhandelen van apparaatregistratie voor de client met behulp van de nieuwste en beste installatie- benadering. De service verzendt ook pushmeldingen op een platformoverschrijdende manier.
Deze bewerkingen worden verwerkt met behulp van de Notification Hubs SDK voor back-endbewerkingen. Meer informatie over de algemene benadering vindt u in de Registreren vanuit de back-end van uw app documentatie.
In deze zelfstudie doorloopt u de volgende stappen:
- Push Notification Services en Azure Notification Hubs instellen.
- een ASP.NET Core Web API-back-endtoepassing maken.
- Een platformoverschrijdende Flutter-toepassing maken.
- het systeemeigen Android-project configureren voor pushmeldingen.
- Het systeemeigen iOS-project configureren voor pushmeldingen.
- De oplossing testen.
Voorwaarden
Als u wilt volgen, hebt u het volgende nodig:
- Een Azure-abonnement waar u resources kunt maken en beheren.
- De Flutter toolkit (samen met de vereisten).
- Visual Studio Code met de Flutter- en Dart-invoegtoepassingen geïnstalleerd.
- CocoaPods geïnstalleerd voor het beheren van bibliotheekafhankelijkheden.
- De mogelijkheid om de app uit te voeren op Android- (fysieke of emulatorapparaten) of iOS- (alleen fysieke apparaten).
Voor Android hebt u het volgende nodig:
- Een ontwikkelaar ontgrendeld fysiek apparaat of een emulator (met API 26 en hoger waarop Google Play Services is geïnstalleerd).
Voor iOS hebt u het volgende nodig:
- Een actief Apple Developer-account.
- Een fysiek iOS-apparaat dat is geregistreerd bij uw ontwikkelaarsaccount(met iOS 13.0 en hoger).
- Een .p12ontwikkelingscertificaat geïnstalleerd in uw sleutelhanger zodat u een app kunt uitvoeren op een fysiek apparaat.
Notitie
De iOS-simulator biedt geen ondersteuning voor externe meldingen en daarom is een fysiek apparaat vereist bij het verkennen van dit voorbeeld in iOS. U hoeft de app echter niet uit te voeren op zowel Android- als iOS- om deze zelfstudie te voltooien.
U kunt de stappen in dit voorbeeld van de eerste principes volgen zonder eerdere ervaring. U hebt echter wel baat bij het kennen van de volgende aspecten.
- Apple Developer Portal.
- ASP.NET Core.
- Google Firebase Console.
- Microsoft Azure en Pushmeldingen verzenden naar iOS-apps met behulp van Azure Notification Hubs.
- Flutter en Dart voor platformoverschrijdende ontwikkeling.
- Kotlin en Swift voor systeemeigen android- en iOS-ontwikkeling.
De opgegeven stappen zijn specifiek voor macOS-. U kunt Windows volgen door de iOS- aspecten over te slaan.
Push Notification Services en Azure Notification Hub instellen
In deze sectie stelt u Firebase Cloud Messaging (FCM) en APNS (Apple Push Notification Services) in. Vervolgens maakt en configureert u een Notification Hub om met deze services te werken.
Een Firebase-project maken en Firebase Cloud Messaging voor Android inschakelen
Meld u aan bij de Firebase-console. Maak een nieuw Firebase-project dat PushDemo- invoert als projectnaam.
Notitie
Er wordt een unieke naam voor u gegenereerd. Dit bestaat standaard uit een variant in kleine letters van de naam die u hebt opgegeven plus een gegenereerd getal gescheiden door een streepje. U kunt dit wijzigen als u wilt dat deze nog steeds wereldwijd uniek is.
Nadat u uw project hebt gemaakt, selecteert u Firebase toevoegen aan uw Android-app.
Voer op de pagina Firebase toevoegen aan uw Android-app de volgende stappen uit.
Voer voor de Android-pakketnaameen naam in voor uw pakket. Bijvoorbeeld:
com.<organization_identifier>.<package_name>
.Selecteer App-registreren.
Selecteer google-services.jsondownloaden. Sla het bestand vervolgens op in een lokale map voor later gebruik en selecteer Volgende.
downloaden
Selecteer Volgende.
Selecteer Console doorgaan
Notitie
Als de knop Doorgaan naar de console niet is ingeschakeld, kiest u deze stap overslaanvanwege de de installatie controleren.
Selecteer in de Firebase-console het tandwiel voor uw project. Selecteer vervolgens projectinstellingen.
Notitie
Als u het google-services.json bestand nog niet hebt gedownload, kunt u het downloaden op deze pagina.
Ga naar het tabblad Cloud Messaging bovenaan. Kopieer en sla de Server-sleutel op voor later gebruik. U gebruikt deze waarde om uw Notification Hub te configureren.
Uw iOS-app registreren voor pushmeldingen
Als u pushmeldingen wilt verzenden naar een iOS-app, registreert u uw toepassing bij Apple en registreert u zich ook voor pushmeldingen.
Als u uw app nog niet hebt geregistreerd, bladert u naar de iOS-inrichtingsportal in het Apple Developer Center. Meld u aan bij de portal met uw Apple ID, navigeer naar certificaten, id's & profielenen selecteer vervolgens id's. Klik op + om een nieuwe app te registreren.
Selecteer in het scherm Een nieuwe id registreren het keuzerondje app-id's. Selecteer vervolgens Doorgaan.
Werk de volgende drie waarden voor uw nieuwe app bij en selecteer vervolgens Doorgaan:
Beschrijving: typ een beschrijvende naam voor uw app.
bundel-id: voer een bundel-id in van het formulier com.<organization_identifier>.<product_name> zoals vermeld in de app-distributiehandleiding. In de volgende schermopname wordt de
mobcat
-waarde gebruikt als organisatie-id en wordt de PushDemo--waarde gebruikt als productnaam.pushmeldingen: controleer de optie Pushmeldingen in de sectie Capabilities.
Met deze actie wordt uw app-id gegenereerd en worden de gegevens bevestigd. Selecteer Doorgaanen selecteer registreren om de nieuwe app-id te bevestigen.
Nadat u registreren hebt geselecteerd, ziet u de nieuwe app-id als regelitem op de pagina Certificaten, Id's & Profielen.
Zoek op de pagina Certificaten, id's & profielen onder id'shet regelitem app-id dat u hebt gemaakt. Selecteer vervolgens de rij om de Uw app-id-configuratie scherm bewerken weer te geven.
Een certificaat maken voor Notification Hubs
Een certificaat is vereist om de Notification Hub in staat te stellen om te werken met APNS- (Apple Push Notification Services) en kan op twee manieren worden verstrekt:
Een p12-pushcertificaat maken dat rechtstreeks naar Notification Hub kan worden geüpload (de oorspronkelijke benadering)
Een p8-certificaat maken dat kan worden gebruikt voor verificatie op basis van tokens (de nieuwere en aanbevolen benadering)
De nieuwere benadering heeft een aantal voordelen, zoals beschreven in verificatie op basis van token (HTTP/2) voor APNS-. Er zijn minder stappen vereist, maar worden ook verplicht voor specifieke scenario's. Er zijn echter stappen gegeven voor beide benaderingen, omdat beide voor de doeleinden van deze zelfstudie werken.
OPTIE 1: Een p12-pushcertificaat maken dat rechtstreeks naar Notification Hub kan worden geüpload
Voer op uw Mac het hulpprogramma Sleutelhangertoegang uit. Het kan worden geopend vanuit de Utilities map of de Andere map op launchpad.
Selecteer sleutelhangertoegang, vouw certificaatassistentuit en selecteer vervolgens Een certificaat aanvragen bij een certificeringsinstantie.
Notitie
Sleutelhangertoegang selecteert standaard het eerste item in de lijst. Dit kan een probleem zijn als u zich in de categorie Certificaten bevindt en Apple Worldwide Developer Relations Certification Authority niet het eerste item in de lijst is. Zorg ervoor dat u een niet-sleutelitem hebt of dat de Apple Worldwide Developer Relations-certificeringsinstantie sleutel is geselecteerd voordat u de CSR (Certificaatondertekeningsaanvraag) genereert.
Selecteer uw e-mailadres van de gebruiker, voer uw algemene naam waarde in, zorg ervoor dat u opgeslagen op schijfopgeeft en selecteer vervolgens Doorgaan. Laat CA-e-mailadres leeg omdat dit niet vereist is.
Voer een naam in voor het CSR-bestand (Certificate Signing Request) in Opslaan als, selecteer de locatie in Waaren selecteer vervolgens Opslaan.
Met deze actie wordt het CSR-bestand opgeslagen op de geselecteerde locatie. De standaardlocatie is Desktop. Onthoud de locatie die voor het bestand is gekozen.
Ga terug naar de pagina Certificaten, id's & profielen pagina in de iOS-inrichtingsportal, schuif omlaag naar de ingeschakelde optie Pushmeldingen en selecteer configureren om het certificaat te maken.
Het venster Apple Push Notification Service TLS/SSL-certificaten wordt weergegeven. Selecteer de knop Certificaat maken onder de sectie Development TLS/SSL Certificate.
Het scherm Een nieuw certificaat maken wordt weergegeven.
Notitie
In deze zelfstudie wordt gebruikgemaakt van een ontwikkelingscertificaat. Hetzelfde proces wordt gebruikt bij het registreren van een productiecertificaat. Zorg ervoor dat u hetzelfde certificaattype gebruikt bij het verzenden van meldingen.
Selecteer Bestandkiezen, blader naar de locatie waar u het CSR-bestandhebt opgeslagen en dubbelklik vervolgens op de naam van het certificaat om het te laden. Selecteer vervolgens Doorgaan.
Nadat de portal het certificaat heeft gemaakt, selecteert u de knop Downloaden. Sla het certificaat op en onthoud de locatie waarop het is opgeslagen.
Het certificaat wordt gedownload en opgeslagen op uw computer in de map Downloads.
Notitie
Standaard heeft het gedownloade ontwikkelingscertificaat de naam aps_development.cer.
Dubbelklik op het gedownloade pushcertificaat aps_development.cer. Met deze actie wordt het nieuwe certificaat in de sleutelhanger geïnstalleerd, zoals wordt weergegeven in de volgende afbeelding:
Notitie
Hoewel de naam in uw certificaat mogelijk anders is, wordt de naam voorafgegaan door Apple Development iOS Push Services en de juiste bundel-id eraan te koppelen.
Klik in Sleutelhangertoegang Control + klik op op het nieuwe pushcertificaat dat u hebt gemaakt in de categorie Certificaten. Selecteer Exporteren, geef het bestand een naam, selecteer de p12-indeling en selecteer vervolgens Opslaan.
U kunt ervoor kiezen om het certificaat te beveiligen met een wachtwoord, maar een wachtwoord is optioneel. Klik op OK als u het maken van een wachtwoord wilt omzeilen. Noteer de bestandsnaam en locatie van het geëxporteerde p12-certificaat. Ze worden gebruikt om verificatie met APNs in te schakelen.
Notitie
De naam en locatie van uw p12-bestand kunnen afwijken van wat in deze zelfstudie wordt weergegeven.
OPTIE 2: Een p8-certificaat maken dat kan worden gebruikt voor verificatie op basis van tokens
Noteer de volgende details:
- voorvoegsel voor app-id's (team-id)
- bundel-id
Klik in certificaten, id's & profielenop sleutels.
Notitie
Als u al een sleutel hebt geconfigureerd voor APNS-, kunt u het p8-certificaat dat u hebt gedownload, opnieuw gebruiken nadat het is gemaakt. Zo ja, dan kunt u stappen 3 tot en met 5negeren.
Klik op de knop + (of de knop Een sleutel maken) om een nieuwe sleutel te maken.
Geef een geschikte sleutelnaam waarde op, schakel vervolgens de APNS-optie (Apple Push Notifications Service) in en klik vervolgens op Doorgaan, gevolgd door registreren op het volgende scherm.
Klik op Download en verplaats het bestand p8 (voorafgegaan door AuthKey_) naar een beveiligde lokale map en klik vervolgens op Gereed.
Notitie
Zorg ervoor dat u het p8-bestand op een veilige plaats bewaart (en een back-up opslaat). Nadat u de sleutel hebt gedownload, kan deze niet opnieuw worden gedownload omdat de serverkopie wordt verwijderd.
Klik in Sleutelsop de sleutel die u hebt gemaakt (of een bestaande sleutel als u ervoor hebt gekozen om die te gebruiken).
Noteer de sleutel-id waarde.
Open uw p8-certificaat in een geschikte toepassing van uw keuze, zoals Visual Studio Code. Noteer de sleutelwaarde (tussen -----BEGIN PRIVATE KEY----- en -----END PRIVATE KEY-----).
-----BEGIN PRIVATE KEY-----
<key_value>
----------Notitie
Dit is de tokenwaarde die later wordt gebruikt om Notification Hub-te configureren.
Aan het einde van deze stappen moet u de volgende informatie hebben voor later gebruik in Uw Notification Hub configureren met APNS-informatie:
- team-id (zie stap 1)
- bundel-id (zie stap 1)
- sleutel-id (zie stap 7)
- tokenwaarde (p8-sleutelwaarde verkregen in stap 8)
Een inrichtingsprofiel voor de app maken
Ga terug naar de iOS-inrichtingsportal, selecteer Certificaten, Id's & Profielen, selecteer Profielen in het menu links en selecteer + om een nieuw profiel te maken. Het scherm Een nieuw inrichtingsprofiel registreren wordt weergegeven.
Selecteer
onder Development als het inrichtingsprofieltype en selecteer vervolgensDoorgaan .Selecteer vervolgens de app-id die u hebt gemaakt in de vervolgkeuzelijst App-id en selecteer Doorgaan.
Selecteer in het venster Certificaten selecteren het ontwikkelingscertificaat dat u gebruikt voor het ondertekenen van programmacode en selecteer Doorgaan.
Notitie
Dit certificaat is niet het pushcertificaat dat u hebt gemaakt in de vorige stap. Dit is uw ontwikkelingscertificaat. Als er geen bestaat, moet u deze maken omdat dit een vereiste is voor deze zelfstudie. Ontwikkelaarscertificaten kunnen worden gemaakt in de Apple Developer Portal, via Xcode- of in Visual Studio-.
Ga terug naar de pagina Certificaten, Id's & Profielen, selecteer Profielen in het linkermenu en selecteer vervolgens + om een nieuw profiel te maken. Het scherm Een nieuw inrichtingsprofiel registreren wordt weergegeven.
Selecteer in het venster Certificaten selecteren het ontwikkelingscertificaat dat u hebt gemaakt. Selecteer vervolgens Doorgaan.
Selecteer vervolgens de apparaten die u wilt gebruiken voor testen en selecteer Doorgaan.
Kies ten slotte een naam voor het profiel in Inrichtingsprofielnaamen selecteer genereren.
Wanneer het nieuwe inrichtingsprofiel wordt gemaakt, selecteert u downloaden. Onthoud de locatie waarop deze is opgeslagen.
Blader naar de locatie van het inrichtingsprofiel en dubbelklik erop om het te installeren op uw ontwikkelcomputer.
Een Notification Hub maken
In deze sectie maakt u een Notification Hub en configureert u verificatie met APNS-. U kunt een p12-pushcertificaat of verificatie op basis van tokens gebruiken. Als u een Notification Hub wilt gebruiken die u al hebt gemaakt, kunt u doorgaan naar stap 5.
Meld u aan bij Azure.
Klik op Een resource maken, zoek en kies Notification Hub-en klik vervolgens op Maken.
Werk de volgende velden bij en klik vervolgens op maken:
BASIC DETAILS
-abonnement: Kies het doelabonnement abonnement in de vervolgkeuzelijst
resourcegroep: een nieuwe resourcegroep maken (of kies een bestaande resourcegroep)NAAMRUIMTEDETAILS
Notification Hub-naamruimte: voer een wereldwijd unieke naam in voor de Notification Hub-naamruimte
Notitie
Zorg ervoor dat de optie Nieuwe maken is geselecteerd voor dit veld.
NOTIFICATION HUB DETAILS
Notification Hub: voer een naam in voor de Notification Hub-
Locatie: Kies een geschikte locatie in de vervolgkeuzelijst
prijscategorie: De standaardoptie Gratis behoudenNotitie
Tenzij u het maximum aantal hubs in de gratis laag hebt bereikt.
Zodra de Notification Hub is ingericht, gaat u naar die resource.
Navigeer naar uw nieuwe Notification Hub-.
Selecteer toegangsbeleid in de lijst (onder BEHEREN).
Noteer de beleidsnaam waarden, samen met de bijbehorende verbindingsreeks waarden.
Uw Notification Hub configureren met APNS-gegevens
Selecteer onder Notification ServicesApple volg vervolgens de juiste stappen op basis van de methode die u eerder hebt gekozen in de sectie Een certificaat voor Notification Hubs maken.
Notitie
Gebruik de Production- alleen voor toepassingsmodus als u pushmeldingen wilt verzenden naar gebruikers die uw app in de Store hebben gekocht.
OPTIE 1: Een .p12-pushcertificaat gebruiken
Selecteer Certificaat.
Selecteer het bestandspictogram.
Selecteer het .p12-bestand dat u eerder hebt geëxporteerd en selecteer vervolgens Open.
Geef indien nodig het juiste wachtwoord op.
Selecteer Sandbox- modus.
Selecteer opslaan.
OPTIE 2: Verificatie op basis van tokens gebruiken
Selecteer token.
Voer de volgende waarden in die u eerder hebt verkregen:
- sleutel-id
- bundel-id
- team-id
- token
Kies Sandbox-.
Selecteer opslaan.
Uw Notification Hub configureren met FCM-gegevens
- Selecteer Google- (GCM/FCM) in de sectie Instellingen in het linkermenu.
- Voer de -serversleutel in die u hebt genoteerd in de Google Firebase Console.
- Selecteer opslaan op de werkbalk.
Een ASP.NET Core Web API-back-endtoepassing maken
In deze sectie maakt u de ASP.NET Core Web-API back-end voor het afhandelen van apparaatregistratie en het verzenden van meldingen naar de mobiele Flutter-app.
Een webproject maken
Selecteer in Visual StudioFile>New Solution.
Selecteer .NET Core>App>ASP.NET Core>API>Volgende.
Selecteer in het dialoogvenster Uw nieuwe ASP.NET Core Web-API configurerenTarget Framework van .NET Core 3.1-.
Voer PushDemoApi- in voor de projectnaam en selecteer maken.
Start de foutopsporing (Command + Enter) om de sjabloon-app te testen.
Notitie
De sjabloon-app is geconfigureerd voor het gebruik van de WeatherForecastController- als de launchUrl-. Dit is ingesteld in Eigenschappen>launchSettings.json.
Als u wordt gevraagd om een Ongeldig ontwikkelingscertificaat gevonden bericht:
Klik op Ja om akkoord te gaan met het uitvoeren van het hulpprogramma dotnet dev-certs https om dit op te lossen. Het hulpprogramma dotnet dev-certs https vraagt u vervolgens om een wachtwoord in te voeren voor het certificaat en het wachtwoord voor uw sleutelhanger.
Klik op Ja wanneer u wordt gevraagd om het nieuwe certificaat te installeren en te vertrouwenen voer vervolgens het wachtwoord voor de sleutelhanger in.
Vouw de map Controllers uit en verwijder WeatherForecastController.cs.
Verwijder WeatherForecast.cs.
Lokale configuratiewaarden instellen met behulp van het hulpprogramma Secret Manager. Door de geheimen van de oplossing los te koppelen, zorgt u ervoor dat ze niet in broncodebeheer terechtkomen. Open Terminal ga vervolgens naar de map van het projectbestand en voer de volgende opdrachten uit:
dotnet user-secrets init dotnet user-secrets set "NotificationHub:Name" <value> dotnet user-secrets set "NotificationHub:ConnectionString" <value>
Vervang de waarden van de tijdelijke aanduiding door de naam en de verbindingsreekswaarden van uw eigen Notification Hub. U hebt deze in de een notification hub sectie gemaakt. Anders kunt u ze opzoeken in Azure.
NotificationHub:Name:
Zie Name in de samenvatting van Essentials bovenaan Overview.NotificationHub:ConnectionString-:
Zie DefaultFullSharedAccessSignature- in toegangsbeleidNotitie
Voor productiescenario's kunt u opties bekijken, zoals Azure KeyVault- om de verbindingsreeks veilig op te slaan. Ter vereenvoudiging worden de geheimen toegevoegd aan de Azure App Service toepassingsinstellingen.
Clients verifiëren met behulp van een API-sleutel (optioneel)
API-sleutels zijn niet zo veilig als tokens, maar zijn voldoende voor de doeleinden van deze zelfstudie. Een API-sleutel kan eenvoudig worden geconfigureerd via de ASP.NET Middleware-.
Voeg de API-sleutel toe aan de lokale configuratiewaarden.
dotnet user-secrets set "Authentication:ApiKey" <value>
Notitie
Vervang de waarde van de tijdelijke aanduiding door uw eigen waarde en noteer deze.
Control + Klik op in het project PushDemoApi, kies nieuwe map in het menu toevoegen en klik vervolgens op toevoegen met Authentication als de mapnaam.
Control + klik op in de map Authentication en kies New File... in het menu Toevoegen.
Selecteer >Lege klasse, voer ApiKeyAuthOptions.cs in voor de naamen klik vervolgens op Nieuwe de volgende implementatie toe te voegen.
using Microsoft.AspNetCore.Authentication; namespace PushDemoApi.Authentication { public class ApiKeyAuthOptions : AuthenticationSchemeOptions { public const string DefaultScheme = "ApiKey"; public string Scheme => DefaultScheme; public string ApiKey { get; set; } } }
Voeg nog een Lege klasse toe aan de map Authentication met de naam ApiKeyAuthHandler.csen voeg vervolgens de volgende implementatie toe.
using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace PushDemoApi.Authentication { public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions> { const string ApiKeyIdentifier = "apikey"; public ApiKeyAuthHandler( IOptionsMonitor<ApiKeyAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) {} protected override Task<AuthenticateResult> HandleAuthenticateAsync() { string key = string.Empty; if (Request.Headers[ApiKeyIdentifier].Any()) { key = Request.Headers[ApiKeyIdentifier].FirstOrDefault(); } else if (Request.Query.ContainsKey(ApiKeyIdentifier)) { if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey)) key = queryKey; } if (string.IsNullOrWhiteSpace(key)) return Task.FromResult(AuthenticateResult.Fail("No api key provided")); if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal)) return Task.FromResult(AuthenticateResult.Fail("Invalid api key.")); var identities = new List<ClaimsIdentity> { new ClaimsIdentity("ApiKeyIdentity") }; var ticket = new AuthenticationTicket( new ClaimsPrincipal(identities), Options.Scheme); return Task.FromResult(AuthenticateResult.Success(ticket)); } } }
Notitie
Een verificatiehandler is een type dat het gedrag van een schema implementeert, in dit geval een aangepast API-sleutelschema.
Voeg nog een Lege klasse toe aan de map Authentication met de naam ApiKeyAuthenticationBuilderExtensions.csen voeg vervolgens de volgende implementatie toe.
using System; using Microsoft.AspNetCore.Authentication; namespace PushDemoApi.Authentication { public static class AuthenticationBuilderExtensions { public static AuthenticationBuilder AddApiKeyAuth( this AuthenticationBuilder builder, Action<ApiKeyAuthOptions> configureOptions) { return builder .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>( ApiKeyAuthOptions.DefaultScheme, configureOptions); } } }
Notitie
Deze extensiemethode vereenvoudigt de middleware-configuratiecode in Startup.cs waardoor deze beter leesbaar en over het algemeen gemakkelijker te volgen is.
Werk in Startup.csde methode ConfigureServices bij om de API-sleutelverificatie te configureren onder de aanroep van de -services. Methode AddControllers.
using PushDemoApi.Authentication; using PushDemoApi.Models; using PushDemoApi.Services; public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme; options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme; }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind); }
Werk nog steeds in Startup.csde methode Configureren bij om de UseAuthentication- en UseAuthorization extensiemethoden aan te roepen op de IApplicationBuilder-van de app. Zorg ervoor dat deze methoden worden aangeroepen na UseRouting- en vóór app. UseEndpoints.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
Notitie
Het aanroepen van UseAuthentication registreert de middleware die gebruikmaakt van de eerder geregistreerde verificatieschema's (van ConfigureServices). Dit moet worden aangeroepen voordat middleware wordt aangeroepen die afhankelijk is van gebruikers die worden geverifieerd.
Afhankelijkheden toevoegen en services configureren
ASP.NET Core ondersteunt het afhankelijkheidsinjectiepatroon (DI) softwareontwerppatroon. Dit is een techniek voor het bereiken van Inversion of Control (IoC) tussen klassen en hun afhankelijkheden.
Het gebruik van de Notification Hub en de Notification Hubs SDK voor back-endbewerkingen wordt ingekapseld in een service. De service wordt geregistreerd en beschikbaar gesteld via een geschikte abstractie.
Control + Klik op in de map Afhankelijkheden en kies vervolgens NuGet-pakketten beheren....
Zoek Microsoft.Azure.NotificationHubs en controleer of deze is ingeschakeld.
Klik op Pakketten toevoegenen klik vervolgens op Accepteren wanneer u wordt gevraagd de licentievoorwaarden te accepteren.
Control + Klik op in het project PushDemoApi, kies nieuwe map in het menu toevoegen en klik vervolgens op toevoegen met modellen als de mapnaam.
Control + Klik op in de map Modellen en kies vervolgens Nieuw bestand... in het menu Toevoegen.
Selecteer >Lege klasse, voer PushTemplates.cs in voor de Naamen klik vervolgens op Nieuwe de volgende implementatie toe te voegen.
namespace PushDemoApi.Models { public class PushTemplates { public class Generic { public const string Android = "{ \"notification\": { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } }"; public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }"; } public class Silent { public const string Android = "{ \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} }"; public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }"; } } }
Notitie
Deze klasse bevat de nettoladingen voor tokenized meldingen voor de algemene en stille meldingen die vereist zijn voor dit scenario. De nettoladingen worden buiten de Installation gedefinieerd om experimenten toe te staan zonder dat bestaande installaties via de service hoeven te worden bijgewerkt. Het afhandelen van wijzigingen in installaties op deze manier valt buiten het bereik van deze zelfstudie. Overweeg voor productie aangepaste sjablonen.
Voeg nog een Lege klasse toe aan de map Modellen met de naam DeviceInstallation.csen voeg vervolgens de volgende implementatie toe.
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace PushDemoApi.Models { public class DeviceInstallation { [Required] public string InstallationId { get; set; } [Required] public string Platform { get; set; } [Required] public string PushChannel { get; set; } public IList<string> Tags { get; set; } = Array.Empty<string>(); } }
Voeg nog een Empty Class toe aan de map Models met de naam NotificationRequest.csen voeg vervolgens de volgende implementatie toe.
using System; namespace PushDemoApi.Models { public class NotificationRequest { public string Text { get; set; } public string Action { get; set; } public string[] Tags { get; set; } = Array.Empty<string>(); public bool Silent { get; set; } } }
Voeg nog een Lege klasse toe aan de map Models met de naam NotificationHubOptions.csen voeg vervolgens de volgende implementatie toe.
using System.ComponentModel.DataAnnotations; namespace PushDemoApi.Models { public class NotificationHubOptions { [Required] public string Name { get; set; } [Required] public string ConnectionString { get; set; } } }
Voeg een nieuwe map toe aan het project PushDemoApi met de naam Services.
Voeg een Empty Interface toe aan de map Services met de naam INotificationService.csen voeg vervolgens de volgende implementatie toe.
using System.Threading; using System.Threading.Tasks; using PushDemoApi.Models; namespace PushDemoApi.Services { public interface INotificationService { Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token); Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token); Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token); } }
Voeg een Lege klasse toe aan de map Services met de naam NotificationHubsService.csen voeg vervolgens de volgende code toe om de INotificationService-interface te implementeren:
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.NotificationHubs; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using PushDemoApi.Models; namespace PushDemoApi.Services { public class NotificationHubService : INotificationService { readonly NotificationHubClient _hub; readonly Dictionary<string, NotificationPlatform> _installationPlatform; readonly ILogger<NotificationHubService> _logger; public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger) { _logger = logger; _hub = NotificationHubClient.CreateClientFromConnectionString( options.Value.ConnectionString, options.Value.Name); _installationPlatform = new Dictionary<string, NotificationPlatform> { { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns }, { nameof(NotificationPlatform.Fcm).ToLower(), NotificationPlatform.Fcm } }; } public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token) { if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) || string.IsNullOrWhiteSpace(deviceInstallation?.Platform) || string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel)) return false; var installation = new Installation() { InstallationId = deviceInstallation.InstallationId, PushChannel = deviceInstallation.PushChannel, Tags = deviceInstallation.Tags }; if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform)) installation.Platform = platform; else return false; try { await _hub.CreateOrUpdateInstallationAsync(installation, token); } catch { return false; } return true; } public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token) { if (string.IsNullOrWhiteSpace(installationId)) return false; try { await _hub.DeleteInstallationAsync(installationId, token); } catch { return false; } return true; } public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token) { if ((notificationRequest.Silent && string.IsNullOrWhiteSpace(notificationRequest?.Action)) || (!notificationRequest.Silent && (string.IsNullOrWhiteSpace(notificationRequest?.Text)) || string.IsNullOrWhiteSpace(notificationRequest?.Action))) return false; var androidPushTemplate = notificationRequest.Silent ? PushTemplates.Silent.Android : PushTemplates.Generic.Android; var iOSPushTemplate = notificationRequest.Silent ? PushTemplates.Silent.iOS : PushTemplates.Generic.iOS; var androidPayload = PrepareNotificationPayload( androidPushTemplate, notificationRequest.Text, notificationRequest.Action); var iOSPayload = PrepareNotificationPayload( iOSPushTemplate, notificationRequest.Text, notificationRequest.Action); try { if (notificationRequest.Tags.Length == 0) { // This will broadcast to all users registered in the notification hub await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token); } else if (notificationRequest.Tags.Length <= 20) { await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token); } else { var notificationTasks = notificationRequest.Tags .Select((value, index) => (value, index)) .GroupBy(g => g.index / 20, i => i.value) .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token)); await Task.WhenAll(notificationTasks); } return true; } catch (Exception e) { _logger.LogError(e, "Unexpected error sending notification"); return false; } } string PrepareNotificationPayload(string template, string text, string action) => template .Replace("$(alertMessage)", text, StringComparison.InvariantCulture) .Replace("$(alertAction)", action, StringComparison.InvariantCulture); Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token) { var sendTasks = new Task[] { _hub.SendFcmNativeNotificationAsync(androidPayload, token), _hub.SendAppleNativeNotificationAsync(iOSPayload, token) }; return Task.WhenAll(sendTasks); } Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token) { var sendTasks = new Task[] { _hub.SendFcmNativeNotificationAsync(androidPayload, tags, token), _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token) }; return Task.WhenAll(sendTasks); } } }
Notitie
De tagexpressie die is verstrekt aan SendTemplateNotificationAsync is beperkt tot 20 tags. Het is beperkt tot 6 voor de meeste operators, maar de expressie bevat in dit geval alleen OR's (||). Als er meer dan 20 tags in de aanvraag staan, moeten ze worden gesplitst in meerdere aanvragen. Zie de Routerings- en tagexpressies documentatie voor meer informatie.
Werk in Startup.csde methode ConfigureServices bij om de NotificationHubsService- toe te voegen als een singleton-implementatie van INotificationService.
using PushDemoApi.Models; using PushDemoApi.Services; public void ConfigureServices(IServiceCollection services) { ... services.AddSingleton<INotificationService, NotificationHubService>(); services.AddOptions<NotificationHubOptions>() .Configure(Configuration.GetSection("NotificationHub").Bind) .ValidateDataAnnotations(); }
De API voor meldingen maken
Control + Klik op in de map Controllers en kies vervolgens Nieuw bestand... in het menu Toevoegen.
Selecteer ASP.NET Core>Web API Controller Class, voer NotificationsController in voor de Nameen klik vervolgens op New.
Notitie
Als u Visual Studio 2019-volgt, kiest u de API-controller met lees-/schrijfacties sjabloon.
Voeg de volgende naamruimten toe aan het begin van het bestand.
using System.ComponentModel.DataAnnotations; using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PushDemoApi.Models; using PushDemoApi.Services;
Werk de sjablooncontroller bij zodat deze is afgeleid van ControllerBase- en is ingericht met het kenmerk ApiController.
[ApiController] [Route("api/[controller]")] public class NotificationsController : ControllerBase { // Templated methods here }
Notitie
De Controller basisklasse biedt ondersteuning voor weergaven, maar dit is in dit geval niet nodig en dus kan ControllerBase- worden gebruikt. Als u Visual Studio 2019volgt, kunt u deze stap overslaan.
Als u ervoor hebt gekozen om de sectie Clients verifiëren te voltooien met behulp van een API-sleutel, moet u ook de NotificationsController voorzien van het kenmerk Autoriseren.
[Authorize]
Werk de constructor bij om het geregistreerde exemplaar van INotificationService als argument te accepteren en toe te wijzen aan een alleen-lezen lid.
readonly INotificationService _notificationService; public NotificationsController(INotificationService notificationService) { _notificationService = notificationService; }
Wijzig in launchSettings.json (in de map Eigenschappen) de launchUrl- van
weatherforecast
in API/notifications zodat deze overeenkomt met de URL die is opgegeven in het kenmerk RegistrationsControllerRoute.Start de foutopsporing (Command + Enter) om te controleren of de app werkt met de nieuwe NotificationsController- en retourneert een 401 Niet-geautoriseerde status.
Notitie
Visual Studio start de app mogelijk niet automatisch in de browser. U gebruikt Postman- om de API vanaf dit punt te testen.
Stel op een nieuw tabblad Postman de aanvraag in op GET-. Voer het onderstaande adres in en vervang de tijdelijke aanduiding <applicationUrl> door de https applicationUrl gevonden in Properties>launchSettings.json.
<applicationUrl>/api/notifications
Notitie
De applicationUrl- moet 'https://localhost:5001' zijn voor het standaardprofiel. Als u IIS- gebruikt (standaard in Visual Studio 2019- in Windows), moet u in plaats daarvan de applicationUrl- gebruiken die is opgegeven in het iisSettings item. U ontvangt een 404-antwoord als het adres onjuist is.
Als u ervoor hebt gekozen om de Clients verifiëren met behulp van een sectie API-sleutel te voltooien, moet u de aanvraagheaders zo configureren dat deze uw apikey waarde bevatten.
Sleutel Waarde apikey <your_api_key> Klik op de knop Verzenden.
Notitie
U ontvangt een 200 OK status met een aantal JSON- inhoud.
Als u een SSL-certificaatverificatie ontvangt waarschuwing, kunt u de verificatie van het SSL-certificaat Postman uitschakelen in de Instellingen.
Vervang de sjabloonklassemethoden in NotificationsController.cs door de volgende code.
[HttpPut] [Route("installations")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)] public async Task<IActionResult> UpdateInstallation( [Required]DeviceInstallation deviceInstallation) { var success = await _notificationService .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted); if (!success) return new UnprocessableEntityResult(); return new OkResult(); } [HttpDelete()] [Route("installations/{installationId}")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)] public async Task<ActionResult> DeleteInstallation( [Required][FromRoute]string installationId) { var success = await _notificationService .DeleteInstallationByIdAsync(installationId, CancellationToken.None); if (!success) return new UnprocessableEntityResult(); return new OkResult(); } [HttpPost] [Route("requests")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)] public async Task<IActionResult> RequestPush( [Required]NotificationRequest notificationRequest) { if ((notificationRequest.Silent && string.IsNullOrWhiteSpace(notificationRequest?.Action)) || (!notificationRequest.Silent && string.IsNullOrWhiteSpace(notificationRequest?.Text))) return new BadRequestResult(); var success = await _notificationService .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted); if (!success) return new UnprocessableEntityResult(); return new OkResult(); }
De API-app maken
U maakt nu een API-app in Azure App Service- voor het hosten van de back-endservice.
Meld u aan bij de Azure Portal.
Klik op Een resource maken, zoek en kies API-appen klik vervolgens op Maken.
Werk de volgende velden bij en klik vervolgens op maken.
app-naam:
Voer een wereldwijd unieke naam in voor de API-app-abonnement:
Kies hetzelfde doel Abonnement u de Notification Hub hebt gemaakt.resourcegroep:
Kies dezelfde resourcegroep u de Notification Hub hebt gemaakt.App Service-plan/-locatie:
Een nieuw App Service-plan makenNotitie
Wijzig van de standaardoptie in een abonnement met SSL--ondersteuning. Anders moet u de juiste stappen uitvoeren bij het werken met de mobiele app om te voorkomen dat http- aanvragen worden geblokkeerd.
Application Insights:
Behoud de voorgestelde optie (er wordt een nieuwe resource gemaakt met die naam) of kies een bestaande resource.Zodra de API-app is ingericht, gaat u naar die resource.
Noteer de eigenschap URL in de samenvatting van de Essentials boven aan de Overzichts-. Deze URL is uw back-endeindpunt dat verderop in deze zelfstudie wordt gebruikt.
Notitie
De URL gebruikt de naam van de API-app die u eerder hebt opgegeven, met de indeling
https://<app_name>.azurewebsites.net
.Selecteer Configuratie- in de lijst (onder Instellingen).
Klik voor elk van de onderstaande instellingen op Nieuwe toepassingsinstelling om de naam en een waardein te voeren en klik vervolgens op OK-.
Naam Waarde Authentication:ApiKey
<api_key_value> NotificationHub:Name
<hub_name_value> NotificationHub:ConnectionString
<hub_connection_string_value> Notitie
Dit zijn dezelfde instellingen die u eerder hebt gedefinieerd in de gebruikersinstellingen. U moet deze kunnen kopiëren. De instelling Authentication:ApiKey is alleen vereist als u ervoor kiest om de Clients te verifiëren met behulp van een sectie API-sleutel. Voor productiescenario's kunt u opties bekijken, zoals Azure KeyVault-. Deze zijn toegevoegd als toepassingsinstellingen voor eenvoud in dit geval.
Zodra alle toepassingsinstellingen zijn toegevoegd, klikt u op Opslaanen Doorgaan.
De back-endservice publiceren
Vervolgens implementeert u de app in de API-app om deze toegankelijk te maken vanaf alle apparaten.
Notitie
De volgende stappen zijn specifiek voor Visual Studio voor Mac. Als u Visual Studio 2019- in Windows volgt, is de publicatiestroom anders. Zie Publiceren naar Azure App Service in Windows.
Wijzig de configuratie van Debug in Release als u dit nog niet hebt gedaan.
Control + Klik op het project PushDemoApi en kies vervolgens Publiceren naar Azure... in het menu Publiceren.
Volg de verificatiestroom als u hierom wordt gevraagd. Gebruik het account dat u in de vorige hebt gebruikt om de sectie API-app te maken.
Selecteer de Azure App Service API-app die u eerder hebt gemaakt in de lijst als publicatiedoel en klik vervolgens op Publiceren.
Nadat u de wizard hebt voltooid, wordt de app gepubliceerd naar Azure en wordt de app vervolgens geopend. Noteer de URL als u dit nog niet hebt gedaan. Deze URL is uw back-endeindpunt dat verderop in deze zelfstudie wordt gebruikt.
De gepubliceerde API valideren
In Postman een nieuw tabblad openen, stelt u de aanvraag in op PUT- en voert u het onderstaande adres in. Vervang de tijdelijke aanduiding door het basisadres dat u in de vorige de back-endservice sectie publiceert.
https://<app_name>.azurewebsites.net/api/notifications/installations
Notitie
Het basisadres moet de indeling hebben
https://<app_name>.azurewebsites.net/
Als u ervoor hebt gekozen om de Clients verifiëren met behulp van een sectie API-sleutel te voltooien, moet u de aanvraagheaders zo configureren dat deze uw apikey waarde bevatten.
Sleutel Waarde apikey <your_api_key> Kies de onbewerkte optie voor de Hoofdtekst, kies vervolgens JSON- in de lijst met indelingsopties en neem vervolgens een tijdelijke aanduiding op JSON- inhoud:
{}
Klik op verzenden.
Notitie
U ontvangt een 422 UnprocessableEntity status van de service.
Voer stap 1-4 opnieuw uit, maar deze keer geeft u het eindpunt voor aanvragen op om te valideren dat u een 400 Ongeldige aanvraag ontvangt antwoord.
https://<app_name>.azurewebsites.net/api/notifications/requests
Notitie
Het is nog niet mogelijk om de API te testen met geldige aanvraaggegevens, omdat hiervoor platformspecifieke informatie van de mobiele client-app vereist is.
Een platformoverschrijdende Flutter-toepassing maken
In deze sectie bouwt u een Flutter mobiele toepassing die pushmeldingen implementeert op een platformoverschrijdende manier.
Hiermee kunt u zich registreren en de registratie van een Notification Hub ongedaan maken via de back-endservice die u hebt gemaakt.
Er wordt een waarschuwing weergegeven wanneer een actie wordt opgegeven en de app zich op de voorgrond bevindt. Anders worden meldingen weergegeven in het meldingencentrum.
Notitie
Normaal gesproken voert u de registratie-acties (en deregistratie) uit tijdens het juiste punt in de levenscyclus van de toepassing (of als onderdeel van uw first-run-ervaring) zonder expliciete invoer voor gebruikersregistratie/registratie. In dit voorbeeld is echter expliciete gebruikersinvoer vereist om deze functionaliteit gemakkelijker te kunnen verkennen en testen.
De Flutter-oplossing maken
Open een nieuw exemplaar van Visual Studio Code.
Open het opdrachtpalet (Shift + Command + P).
Selecteer de opdracht Flutter: Nieuw project en druk vervolgens op Enter-.
Voer push_demo in voor de projectnaam en selecteer vervolgens een projectlocatie.
Wanneer u hierom wordt gevraagd, kiest u Pakketten ophalen.
Control Klik op in de mapkotlin (onder app src hoofd- ) en kiesWeergeven in Finder . Wijzig vervolgens de naam van de onderliggende mappen (onder de map kotlin) in respectievelijkcom
,<your_organization>
enpushdemo
.Notitie
Wanneer u de
Visual Studio Code sjabloon gebruikt, worden deze mappen standaardcom, voorbeeld , . Ervan uitgaande dat mobcat- wordt gebruikt voor de organisatie, moet de mapstructuur indicatief worden weergegeven als:project_name - kotlin
- Com
- mobcat
- pushdemo
- mobcat
- Com
- kotlin
Werk in Visual Studio Code-de applicationId--waarde bij in android-app>-app>build.gradle naar
com.<your_organization>.pushdemo
.Notitie
U moet de naam van uw eigen organisatie gebruiken voor de tijdelijke aanduiding <your_organization>. Als u bijvoorbeeld mobcat- gebruikt, resulteert dit in een pakketnaam waarde van com.mobcat.pushdemo.
Werk het kenmerk
pakket bij in de AndroidManifest.xml -bestanden, ondersrc foutopsporing ,src hoofd- ensrc profiel respectievelijk. Zorg ervoor dat de waarden overeenkomen met de applicationId die u in de vorige stap hebt gebruikt.<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.<your_organization>.pushdemo>"> ... </manifest>
Werk het kenmerk
android:label
in het AndroidManifest.xml-bestand bij onder src>hoofd- naar PushDemo-. Voeg vervolgens het kenmerkandroid:allowBackup
toe, direct onderandroid:label
, en stel de waarde in op onwaar.<application android:name="io.flutter.app.FlutterApplication" android:label="PushDemo" android:allowBackup="false" android:icon="@mipmap/ic_launcher"> ... </application>
Open het bestand build.gradle (android>-app>build.gradle) en werk vervolgens de compileSdkVersion- (uit de sectie android-) bij om API-29te gebruiken. Werk vervolgens de minSdkVersion- en targetSdkVersion waarden (uit de sectie defaultConfig) bij naar respectievelijk 26 en 29.
Notitie
Alleen apparaten met API-niveau 26 en hoger worden ondersteund voor de doeleinden van deze zelfstudie, maar u kunt deze uitbreiden om apparaten met oudere versies te ondersteunen.
Control + Klik op in de map ios en kies Openen in Xcode.
Klik in Xcode-op Runner (de xcodeproj- bovenaan, niet op de map). Selecteer vervolgens het
Runner doel en selecteer het tabbladAlgemeen . Werk debundel-id- bij naarterwijl de configuratie van alle build is geselecteerd.Notitie
U moet de naam van uw eigen organisatie gebruiken voor de tijdelijke aanduiding <your_organization>. Als u bijvoorbeeld mobcat- als organisatie gebruikt, resulteert dit in een bundel-id waarde van com.mobcat.PushDemo-.
Klik op
Info.plist werk debundelnaam waarde bij om PushDemo- teSluit Xcode- en ga terug naar Visual Studio Code-.
Open in Visual Studio Codepubspec.yamlde http- en flutter_secure_storageDart-pakketten als afhankelijkheden. Sla het bestand vervolgens op en klik op Pakketten ophalen wanneer u hierom wordt gevraagd.
dependencies: flutter: sdk: flutter http: ^0.12.1 flutter_secure_storage: ^3.3.3
Wijzig in Terminalde map naar de map ios (voor uw Flutter-project). Voer vervolgens de pod-installatie uit opdracht om nieuwe pods te installeren (vereist voor het flutter_secure_storage-pakket).
Control + Klik op in de map lib en kies New File in het menu met main_page.dart als bestandsnaam. Voeg vervolgens de volgende code toe.
import 'package:flutter/material.dart'; class MainPage extends StatefulWidget { @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[], ) ) ); } }
Vervang in main.dartde sjablooncode door het volgende.
import 'package:flutter/material.dart'; import 'package:push_demo/main_page.dart'; final navigatorKey = GlobalKey<NavigatorState>(); void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
In Terminalbouwt en voert u de app uit op elk doelplatform om te testen of de sjabloon-app wordt uitgevoerd op uw apparaat(en). Zorg ervoor dat ondersteunde apparaten zijn verbonden.
flutter run
De platformoverschrijdende onderdelen implementeren
Control + Klik op in de map lib en kies Nieuwe map in het menu met modellen als mapnaam.
Control + Klik op in de map modellen en kies Nieuw bestand in het menu met device_installation.dart- als bestandsnaam. Voeg vervolgens de volgende code toe.
class DeviceInstallation { final String deviceId; final String platform; final String token; final List<String> tags; DeviceInstallation(this.deviceId, this.platform, this.token, this.tags); DeviceInstallation.fromJson(Map<String, dynamic> json) : deviceId = json['installationId'], platform = json['platform'], token = json['pushChannel'], tags = json['tags']; Map<String, dynamic> toJson() => { 'installationId': deviceId, 'platform': platform, 'pushChannel': token, 'tags': tags, }; }
Voeg een nieuw bestand toe aan de -modellen map met de naam push_demo_action.dart het definiëren van de opsomming van acties die in dit voorbeeld worden ondersteund.
enum PushDemoAction { actionA, actionB, }
Voeg een nieuwe map toe aan het project met de naam services voeg vervolgens een nieuw bestand toe aan die map met de naam device_installation_service.dart met de volgende implementatie.
import 'package:flutter/services.dart'; class DeviceInstallationService { static const deviceInstallation = const MethodChannel('com.<your_organization>.pushdemo/deviceinstallation'); static const String getDeviceIdChannelMethod = "getDeviceId"; static const String getDeviceTokenChannelMethod = "getDeviceToken"; static const String getDevicePlatformChannelMethod = "getDevicePlatform"; Future<String> getDeviceId() { return deviceInstallation.invokeMethod(getDeviceIdChannelMethod); } Future<String> getDeviceToken() { return deviceInstallation.invokeMethod(getDeviceTokenChannelMethod); } Future<String> getDevicePlatform() { return deviceInstallation.invokeMethod(getDevicePlatformChannelMethod); } }
Notitie
U moet de naam van uw eigen organisatie gebruiken voor de tijdelijke aanduiding <your_organization>. Als u bijvoorbeeld mobcat- als de organisatie gebruikt, resulteert dit in een MethodChannel naam van com.mobcat.pushdemo/deviceinstallation.
Deze klasse omvat het werken met het onderliggende systeemeigen platform om de vereiste apparaatinstallatiegegevens te verkrijgen. Een MethodChannel vereenvoudigt bidirectionele asynchrone communicatie met de onderliggende systeemeigen platforms. De platformspecifieke tegenhanger voor dit kanaal wordt in latere stappen gemaakt.
Voeg nog een bestand toe aan die map met de naam notification_action_service.dart met de volgende implementatie.
import 'package:flutter/services.dart'; import 'dart:async'; import 'package:push_demo/models/push_demo_action.dart'; class NotificationActionService { static const notificationAction = const MethodChannel('com.<your_organization>.pushdemo/notificationaction'); static const String triggerActionChannelMethod = "triggerAction"; static const String getLaunchActionChannelMethod = "getLaunchAction"; final actionMappings = { 'action_a' : PushDemoAction.actionA, 'action_b' : PushDemoAction.actionB }; final actionTriggeredController = StreamController.broadcast(); NotificationActionService() { notificationAction .setMethodCallHandler(handleNotificationActionCall); } Stream get actionTriggered => actionTriggeredController.stream; Future<void> triggerAction({action: String}) async { if (!actionMappings.containsKey(action)) { return; } actionTriggeredController.add(actionMappings[action]); } Future<void> checkLaunchAction() async { final launchAction = await notificationAction.invokeMethod(getLaunchActionChannelMethod) as String; if (launchAction != null) { triggerAction(action: launchAction); } } Future<void> handleNotificationActionCall(MethodCall call) async { switch (call.method) { case triggerActionChannelMethod: return triggerAction(action: call.arguments as String); default: throw MissingPluginException(); break; } } }
Notitie
Dit wordt gebruikt als een eenvoudig mechanisme om de verwerking van meldingsacties te centraliseren, zodat ze op een platformoverschrijdende manier kunnen worden verwerkt met behulp van een sterk getypte opsomming. Met de service kan het onderliggende systeemeigen platform een actie activeren wanneer er een wordt opgegeven in de nettolading van de melding. Ook kan met de algemene code met terugwerkende kracht worden gecontroleerd of er een actie is opgegeven tijdens het starten van de toepassing zodra Flutter klaar is om deze te verwerken. Wanneer de app bijvoorbeeld wordt gestart door te tikken op een melding vanuit het meldingencentrum.
Voeg een nieuw bestand toe aan de map services met de naam notification_registration_service.dart met de volgende implementatie.
import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:push_demo/services/device_installation_service.dart'; import 'package:push_demo/models/device_installation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class NotificationRegistrationService { static const notificationRegistration = const MethodChannel('com.<your_organization>.pushdemo/notificationregistration'); static const String refreshRegistrationChannelMethod = "refreshRegistration"; static const String installationsEndpoint = "api/notifications/installations"; static const String cachedDeviceTokenKey = "cached_device_token"; static const String cachedTagsKey = "cached_tags"; final deviceInstallationService = DeviceInstallationService(); final secureStorage = FlutterSecureStorage(); String baseApiUrl; String apikey; NotificationRegistrationService(this.baseApiUrl, this.apikey) { notificationRegistration .setMethodCallHandler(handleNotificationRegistrationCall); } String get installationsUrl => "$baseApiUrl$installationsEndpoint"; Future<void> deregisterDevice() async { final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey); final serializedTags = await secureStorage.read(key: cachedTagsKey); if (cachedToken == null || serializedTags == null) { return; } var deviceId = await deviceInstallationService.getDeviceId(); if (deviceId.isEmpty) { throw "Unable to resolve an ID for the device."; } var response = await http .delete("$installationsUrl/$deviceId", headers: {"apikey": apikey}); if (response.statusCode != 200) { throw "Deregister request failed: ${response.reasonPhrase}"; } await secureStorage.delete(key: cachedDeviceTokenKey); await secureStorage.delete(key: cachedTagsKey); } Future<void> registerDevice(List<String> tags) async { try { final deviceId = await deviceInstallationService.getDeviceId(); final platform = await deviceInstallationService.getDevicePlatform(); final token = await deviceInstallationService.getDeviceToken(); final deviceInstallation = DeviceInstallation(deviceId, platform, token, tags); final response = await http.put(installationsUrl, body: jsonEncode(deviceInstallation), headers: {"apikey": apikey, "Content-Type": "application/json"}); if (response.statusCode != 200) { throw "Register request failed: ${response.reasonPhrase}"; } final serializedTags = jsonEncode(tags); await secureStorage.write(key: cachedDeviceTokenKey, value: token); await secureStorage.write(key: cachedTagsKey, value: serializedTags); } on PlatformException catch (e) { throw e.message; } catch (e) { throw "Unable to register device: $e"; } } Future<void> refreshRegistration() async { final currentToken = await deviceInstallationService.getDeviceToken(); final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey); final serializedTags = await secureStorage.read(key: cachedTagsKey); if (currentToken == null || cachedToken == null || serializedTags == null || currentToken == cachedToken) { return; } final tags = jsonDecode(serializedTags); return registerDevice(tags); } Future<void> handleNotificationRegistrationCall(MethodCall call) async { switch (call.method) { case refreshRegistrationChannelMethod: return refreshRegistration(); default: throw MissingPluginException(); break; } } }
Notitie
Deze klasse bevat het gebruik van de DeviceInstallationService- en de aanvragen voor de back-endservice om de vereiste registratie-, registratie- en vernieuwingsacties uit te voeren. Het argument apiKey is alleen vereist als u ervoor hebt gekozen om de clients te verifiëren met behulp van een sectie API-sleutel.
Voeg een nieuw bestand toe aan de map lib met de naam config.dart met de volgende implementatie.
class Config { static String apiKey = "API_KEY"; static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT"; }
Notitie
Dit wordt gebruikt als een eenvoudige manier om app-geheimen te definiëren. Vervang de waarden van de tijdelijke aanduiding door uw eigen waarden. U moet deze noteren toen u de back-endservice maakte. De API-app-URL moet
https://<api_app_name>.azurewebsites.net/
zijn. Het apiKey lid is alleen vereist als u ervoor kiest om de clients te verifiëren met behulp van een sectie API-sleutel.Zorg ervoor dat u dit toevoegt aan uw Gitignore-bestand om te voorkomen dat deze geheimen worden doorgevoerd in broncodebeheer.
De platformoverschrijdende gebruikersinterface implementeren
Vervang in main_page.dartde functie build door het volgende.
@override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 40.0), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ FlatButton( child: Text("Register"), onPressed: registerButtonClicked, ), FlatButton( child: Text("Deregister"), onPressed: deregisterButtonClicked, ), ], ), ), ); }
Voeg de vereiste importbewerkingen toe aan de bovenkant van het bestand main_page.dart.
import 'package:push_demo/services/notification_registration_service.dart'; import 'config.dart';
Voeg een veld toe aan de klasse _MainPageState om een verwijzing naar de NotificationRegistrationServiceop te slaan.
final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
Implementeer in de _MainPageState klasse de gebeurtenis-handlers voor de knoppen Registreren en De registratie van knoppen ongedaan maken opPressed--gebeurtenissen. Roep de bijbehorende Register/Deregister methoden aan en geef vervolgens een waarschuwing weer om het resultaat aan te geven.
void registerButtonClicked() async { try { await notificationRegistrationService.registerDevice(List<String>()); await showAlert(message: "Device registered"); } catch (e) { await showAlert(message: e); } } void deregisterButtonClicked() async { try { await notificationRegistrationService.deregisterDevice(); await showAlert(message: "Device deregistered"); } catch (e) { await showAlert(message: e); } } Future<void> showAlert({ message: String }) async { return showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('PushDemo'), content: SingleChildScrollView( child: ListBody( children: <Widget>[ Text(message), ], ), ), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }
Controleer nu in main.dartof de volgende import bovenaan het bestand aanwezig is.
import 'package:flutter/material.dart'; import 'package:push_demo/models/push_demo_action.dart'; import 'package:push_demo/services/notification_action_service.dart'; import 'package:push_demo/main_page.dart';
Declareer een variabele voor het opslaan van verwijzingen naar een exemplaar van NotificationActionService en initialiseer deze.
final notificationActionService = NotificationActionService();
Voeg functies toe om de weergave van een waarschuwing af te handelen wanneer een actie wordt geactiveerd.
void notificationActionTriggered(PushDemoAction action) { showActionAlert(message: "${action.toString().split(".")[1]} action received"); } Future<void> showActionAlert({ message: String }) async { return showDialog<void>( context: navigatorKey.currentState.overlay.context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('PushDemo'), content: SingleChildScrollView( child: ListBody( children: <Widget>[ Text(message), ], ), ), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }
Werk de belangrijkste-functie bij om de NotificationActionServiceactionTriggered stream te bekijken en te controleren op acties die zijn vastgelegd tijdens het starten van de app.
void main() async { runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,)); notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); }); await notificationActionService.checkLaunchAction(); }
Notitie
Dit is simpelweg om de ontvangst en doorgifte van pushmeldingsacties te demonstreren. Normaal gesproken worden deze op de achtergrond afgehandeld, bijvoorbeeld door naar een specifieke weergave te navigeren of bepaalde gegevens te vernieuwen in plaats van in dit geval een waarschuwing weer te geven.
Het systeemeigen Android-project configureren voor pushmeldingen
Het JSON-bestand van Google Services toevoegen
Control + Klik op in de map Android- en kies vervolgens Openen in Android Studio. Schakel vervolgens over naar de weergave Project (als dit nog niet is gebeurd).
Zoek het google-services.json bestand dat u eerder hebt gedownload toen u het project PushDemo in de Firebase Consoleinstelt. Sleep deze vervolgens naar de hoofdmap van de -app module (Android>Android>-app).
Build-instellingen en -machtigingen configureren
Zet de weergave Project op Android-.
Open AndroidManifest.xmlen voeg de INTERNET- en READ_PHONE_STATE machtigingen toe na het -element voordat de -tag wordt gesloten.
<manifest> <application>...</application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> </manifest>
De Firebase SDK's toevoegen
Open in Android Studiohet bestand build.gradle build.gradle (Gradle Scripts>build.gradle (Project: android)). en zorg ervoor dat u het klassepad com.google.gms:google-services hebt in het
buildscript
>afhankelijkheden knooppunt.buildscript { repositories { // Check that you have the following line (if not, add it): google() // Google's Maven repository } dependencies { // ... // Add the following line: classpath 'com.google.gms:google-services:4.3.3' // Google Services plugin } } allprojects { // ... repositories { // Check that you have the following line (if not, add it): google() // Google's Maven repository // ... } }
Notitie
Zorg ervoor dat u naar de nieuwste versie verwijst volgens de instructies in de Firebase-console toen u de Android Project-hebt gemaakt.
Pas in het bestand build.gradle (Gradle Scripts>build.gradle (Module: app)) de Google Services Gradle-invoegtoepassing toe. Pas de invoegtoepassing rechts boven het knooppunt android- toe.
// ... // Add the following line: apply plugin: 'com.google.gms.google-services' // Google Services plugin android { // ... }
Voeg in hetzelfde bestand in het afhankelijkheden knooppunt de afhankelijkheid toe voor de Cloud Messaging Android-bibliotheek.
dependencies { // ... implementation 'com.google.firebase:firebase-messaging:20.2.0' }
Notitie
Zorg ervoor dat u naar de nieuwste versie verwijst volgens de Cloud Messaging Android-clientdocumentatie.
Sla de wijzigingen op en klik vervolgens op de knop Nu synchroniseren (vanuit de werkbalkprompt) of Project synchroniseren met Gradle Files.
Pushmeldingen voor Android verwerken
Klik in Android StudioControl + klik op op de com.<your_organization>.pushdemo pakketmap (app>src>hoofd->kotlin-), kies Pakket in het menu Nieuw. Voer services in als naam en druk vervolgens op Return-.
Control + Klik op in de map services en kies Kotlin File/Class in het menu New. Voer DeviceInstallationService in als de naam en druk op Return-.
Implementeer de DeviceInstallationService met behulp van de volgende code.
package com.<your_organization>.pushdemo.services import android.annotation.SuppressLint import android.content.Context import android.provider.Settings.Secure import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel @SuppressLint("HardwareIds") class DeviceInstallationService { companion object { const val DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation" const val GET_DEVICE_ID = "getDeviceId" const val GET_DEVICE_TOKEN = "getDeviceToken" const val GET_DEVICE_PLATFORM = "getDevicePlatform" } private var context: Context private var deviceInstallationChannel : MethodChannel val playServicesAvailable get() = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS constructor(context: Context, flutterEngine: FlutterEngine) { this.context = context deviceInstallationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, DEVICE_INSTALLATION_CHANNEL) deviceInstallationChannel.setMethodCallHandler { call, result -> handleDeviceInstallationCall(call, result) } } fun getDeviceId() : String = Secure.getString(context.applicationContext.contentResolver, Secure.ANDROID_ID) fun getDeviceToken() : String { if(!playServicesAvailable) { throw Exception(getPlayServicesError()) } // TODO: Revisit once we have created the PushNotificationsFirebaseMessagingService val token = "Placeholder_Get_Value_From_FirebaseMessagingService_Implementation" if (token.isNullOrBlank()) { throw Exception("Unable to resolve token for FCM.") } return token } fun getDevicePlatform() : String = "fcm" private fun handleDeviceInstallationCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { GET_DEVICE_ID -> { result.success(getDeviceId()) } GET_DEVICE_TOKEN -> { getDeviceToken(result) } GET_DEVICE_PLATFORM -> { result.success(getDevicePlatform()) } else -> { result.notImplemented() } } } private fun getDeviceToken(result: MethodChannel.Result) { try { val token = getDeviceToken() result.success(token) } catch (e: Exception) { result.error("ERROR", e.message, e) } } private fun getPlayServicesError(): String { val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) if (resultCode != ConnectionResult.SUCCESS) { return if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)){ GoogleApiAvailability.getInstance().getErrorString(resultCode) } else { "This device is not supported" } } return "An error occurred preventing the use of push notifications" } }
Notitie
Deze klasse implementeert de platformspecifieke tegenhanger voor het
com.<your_organization>.pushdemo/deviceinstallation
-kanaal. Dit is gedefinieerd in het Flutter-gedeelte van de app binnen DeviceInstallationService.dart. In dit geval worden de aanroepen gedaan van de algemene code naar de systeemeigen host. Zorg ervoor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.Deze klasse biedt een unieke id (met behulp van Secure.AndroidId) als onderdeel van de nettolading van de Notification Hub-registratie.
Voeg nog een Kotlin File/Class toe aan de map services met de naam NotificationRegistrationServiceen voeg vervolgens de volgende code toe.
package com.<your_organization>.pushdemo.services import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class NotificationRegistrationService { companion object { const val NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration" const val REFRESH_REGISTRATION = "refreshRegistration" } private var notificationRegistrationChannel : MethodChannel constructor(flutterEngine: FlutterEngine) { notificationRegistrationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationRegistrationService.NOTIFICATION_REGISTRATION_CHANNEL) } fun refreshRegistration() { notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, null) } }
Notitie
Deze klasse implementeert de platformspecifieke tegenhanger voor het
com.<your_organization>.pushdemo/notificationregistration
-kanaal. Dit is gedefinieerd in het Flutter-gedeelte van de app binnen NotificationRegistrationService.dart. In dit geval worden de aanroepen gedaan van de systeemeigen host naar de algemene code. Zorg er ook voor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.Voeg nog een Kotlin File/Class toe aan de map services met de naam NotificationActionServiceen voeg vervolgens de volgende code toe.
package com.<your_organization>.pushdemo.services import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel class NotificationActionService { companion object { const val NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction" const val TRIGGER_ACTION = "triggerAction" const val GET_LAUNCH_ACTION = "getLaunchAction" } private var notificationActionChannel : MethodChannel var launchAction : String? = null constructor(flutterEngine: FlutterEngine) { notificationActionChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationActionService.NOTIFICATION_ACTION_CHANNEL) notificationActionChannel.setMethodCallHandler { call, result -> handleNotificationActionCall(call, result) } } fun triggerAction(action: String) { notificationActionChannel.invokeMethod(NotificationActionService.TRIGGER_ACTION, action) } private fun handleNotificationActionCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { NotificationActionService.GET_LAUNCH_ACTION -> { result.success(launchAction) } else -> { result.notImplemented() } } } }
Notitie
Deze klasse implementeert de platformspecifieke tegenhanger voor het
com.<your_organization>.pushdemo/notificationaction
-kanaal. Dat is gedefinieerd in het Flutter-gedeelte van de app binnen NotificationActionService.dart. In beide richtingen kunnen oproepen worden gedaan. Zorg ervoor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.Voeg een nieuwe Kotlin File/Class toe aan het com.<your_organization>.pushdemo-pakket met de naam PushNotificationsFirebaseMessagingServiceen implementeer vervolgens met behulp van de volgende code.
package com.<your_organization>.pushdemo import android.os.Handler import android.os.Looper import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.<your_organization>.pushdemo.services.NotificationActionService import com.<your_organization>.pushdemo.services.NotificationRegistrationService class PushNotificationsFirebaseMessagingService : FirebaseMessagingService() { companion object { var token : String? = null var notificationRegistrationService : NotificationRegistrationService? = null var notificationActionService : NotificationActionService? = null } override fun onNewToken(token: String) { PushNotificationsFirebaseMessagingService.token = token notificationRegistrationService?.refreshRegistration() } override fun onMessageReceived(message: RemoteMessage) { message.data.let { Handler(Looper.getMainLooper()).post { notificationActionService?.triggerAction(it.getOrDefault("action", null)) } } } }
Notitie
Deze klasse is verantwoordelijk voor het verwerken van meldingen wanneer de app op de voorgrond wordt uitgevoerd. De triggerAction- wordt voorwaardelijk aangeroepen op de NotificationActionService als een actie is opgenomen in de nettolading van de melding die is ontvangen in onMessageReceived. Hiermee wordt ook refreshRegistration- aangeroepen op de NotificationRegistrationService wanneer het Firebase-token opnieuw wordt gegenereerd door de functie onNewToken te overschrijven.
Zorg er opnieuw voor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.
Voeg in AndroidManifest.xml (app>src>hoofd-) de PushNotificationsFirebaseMessagingService toe aan de onderkant van het -toepassingselement met het
com.google.firebase.MESSAGING_EVENT
intentiefilter.<manifest> <application> <!-- EXISTING MANIFEST CONTENT --> <service android:name="com.<your_organization>.pushdemo.PushNotificationsFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> </application> </manifest>
Controleer in DeviceInstallationServiceof de volgende importen boven aan het bestand aanwezig zijn.
package com.<your_organization>.pushdemo import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
Notitie
Vervang <your_organization> door de waarde van uw eigen organisatie.
Werk de tekst van de tijdelijke aanduiding Placeholder_Get_Value_From_FirebaseMessagingService_Implementation bij om de tokenwaarde op te halen uit de PushNotificationFirebaseMessagingService.
fun getDeviceToken() : String { if(!playServicesAvailable) { throw Exception(getPlayServicesError()) } // Get token from the PushNotificationsFirebaseMessagingService.token field. val token = PushNotificationsFirebaseMessagingService.token if (token.isNullOrBlank()) { throw Exception("Unable to resolve token for FCM.") } return token }
Controleer in MainActivityof de volgende importen boven aan het bestand aanwezig zijn.
package com.<your_organization>.pushdemo import android.content.Intent import android.os.Bundle import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.iid.FirebaseInstanceId import com.<your_organization>.pushdemo.services.DeviceInstallationService import com.<your_organization>.pushdemo.services.NotificationActionService import com.<your_organization>.pushdemo.services.NotificationRegistrationService import io.flutter.embedding.android.FlutterActivity
Notitie
Vervang <your_organization> door de waarde van uw eigen organisatie.
Voeg een variabele toe om een verwijzing op te slaan naar de DeviceInstallationService.
private lateinit var deviceInstallationService: DeviceInstallationService
Voeg een functie toe met de naam processNotificationActions om te controleren of een Intent een extra waarde heeft met de naam actie. Activeer die actie voorwaardelijk of sla deze op voor later gebruik als de actie wordt verwerkt tijdens het starten van de app.
private fun processNotificationActions(intent: Intent, launchAction: Boolean = false) { if (intent.hasExtra("action")) { var action = intent.getStringExtra("action"); if (action.isNotEmpty()) { if (launchAction) { PushNotificationsFirebaseMessagingService.notificationActionService?.launchAction = action } else { PushNotificationsFirebaseMessagingService.notificationActionService?.triggerAction(action) } } } }
Overschrijf de functie onNewIntent om processNotificationActionsaan te roepen.
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) processNotificationActions(intent) }
Notitie
Aangezien de LaunchMode voor MainActivity is ingesteld op SingleTop-, wordt een intent- verzonden naar de bestaande Activiteit-instantie via de onNew Intent functie in plaats van de onCreate functie en dus moet u een binnenkomende intentie verwerken in zowel onCreate als onNewIntent functies.
Overschrijf de functie onCreate en stel de deviceInstallationService in op een nieuw exemplaar van DeviceInstallationService.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) } }
Stel de eigenschappen notificationActionService en notificationRegistrationService in op PushNotificationFirebaseMessagingServices.
flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it) PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it) }
Roep in dezelfde functie FirebaseInstanceId.getInstance().instanceIdvoorwaardelijk aan. Implementeer de
OnCompleteListener om het resulterende token in te stellen waarde opPushNotificationFirebaseMessagingService voordat urefreshRegistration- aanroept.if(deviceInstallationService?.playServicesAvailable) { FirebaseInstanceId.getInstance().instanceId .addOnCompleteListener(OnCompleteListener { task -> if (!task.isSuccessful) return@OnCompleteListener PushNotificationsFirebaseMessagingService.token = task.result?.token PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration() }) }
In onCreateroept u processNotificationActions aan het einde van de functie aan. Gebruik true voor het argument launchAction om aan te geven dat deze actie wordt verwerkt tijdens het starten van de app.
processNotificationActions(this.intent, true)
Notitie
U moet de app telkens wanneer u deze uitvoert opnieuw registreren en stoppen met een foutopsporingssessie om pushmeldingen te blijven ontvangen.
Het systeemeigen iOS-project configureren voor pushmeldingen
Het runner-doel en Info.plist configureren
Klik in Visual Studio CodeControl + klik op in de map ios en kies vervolgens Openen in Xcode.
Klik in Xcodeop Runner (de xcodeproj- bovenaan, niet op de map) en selecteer vervolgens het Runner-doel en & Capabilities. Kies uw ontwikkelaarsaccount voor het Teamterwijl de configuratie van alle build is geselecteerd. Zorg ervoor dat de optie 'Automatisch beheren' is ingeschakeld en uw handtekeningcertificaat en inrichtingsprofiel automatisch zijn geselecteerd.
Notitie
Als u de nieuwe waarde voor het inrichtingsprofiel niet ziet, vernieuwt u de profielen voor de ondertekeningsidentiteit door Xcode>Voorkeuren>Account te selecteren selecteert u vervolgens de knop Handmatige profielen downloaden om de profielen te downloaden.
Klik op + Mogelijkheiden zoek naar Pushmeldingen. dubbelklik op op pushmeldingen om deze mogelijkheid toe te voegen.
Open Info.plist en stel Minimale systeemversie in op 13.0.
Notitie
Alleen apparaten met iOS 13.0 en hoger worden ondersteund voor de doeleinden van deze zelfstudie, maar u kunt deze uitbreiden om apparaten met oudere versies te ondersteunen.
Open Runner.entitlements en zorg ervoor dat de instelling APS Environment is ingesteld op ontwikkeling.
Pushmeldingen voor iOS verwerken
Control + Klik op in de map Runner (binnen het Runner-project) en kies vervolgens Nieuwe groep met Services als naam.
Control + Klik op in de map Services en kies Nieuw bestand.... Kies vervolgens Swift-bestand en klik op Volgende. Geef DeviceInstallationService op als naam en klik vervolgens op maken.
Implementeer DeviceInstallationService.swift met behulp van de volgende code.
import Foundation class DeviceInstallationService { enum DeviceRegistrationError: Error { case notificationSupport(message: String) } var token : Data? = nil let DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation" let GET_DEVICE_ID = "getDeviceId" let GET_DEVICE_TOKEN = "getDeviceToken" let GET_DEVICE_PLATFORM = "getDevicePlatform" private let deviceInstallationChannel : FlutterMethodChannel var notificationsSupported : Bool { get { if #available(iOS 13.0, *) { return true } else { return false } } } init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) { deviceInstallationChannel = FlutterMethodChannel(name: DEVICE_INSTALLATION_CHANNEL, binaryMessenger: binaryMessenger) deviceInstallationChannel.setMethodCallHandler(handleDeviceInstallationCall) } func getDeviceId() -> String { return UIDevice.current.identifierForVendor!.description } func getDeviceToken() throws -> String { if(!notificationsSupported) { let notificationSupportError = getNotificationsSupportError() throw DeviceRegistrationError.notificationSupport(message: notificationSupportError) } if (token == nil) { throw DeviceRegistrationError.notificationSupport(message: "Unable to resolve token for APNS.") } return token!.reduce("", {$0 + String(format: "%02X", $1)}) } func getDevicePlatform() -> String { return "apns" } private func handleDeviceInstallationCall(call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case GET_DEVICE_ID: result(getDeviceId()) case GET_DEVICE_TOKEN: getDeviceToken(result: result) case GET_DEVICE_PLATFORM: result(getDevicePlatform()) default: result(FlutterMethodNotImplemented) } } private func getDeviceToken(result: @escaping FlutterResult) { do { let token = try getDeviceToken() result(token) } catch let error { result(FlutterError(code: "UNAVAILABLE", message: error.localizedDescription, details: nil)) } } private func getNotificationsSupportError() -> String { if (!notificationsSupported) { return "This app only supports notifications on iOS 13.0 and above. You are running \(UIDevice.current.systemVersion)" } return "An error occurred preventing the use of push notifications." } }
Notitie
Deze klasse implementeert de platformspecifieke tegenhanger voor het
com.<your_organization>.pushdemo/deviceinstallation
-kanaal. Dit is gedefinieerd in het Flutter-gedeelte van de app binnen DeviceInstallationService.dart. In dit geval worden de aanroepen gedaan van de algemene code naar de systeemeigen host. Zorg ervoor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.Deze klasse biedt een unieke id (met behulp van de UIDevice.identifierForVendor waarde) als onderdeel van de nettolading van de Notification Hub-registratie.
Voeg nog een Swift File- toe aan de map Services met de naam NotificationRegistrationServiceen voeg vervolgens de volgende code toe.
import Foundation class NotificationRegistrationService { let NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration" let REFRESH_REGISTRATION = "refreshRegistration" private let notificationRegistrationChannel : FlutterMethodChannel init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) { notificationRegistrationChannel = FlutterMethodChannel(name: NOTIFICATION_REGISTRATION_CHANNEL, binaryMessenger: binaryMessenger) } func refreshRegistration() { notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, arguments: nil) } }
Notitie
Deze klasse implementeert de platformspecifieke tegenhanger voor het
com.<your_organization>.pushdemo/notificationregistration
-kanaal. Dit is gedefinieerd in het Flutter-gedeelte van de app binnen NotificationRegistrationService.dart. In dit geval worden de aanroepen gedaan van de systeemeigen host naar de algemene code. Zorg er ook voor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.Voeg nog een Swift-bestand toe aan de map Services met de naam NotificationActionServiceen voeg vervolgens de volgende code toe.
import Foundation class NotificationActionService { let NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction" let TRIGGER_ACTION = "triggerAction" let GET_LAUNCH_ACTION = "getLaunchAction" private let notificationActionChannel: FlutterMethodChannel var launchAction: String? = nil init(withBinaryMessenger binaryMessenger: FlutterBinaryMessenger) { notificationActionChannel = FlutterMethodChannel(name: NOTIFICATION_ACTION_CHANNEL, binaryMessenger: binaryMessenger) notificationActionChannel.setMethodCallHandler(handleNotificationActionCall) } func triggerAction(action: String) { notificationActionChannel.invokeMethod(TRIGGER_ACTION, arguments: action) } private func handleNotificationActionCall(call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case GET_LAUNCH_ACTION: result(launchAction) default: result(FlutterMethodNotImplemented) } } }
Notitie
Deze klasse implementeert de platformspecifieke tegenhanger voor het
com.<your_organization>.pushdemo/notificationaction
-kanaal. Dat is gedefinieerd in het Flutter-gedeelte van de app binnen NotificationActionService.dart. In beide richtingen kunnen oproepen worden gedaan. Zorg ervoor dat u <your_organization> vervangt door uw eigen organisatie, waar deze ook wordt gebruikt.Voeg in AppDelegate.swiftvariabelen toe om een verwijzing op te slaan naar de services die u eerder hebt gemaakt.
var deviceInstallationService : DeviceInstallationService? var notificationRegistrationService : NotificationRegistrationService? var notificationActionService : NotificationActionService?
Voeg een functie toe met de naam processNotificationActions voor het verwerken van de meldingsgegevens. Activeer die actie voorwaardelijk of sla deze op voor later gebruik als de actie wordt verwerkt tijdens het starten van de app.
func processNotificationActions(userInfo: [AnyHashable : Any], launchAction: Bool = false) { if let action = userInfo["action"] as? String { if (launchAction) { notificationActionService?.launchAction = action } else { notificationActionService?.triggerAction(action: action) } } }
Overschrijf de didRegisterForRemoteNotificationsWithDeviceToken functie waarmee het token waarde voor de DeviceInstallationService-wordt ingesteld. Roep vervolgens refreshRegistration- aan op de NotificationRegistrationService.
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { deviceInstallationService?.token = deviceToken notificationRegistrationService?.refreshRegistration() }
Overschrijf de functie didReceiveRemoteNotification het argument userInfo door te geven aan de functie processNotificationActions.
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { processNotificationActions(userInfo: userInfo) }
Overschrijf de didFailToRegisterForRemoteNotificationsWithError functie om de fout te registreren.
override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print(error); }
Notitie
Dit is een tijdelijke aanduiding. U wilt de juiste logboekregistratie en foutafhandeling implementeren voor productiescenario's.
In didFinishLaunchingWithOptions, instantieert u de deviceInstallationService, notificationRegistrationServiceen notificationActionService variabelen.
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger) notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger) notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
In dezelfde functie vraagt u voorwaardelijke autorisatie aan en registreert u zich voor externe meldingen.
if #available(iOS 13.0, *) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in if (granted) { DispatchQueue.main.async { let pushSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil) application.registerUserNotificationSettings(pushSettings) application.registerForRemoteNotifications() } } } }
Als de launchOptions- de remoteNotification-sleutel bevat, roept u processNotificationActions aan het einde van de didFinishLaunchingWithOptions functie aan. Geef het resulterende userInfo-object door en gebruik true voor het argument launchAction. Een waar waarde geeft aan dat de actie wordt verwerkt tijdens het starten van de app.
if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] { processNotificationActions(userInfo: userInfo, launchAction: true) }
De oplossing testen
U kunt nu het verzenden van meldingen testen via de back-endservice.
Een testmelding verzenden
Open een nieuw tabblad in Postman-.
Stel de aanvraag in op POST-en voer het volgende adres in:
https://<app_name>.azurewebsites.net/api/notifications/requests
Als u ervoor hebt gekozen om de Clients verifiëren met behulp van een sectie API-sleutel te voltooien, moet u de aanvraagheaders zo configureren dat deze uw apikey waarde bevatten.
Sleutel Waarde apikey <your_api_key> Kies de onbewerkte optie voor de Hoofdtekst, kies vervolgens JSON- in de lijst met indelingsopties en neem vervolgens een tijdelijke aanduiding op JSON- inhoud:
{ "text": "Message from Postman!", "action": "action_a" }
Selecteer de knop Code, die zich onder de knop Opslaan in de rechterbovenhoek van het venster bevindt. De aanvraag moet er ongeveer uitzien als in het volgende voorbeeld wanneer deze wordt weergegeven voor HTML- (afhankelijk van of u een apikey header hebt opgenomen):
POST /api/notifications/requests HTTP/1.1 Host: https://<app_name>.azurewebsites.net apikey: <your_api_key> Content-Type: application/json { "text": "Message from backend service", "action": "action_a" }
Voer de PushDemo-toepassing uit op een of beide doelplatforms (Android- en iOS-).
Notitie
Als u test op Android- ervoor zorgt dat u niet in Foutopsporinguitvoert, of als de app is geïmplementeerd door de toepassing uit te voeren, moet u de app geforceerd sluiten en opnieuw starten vanuit het startprogramma.
Tik in de PushDemo-app op de knop Registreren.
Sluit in Postmanhet venster Codefragmenten genereren (als u dit nog niet hebt gedaan) en klik vervolgens op de knop Verzenden.
Controleer of u een 200 OK antwoord krijgt in Postman- en de waarschuwing wordt weergegeven in de app met ActieA-actie ontvangen.
Sluit de PushDemo-app en klik vervolgens nogmaals op de knop Verzenden in Postman-.
Controleer of u een 200 OK antwoord krijgt in Postman-. Controleer of er een melding wordt weergegeven in het systeemvak voor de PushDemo-app met het juiste bericht.
Tik op de melding om te bevestigen dat de app wordt geopend en de ActieA-actie waarschuwing heeft ontvangen.
Wijzig in Postmande vorige aanvraagbody om een melding op de achtergrond te verzenden die action_b opgeeft in plaats van action_a voor de actie waarde.
{ "action": "action_b", "silent": true }
Als de app nog steeds is geopend, klikt u op de knop Verzenden in Postman-.
Controleer of u een 200 OK antwoord krijgt in Postman- en of de waarschuwing wordt weergegeven in de app met ActieB-actie ontvangen in plaats van ActieA-actieontvangen.
Sluit de PushDemo-app en klik vervolgens nogmaals op de knop Verzenden in Postman-.
Controleer of u een 200 OK antwoord krijgt in Postman- en dat de melding op de achtergrond niet wordt weergegeven in het systeemvak.
Probleemoplossing
Geen reactie van de back-endservice
Wanneer u lokaal test, moet u ervoor zorgen dat de back-endservice wordt uitgevoerd en de juiste poort gebruikt.
Als u test op basis van de Azure API-app, controleert u of de service wordt uitgevoerd en is geïmplementeerd en zonder fouten is gestart.
Controleer of u het basisadres correct hebt opgegeven in Postman- of in de configuratie van de mobiele app bij het testen via de client. Het basisadres moet indicatief worden https://<api_name>.azurewebsites.net/
of https://localhost:5001/
bij het lokaal testen.
Geen meldingen ontvangen op Android na het starten of stoppen van een foutopsporingssessie
Zorg ervoor dat u zich opnieuw registreert nadat u een foutopsporingssessie hebt gestart of gestopt. Het foutopsporingsprogramma zorgt ervoor dat er een nieuw Firebase--token wordt gegenereerd. De installatie van de Notification Hub moet ook worden bijgewerkt.
Een 401-statuscode ontvangen van de back-endservice
Controleer of u de apikey instelt aanvraagheader en deze waarde overeenkomt met de waarde die u hebt geconfigureerd voor de back-endservice.
Als u deze fout ontvangt bij het lokaal testen, moet u ervoor zorgen dat de sleutelwaarde die u hebt gedefinieerd in de clientconfiguratie, overeenkomt met de Authentication:ApiKey waarde voor de gebruikersinstelling die wordt gebruikt door de API-.
Als u test met een API-app, controleert u of de sleutelwaarde in het clientconfiguratiebestand overeenkomt met de -toepassingsinstelling Authentication:ApiKey die u gebruikt in de API-app.
Notitie
Als u deze instelling hebt gemaakt of gewijzigd nadat u de back-endservice hebt geïmplementeerd, moet u de service opnieuw starten om deze van kracht te laten worden.
Als u ervoor hebt gekozen om de Clients verifiëren met behulp van een sectie API-sleutel niet te voltooien, moet u ervoor zorgen dat u het kenmerk Autoriseren niet hebt toegepast op de klasse NotificationsController.
Een 404-statuscode ontvangen van de back-endservice
Controleer of het eindpunt en de HTTP-aanvraagmethode juist zijn. De eindpunten moeten bijvoorbeeld indicatief zijn:
-
[PUT]
https://<api_name>.azurewebsites.net/api/notifications/installations
-
[DELETE]
https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
-
[POST]
https://<api_name>.azurewebsites.net/api/notifications/requests
Of wanneer u lokaal test:
-
[PUT]
https://localhost:5001/api/notifications/installations
-
[DELETE]
https://localhost:5001/api/notifications/installations/<installation_id>
-
[POST]
https://localhost:5001/api/notifications/requests
Wanneer u het basisadres in de client-app opgeeft, moet u ervoor zorgen dat het eindigt met een /
. Het basisadres moet indicatief worden https://<api_name>.azurewebsites.net/
of https://localhost:5001/
bij het lokaal testen.
Kan niet registreren en er wordt een notification hub-foutbericht weergegeven
Controleer of het testapparaat netwerkconnectiviteit heeft. Bepaal vervolgens de http-antwoordstatuscode door een onderbrekingspunt in te stellen om de eigenschapswaarde van de StatusCode in de HttpResponse-te controleren.
Bekijk waar van toepassing de vorige suggesties voor probleemoplossing op basis van de statuscode.
Stel een onderbrekingspunt in op de regels die deze specifieke statuscodes retourneren voor de respectieve API. Roep vervolgens de back-endservice aan wanneer u lokaal fouten opspoort.
Controleer of de back-endservice werkt zoals verwacht via Postman- met behulp van de juiste nettolading. Gebruik de werkelijke nettolading die is gemaakt door de clientcode voor het betreffende platform.
Bekijk de platformspecifieke configuratiesecties om ervoor te zorgen dat er geen stappen zijn gemist. Controleer of geschikte waarden worden omgezet voor installation id
en token
variabelen voor het juiste platform.
Kan een id voor het foutbericht van het apparaat niet oplossen
Bekijk de platformspecifieke configuratiesecties om ervoor te zorgen dat er geen stappen zijn gemist.
Verwante koppelingen
- Overzicht van Azure Notification Hubs
- Flutter installeren op macOS-
- Flutter installeren in Windows
- Notification Hubs SDK voor back-endbewerkingen
- Notification Hubs SDK op GitHub
- registreren bij de back-end van de toepassing
- registratiebeheer
- Werken met tags
- Werken met aangepaste sjablonen
Volgende stappen
U moet nu een eenvoudige Flutter-app hebben die is verbonden met een Notification Hub via een back-endservice en meldingen kan verzenden en ontvangen.
Waarschijnlijk moet u het voorbeeld dat in deze zelfstudie wordt gebruikt aanpassen aan uw eigen scenario. Het implementeren van robuustere foutafhandeling, logica voor opnieuw proberen en logboekregistratie wordt ook aanbevolen.
Visual Studio App Center- kan snel worden opgenomen in mobiele apps die analyse- en diagnostische gegevens om hulp te bieden bij het oplossen van problemen.