Kurz: Odesílání nabízených oznámení do aplikací Flutter pomocí služby Azure Notification Hubs prostřednictvím back-endové služby
V tomto kurzu použijete
Back-end základního webového rozhraní API
Tyto operace se zpracovávají pomocí sady Notification Hubs SDK pro back-endové operace. Další podrobnosti o celkovém přístupu najdete v dokumentaci Registrace z back-endu vaší aplikace.
Tento kurz vás provede následujícími kroky:
- Nastavení nabízených oznámení a Azure Notification Hubs.
- Vytvoření back-endové aplikace webového rozhraní API ASP.NET Core.
- Vytvoření multiplatformní aplikace Flutter.
- Nakonfigurujte nativní projekt Androidu pro nabízená oznámení.
- Nakonfigurujte nativní projekt iOS pro nabízená oznámení.
- otestování řešení.
Požadavky
Pokud chcete postup sledovat, budete potřebovat:
- Předplatné Azure, kde můžete vytvářet a spravovat prostředky.
- Sada nástrojů Flutter (spolu s požadavky).
editoru Visual Studio Code s nainstalovanými modul y plug-in Flutter a Dart. - CocoaPods nainstalovaná pro správu závislostí knihovny.
- Možnost spustit aplikaci na android (fyzická nebo emulátorová zařízení) nebo iOS (jenom fyzická zařízení).
Pro Android musíte mít:
- Vývojář odemčený fyzický zařízení nebo emulátor (se spuštěným rozhraním API 26 a novějším s nainstalovanými službami Google Play).
Pro iOS musíte mít:
- Aktivní vývojářský účet Apple.
- Fyzické zařízení s iOSem, které je zaregistrované ve vašem vývojářském účtu(se systémem iOS 13.0 a novějším).
.p12 vývojový certifikát nainstalovaný v klíčenkyumožňuje spustit aplikaci na fyzickém zařízení .
Poznámka
Simulátor iOS nepodporuje vzdálená oznámení, takže při zkoumání této ukázky v iOSu se vyžaduje fyzické zařízení. K dokončení tohoto kurzu ale nemusíte aplikaci spouštět na Android i i OS.
Můžete postupovat podle kroků v tomto prvním příkladu zásad bez předchozího prostředí. Můžete se ale seznámit s následujícími aspekty.
- Portál pro vývojáře Apple.
- ASP.NET core.
- Google Firebase Console.
- Microsoft Azure a Odesílat nabízená oznámení aplikacím pro iOS pomocí služby Azure Notification Hubs.
- flutter a Dart pro vývoj pro různé platformy.
- Kotlin a Swift pro nativní vývoj pro Android a iOS.
Uvedené kroky jsou specifické pro macOS . Na Windows můžete sledovat přeskočením aspektů iOS.
Nastavení nabízených oznámení a Centra oznámení Azure
V této části jste nastavili
Vytvoření projektu Firebase a povolení služby Firebase Cloud Messaging pro Android
Přihlaste se ke konzole Firebase. Vytvořte nový projekt Firebase, který zadá PushDemo jako název projektu .
Poznámka
Pro vás se vygeneruje jedinečný název. Ve výchozím nastavení se skládá z malé varianty názvu, který jste zadali, plus vygenerované číslo oddělené pomlčkou. Tuto možnost můžete změnit, pokud chcete, aby byla stále globálně jedinečná.
Po vytvoření projektu vyberte Přidat Firebase do aplikace pro Android.
Na stránce Přidat Firebase na aplikaci pro Android proveďte následující kroky.
Jako název balíčku Androidzadejte název balíčku. Příklad:
com.<organization_identifier>.<package_name>
.Vyberte Zaregistrovataplikace .
Vyberte Stáhnout google-services.json. Potom soubor uložte do místní složky pro pozdější použití a vyberte Další.
Vyberte Další.
Vyberte Pokračovat v konzole
Poznámka
Pokud tlačítko Pokračovat v konzole není povolené, protože ověřit instalaci, zvolte Přeskočit tento krok.
V konzole Firebase vyberte ozubené kolo projektu. Pak vybertenastavení projektu
. Poznámka
Pokud jste soubor google-services.json nestáhli, můžete si ho stáhnout na této stránce.
Přepněte na kartu Cloud Messaging nahoře. Zkopírujte a uložte klíč Serveru pro pozdější použití. Tuto hodnotu použijete ke konfiguraci centra oznámení.
Registrace aplikace pro iOS pro nabízená oznámení
Pokud chcete odesílat nabízená oznámení do aplikace pro iOS, zaregistrujte aplikaci v Apple a zaregistrujte si také nabízená oznámení.
Pokud jste aplikaci ještě nezaregistrovali, přejděte na portál pro zřizování iOS v Centru pro vývojáře Apple. Přihlaste se k portálu pomocí Apple ID, přejděte na Certifikáty, identifikátory & profilya pak vyberte Identifikátory. Kliknutím na + zaregistrujte novou aplikaci.
id aplikací portálu pro zřizování pro iOS
Na obrazovce Zaregistrovat nový identifikátor vyberte přepínač ID aplikací. Pak vyberte Pokračovat.
Aktualizujte následující tři hodnoty nové aplikace a pak vyberte Pokračovat:
Popis: Zadejte popisný název aplikace.
ID sady : Zadejte ID sady formulářecom. , jak je uvedeno vprůvodce distribucí aplikacíorganization_identifier . product_name . Na následujícím snímku obrazovky se hodnota mobcat
použije jako identifikátor organizace a jako název produktu se použije hodnota PushDemo.portálu pro zřizování pro iOS
nabízená oznámení: V části Možnosti zaškrtněte možnost nabízených oznámení.
Tato akce vygeneruje ID aplikace a požadavky, které potvrdíte. Vyberte Pokračovata pak výběrem Zaregistrovat potvrďte nové ID aplikace.
Jakmile vyberete Zaregistrovat, zobrazí se nové ID aplikace jako řádková položka na stránce Certifikáty, identifikátory & profily.
Na stránce Certifikáty & profily v části Identifikátory vyhledejte položku řádku ID aplikace, kterou jste vytvořili. Potom výběrem jeho řádku zobrazte obrazovku Upravit konfiguraci ID aplikace.
Vytvoření certifikátu pro Notification Hubs
Certifikát se vyžaduje, aby centrum oznámení fungovalo s
Vytvoření certifikátu p12 push, který lze nahrát přímo do centra oznámení (původní přístup)
Vytvoření certifikátu p8, který lze použít pro ověřování na základě tokenů (novější a doporučený přístup)
Novější přístup má řadu výhod, jak je uvedeno v ověřování založeném na tokenech http/2 () pro službu APNS. Vyžaduje se méně kroků, ale je také vyžadováno pro konkrétní scénáře. Pro oba přístupy jsou však k dispozici kroky, protože oba budou fungovat pro účely tohoto kurzu.
MOŽNOST 1: Vytvoření certifikátu push p12, který lze nahrát přímo do centra oznámení
Na macu spusťte nástroj Keychain Access. Dá se otevřít ze složky Nástrojů nebo ze složky Jiné na Launchpadu.
Vyberte
Přístup ke klíčence, rozbalte Pomocníka s certifikáty a pak vyberte Požádat o certifikát od certifikační autority .pomocí klíčenky
Poznámka
Ve výchozím nastavení access řetězce klíčů vybere první položku v seznamu. Může to být problém, pokud jste v kategorii Certifikáty a certifikační autorita Apple Worldwide Developer Relations není první položkou v seznamu. Před vygenerováním žádosti o podepsání certifikátu se ujistěte, že máte neklíčovou položku nebo je vybraná certifikační autorita apple Worldwide Developer Relations klíč.
Vyberte
e-mailovou adresu uživatele , zadejte hodnotu běžný název, ujistěte se, že jste zadaliUloženo na disk a pak vybertePokračovat . E-mailová adresa certifikační autority prázdná, protože není nutná.Do
Uložit jako zadejte název souboruŽádosti o podepsání certifikátu (CSR) , vyberte umístění v Kde a pak vyberteUložit .certifikátu
Tato akce uloží soubor CSR do vybraného umístění. Výchozí umístění je Desktop. Zapamatujte si umístění vybrané pro soubor.
Zpět na stránce Certifikáty, identifikátory & profily na portálu pro zřizování iOS, posuňte se dolů na zaškrtnutou možnost nabízená oznámení a pak vyberte Konfigurovat vytvořit certifikát.
Zobrazí se okno službě Apple Push Notification TLS/SSL Certificates. V části
Vývoj certifikátů TLS/SSL vyberte tlačítko Vytvořit certifikát .Zobrazí se obrazovka Vytvořit nový certifikát.
Poznámka
Tento kurz používá vývojový certifikát. Stejný proces se používá při registraci produkčního certifikátu. Při odesílání oznámení se ujistěte, že používáte stejný typ certifikátu.
Vyberte Zvolte soubor, přejděte do umístění, kam jste uložili soubor CSRa potom poklikáním na název certifikátu ho načtěte. Pak vyberte Pokračovat.
Jakmile portál vytvoří certifikát, vyberte tlačítko Stáhnout. Uložte certifikát a zapamatujte si umístění, do kterého se uloží.
Stránka pro stažení vygenerovaného certifikátu
Certifikát se stáhne a uloží do počítače ve složce Stažené soubory.
Poznámka
Ve výchozím nastavení se stažený vývojový certifikát jmenuje aps_development.cer.
Poklikejte na stažený certifikát push aps_development.cer. Tato akce nainstaluje nový certifikát do klíčenky, jak je znázorněno na následujícím obrázku:
seznam přístupových certifikátů klíčenky
Poznámka
I když se název v certifikátu může lišit, název bude mít předponu Apple Development iOS Push Services a bude mít přidružený odpovídající identifikátor sady.
V okně Přístup ke klíčence řízení + Klikněte na nového certifikátu push, který jste vytvořili v kategorii Certifikáty. Vyberte Exportovat, pojmenujte soubor, vyberte formát p12 a pak vyberte Uložit.
Certifikát můžete chránit heslem, ale heslo je volitelné. Chcete-li obejít vytváření hesla, klikněte na OK. Poznamenejte si název souboru a umístění exportovaného certifikátu p12. Používají se k povolení ověřování pomocí APN.
Poznámka
Název a umístění souboru p12 se může lišit od toho, co je znázorněno v tomto kurzu.
MOŽNOST 2: Vytvoření certifikátu p8, který lze použít pro ověřování na základě tokenu
Poznamenejte si následující podrobnosti:
- předpona ID aplikace (ID týmu)
- ID sady
Zpět v Certifikáty, identifikátory & profily, klikněte na Klíče.
Poznámka
Pokud už máte klíč nakonfigurovaný pro APNS, můžete certifikát p8, který jste stáhli, znovu použít. Pokud ano, můžete ignorovat kroky 3 až 5.
Kliknutím na tlačítko + (nebo tlačítko Vytvořit klíč) vytvořte nový klíč.
Zadejte vhodnou hodnotu
Název klíče a potom zaškrtněte možnost službyApple Push Notifications Service (APNS) a potom klikněte na Pokračovat a potom na další obrazovceZaregistrovat .Klikněte na Stáhnout a přesuňte soubor p8 (s předponou AuthKey_) do zabezpečeného místního adresáře a potom klikněte na Hotovo.
Poznámka
Nezapomeňte soubor p8 uchovávat na bezpečném místě (a uložit zálohu). Po stažení klíče se nedá znovu stáhnout, protože se odebere kopie serveru.
V Klíčeklikněte na klíč, který jste vytvořili (nebo existující klíč, pokud jste se rozhodli tuto možnost použít).
Poznamenejte si hodnotu ID klíče .
Otevřete certifikát p8 v vhodné aplikaci podle vašeho výběru, například Visual Studio Code. Poznamenejte si hodnotu klíče (mezi privátním klíčem -----BEGIN----- a -----END PRIVATE KEY-----).
privátní klíč -----BEGIN-----
<key_value>
privátní klíč -----END-----Poznámka
Toto je hodnota tokenu
, která se použije později ke konfiguracicentra oznámení .
Na konci těchto kroků byste měli mít následující informace pro pozdější použití v Konfigurace centra oznámení s informacemi APNS:
- ID týmu (viz krok 1)
- ID sady prostředků (viz krok 1)
- ID klíče (viz krok 7)
- hodnota tokenu (hodnota klíče p8 získaná v kroku 8)
Vytvoření zřizovacího profilu pro aplikaci
Vraťte se na portál pro zřizování iOS, vyberte Certifikáty, identifikátory & profily, v nabídce vlevo vyberte Profily a pak vyberte + a vytvořte nový profil. Zobrazí se obrazovka Registrace nového zřizovacího profilu.
Jako typ zřizovacího profilu vyberte Vývoj aplikací pro iOS v části Development a pak vyberte Pokračovat.
Dále vyberte ID aplikace, které jste vytvořili, z rozevíracího seznamu
ID aplikace a vyberte Pokračovat .V okně Vyberte certifikáty vyberte vývojový certifikát, který používáte pro podepisování kódu, a vyberte Pokračovat.
Poznámka
Tento certifikát není certifikátem push, který jste vytvořili v předchozím kroku. Toto je váš vývojový certifikát. Pokud neexistuje, musíte ho vytvořit, protože se jedná o předpoklad pro účely tohoto kurzu. Certifikáty pro vývojáře je možné vytvářet naportálu pro vývojáře
Apple prostřednictvím Xcode nebo v Visual Studio .Vraťte se na stránku Certifikáty, identifikátory & profily, v nabídce vlevo vyberte Profily a pak vyberte + a vytvořte nový profil. Zobrazí se obrazovka Registrace nového zřizovacího profilu.
V okně Vyberte certifikáty vyberte vytvořený vývojový certifikát. Pak vyberte Pokračovat.
Dále vyberte zařízení, která chcete použít k testování, a vyberte Pokračovat.
Nakonec zvolte název profilu v Název zřizovacího profilua vyberte Vygenerovat.
Po vytvoření nového zřizovacího profilu vyberte Stáhnout. Zapamatujte si umístění, do kterého se uloží.
Přejděte do umístění zřizovacího profilu a poklikáním na něj nainstalujte na vývojový počítač.
Vytvoření centra oznámení
V této části vytvoříte centrum oznámení a nakonfigurujete ověřování pomocí APNS. Můžete použít certifikát p12 push nebo ověřování založené na tokenech. Pokud chcete použít centrum oznámení, které jste už vytvořili, můžete přeskočit ke kroku 5.
Přihlaste se k Azure.
Klikněte na
Vytvořit prostředku, vyhledejte a zvoltecentra oznámenía potom klikněte na Vytvořit .Aktualizujte následující pole a potom klikněte na Vytvořit:
ZÁKLADNÍ PODROBNOSTI
Předplatné: v rozevíracím seznamu Zvolte cílovou předplatného.
skupina prostředků: Vytvořit novou skupinu prostředků (nebo vybrat existující)PODROBNOSTI o oboru názvů
Namespace centra oznámení
: Zadejte globálně jedinečný název centra oznámeníPoznámka
Ujistěte se, že je pro toto pole vybraná možnost Vytvořit novou.
podrobnosti centra oznámení
Notification Hub: Zadejte název centra oznámení
umístění : Zvolte vhodné umístění z rozevíracího seznamu
cenová úroveň : ponechat výchozí možnost freePoznámka
Pokud jste nedosáhli maximálního počtu center na úrovni Free.
Po zřízení centra oznámení přejděte na tento prostředek.
Přejděte do nového centra oznámení.
V seznamu vyberte zásady přístupu (v části SPRAVOVAT).
Poznamenejte si hodnoty názvu zásady společně s odpovídajícími hodnotami připojovacího řetězce.
Konfigurace centra oznámení s informacemi o službě APNS
V části Notification Servicesvyberte Apple postupujte podle příslušných kroků na základě přístupu, který jste zvolili dříve v části Vytvoření certifikátu pro službu Notification Hubs.
Poznámka
Production použijte pro režim aplikace jenom v případě, že chcete odesílat nabízená oznámení uživatelům, kteří si aplikaci koupili ve Storu.
MOŽNOST 1: Použití certifikátu push .p12
Vybertecertifikátu
. Vyberte ikonu souboru.
Vyberte soubor .p12, který jste vyexportovali dříve, a pak vyberte Otevřít.
V případě potřeby zadejte správné heslo.
Vyberte režim sandboxu.
Vyberte Uložit.
MOŽNOST 2: Použití ověřování založeného na tokenech
Vyberte token.
Zadejte následující hodnoty, které jste získali dříve:
- id klíče
- ID sady
- id týmu
- tokenu
Zvoltesandboxu
. Vyberte Uložit.
Konfigurace centra oznámení s informacemi o FCM
- V Nastavení vlevo vyberte Google (GCM/FCM).
- Zadejte klíč serveru jste si poznamenali z Google Firebase Console.
- Na panelu nástrojů vyberte Uložit.
Vytvoření back-endové aplikace webového rozhraní API ASP.NET Core
V této části vytvoříte back-end ASP.NET Core Web API pro zpracování registrace zařízení a odesílání oznámení do mobilní aplikace Flutter.
Vytvoření webového projektu
V sady Visual Studio vyberte Soubor>Novýřešení .
Vyberte rozhraní .NET Core>App>ASP.NET Core>API>Next.
V dialogovém okně Konfigurace nového webového rozhraní API ASP.NET Core vyberte Target Framework.NET Core 3.1.
Jako název projektu
zadejte PushDemoApi a pak vyberteVytvořit .Spusťte ladění (Command + Enter) a otestujte aplikaci šablony.
Poznámka
Aplikace šablony je nakonfigurována tak, aby jako
launchUrl WeatherForecastController . Toto nastavení je nastaveno v Vlastnosti>launchSettings.json. Pokud se zobrazí výzva s nalezen neplatný vývojový certifikát, zpráva:
Kliknutím na Ano souhlasíte se spuštěním nástroje dotnet dev-certs https. Nástroj dotnet dev-certs https pak vyzve k zadání hesla pro certifikát a heslo klíčenky.
Po zobrazení výzvy k Nainstalovat a důvěřovat novémucertifikátu klikněte na Ano a zadejte heslo klíčenky.
Rozbalte složku Controllers a odstraňte WeatherForecastController.cs.
Odstranit WeatherForecast.cs.
Nastavte místní hodnoty konfigurace pomocí nástroje Secret Manager. Oddělení tajných kódů od řešení zajišťuje, že se nedokončí ve správě zdrojového kódu. Otevřete Terminal přejděte do adresáře souboru projektu a spusťte následující příkazy:
dotnet user-secrets init dotnet user-secrets set "NotificationHub:Name" <value> dotnet user-secrets set "NotificationHub:ConnectionString" <value>
Zástupné hodnoty nahraďte vlastním názvem centra oznámení a hodnotami připojovacího řetězce. Poznamenali jste si je v vytvoření centra oznámení oddílu. V opačném případě je můžete vyhledat v Azure.
NotificationHub:Name:
V souhrnuEssentials v horní částipřehledu se podívejte na název . NotificationHub:ConnectionString:
Viz výchozích zásad přístupuDefaultFullSharedAccessSignature v zásad přístupu Poznámka
V produkčních scénářích se můžete podívat na možnosti, jako je azure KeyVault pro bezpečné uložení připojovacího řetězce. Pro zjednodušení se tajné kódy přidají do nastavení aplikace služby Azure App Service.
Ověřování klientů pomocí klíče rozhraní API (volitelné)
Klíče rozhraní API nejsou tak bezpečné jako tokeny, ale pro účely tohoto kurzu budou stačit. Klíč rozhraní API lze snadno nakonfigurovat prostřednictvímmiddlewaru
Přidejte klíč rozhraní API do místních hodnot konfigurace.
dotnet user-secrets set "Authentication:ApiKey" <value>
Poznámka
Zástupnou hodnotu byste měli nahradit vlastní hodnotou a poznamenejte si ji.
Řízení V projektu Nová složkaPushDemoApi klikněte na , v nabídce Přidat klikněte naPřidat pomocíOvěřovací jakonázev složky. Ovládací prvek + Klikněte na ve složce Ověřování a pak v nabídce Přidat zvolte Nový soubor....
Vyberte
Obecné Prázdný třídy , zadejteApiKeyAuthOptions.cs pronázeva potom klikněte na Nový přidat následující implementaci.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; } } }
Do
ApiKeyAuthHandler.cs složkyAuthentication přidejte dalšíprázdnou třídu a přidejte následující implementaci.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)); } } }
Poznámka
Obslužná rutina ověřování je typ, který implementuje chování schématu, v tomto případě vlastní schéma klíče rozhraní API.
Do složky Authentication s názvem ApiKeyAuthenticationBuilderExtensions.cspřidejte další prázdnou třídu a pak přidejte následující implementaci.
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); } } }
Poznámka
Tato metoda rozšíření zjednodušuje kód konfigurace middlewaru v Startup.cs aby byl čitelnější a obecně srozumitelnější.
V Startup.csaktualizujte metodu ConfigureServices tak, aby se ověřování pomocí klíče rozhraní API konfiguruje pod voláním služeb . AddControllers metoda.
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); }
Stále v Startup.csaktualizujte metodu Configure tak, aby volala useAuthentication a UseAuthorization rozšiřující metody v IApplicationBuilder aplikace. Ujistěte se, že se tyto metody volají po UseRouting a před aplikací. 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(); }); }
Poznámka
Volání UseAuthentication zaregistruje middleware, který používá dříve registrovaná schémata ověřování (ConfigureServices). Musí se volat před jakýmkoli middlewarem, který závisí na ověřování uživatelů.
Přidání závislostí a konfigurace služeb
ASP.NET Core podporuje vzor návrhu softwaru
Použití centra oznámení a sady Notification Hubs SDK pro back-endové operace je zapouzdřeno v rámci služby. Služba se zaregistruje a zpřístupní prostřednictvím vhodné abstrakce.
Ovládací prvek Klikněte na ve složce závislostía pak zvolte Spravovat balíčky NuGet... .Vyhledejte Microsoft.Azure.NotificationHubs a ujistěte se, že je zaškrtnuté.
Klikněte na Přidat balíčkya po zobrazení výzvy k přijetí licenčních podmínek klikněte na Přijmout.
Ovládací prvek v projektu PushDemoApi klikněte na Nová složka, v nabídcePřidat klikněte naPřidat pomocí modelyjakonázev složky . Ovládací Klikněte na ve složce Modelya pak v nabídce Přidat zvolteNový soubor... .Vyberte
Obecné Prázdná třída , zadejtePushTemplates.cs pronázeva potom klepněte na tlačítko Nová přidání následující implementace.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)\" }"; } } }
Poznámka
Tato třída obsahuje tokenizované datové části oznámení pro obecná a bezobslužná oznámení vyžadovaná tímto scénářem. Datové části jsou definovány mimo Instalace, aby bylo možné experimentovat bez nutnosti aktualizovat stávající instalace prostřednictvím služby. Zpracování změn v instalacích tímto způsobem je mimo rozsah tohoto kurzu. V produkčním prostředí zvažte vlastní šablony.
Do složky Models s názvem DeviceInstallation.cspřidejte další prázdnou třídu a přidejte následující implementaci.
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>(); } }
Přidejte další Prázdnou třídu do složky Models s názvem NotificationRequest.csa přidejte následující implementaci.
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; } } }
Přidejte další Prázdnou třídu do složky Models s názvem NotificationHubOptions.csa přidejte následující implementaci.
using System.ComponentModel.DataAnnotations; namespace PushDemoApi.Models { public class NotificationHubOptions { [Required] public string Name { get; set; } [Required] public string ConnectionString { get; set; } } }
Přidejte novou složku do projektu PushDemoApi s názvem Services.
Přidejte
Prázdné rozhraní do složky Services s názvemINotificationService.cs a přidejte následující implementaci.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); } }
Do složky služby
Services s názvem NotificationHubsService.cs přidejteprázdnou třídu a pak přidejte následující kód pro implementaciINotificationService rozhraní: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); } } }
Poznámka
Výraz značky poskytnutý pro SendTemplateNotificationAsync je omezený na 20 značek. U většiny operátorů je omezena na 6, ale výraz v tomto případě obsahuje pouze ORS (||). Pokud požadavek obsahuje více než 20 značek, musí být rozděleny do více požadavků. Další podrobnosti najdete v dokumentaci směrování a výrazů značek.
V
Startup.cs aktualizujte metoduConfigureServices tak, aby se NotificationHubsServiceNotificationHubsService přidala jako jednoúčelová implementace 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(); }
Vytvoření rozhraní API pro oznámení
Ovládací prvek Klikněte na ve složce kontrolerya pak v nabídce Přidat zvolteNový soubor... .Vyberte ASP.NET Core>třídy kontroleru webového rozhraní API, zadejte NotificationsController název názeva potom klikněte na Nový.
Na začátek souboru přidejte následující obory názvů.
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;
Aktualizujte kontroler šablony tak, aby byl odvozen od ControllerBase a je zdoben atributem ApiController.
[ApiController] [Route("api/[controller]")] public class NotificationsController : ControllerBase { // Templated methods here }
Pokud jste se rozhodli dokončit
Ověřování klientů pomocí oddílu klíč rozhraní API, měli byste ozdobitNotificationsController také atributem Authorize .[Authorize]
Aktualizujte konstruktor tak, aby přijímal zaregistrovanou instanci INotificationService jako argument a přiřaďte ji ke členu jen pro čtení.
readonly INotificationService _notificationService; public NotificationsController(INotificationService notificationService) { _notificationService = notificationService; }
V launchSettings.json (ve složce Vlastnosti) změňte launchUrl z
weatherforecast
na api/notifications tak, aby odpovídaly adrese URL zadané v atributu RegistrationsControllerRoute.Spusťte ladění (Command + Enter) a ověřte, že aplikace pracuje s novým NotificationsController a vrátí 401 Neautorizováno stavu.
Poznámka
Visual Studio nemusí automaticky spustit aplikaci v prohlížeči. K otestování rozhraní API od tohoto okamžiku použijete Postman.
Na nové kartě Postman nastavte požadavek na GET. Zadejte níže uvedenou adresu a nahraďte zástupný
applicationUrl httpsapplicationUrl nalezeným v launchSettings.json vlastností. <applicationUrl>/api/notifications
Poznámka
applicationUrl by měl být pro výchozí profilhttps://localhost:5001. Pokud používáte
služby IIS (ve výchozím nastavení v sadě Visual Studio 2019 ve Windows), měli byste místo toho použítapplicationUrl zadanou v položce iisSettings. Pokud je adresa nesprávná, obdržíte odpověď 404. Pokud jste se rozhodli dokončit Ověření klientů pomocí oddílu klíč rozhraní API, nezapomeňte nakonfigurovat hlavičky požadavku tak, aby zahrnovaly klíč rozhraní APIkey hodnotu.
Klíč Hodnota apikey <your_api_key> Klikněte na tlačítko Odeslat.
Poznámka
Měli byste obdržet stav
200 OK s určitým obsahem JSON . Pokud se zobrazí upozornění
ověření certifikátu SSL , můžete v nastavenínastavenípřepnout ověření certifikátu SSL man.Post Nahraďte šablonované metody třídy v NotificationsController.cs následujícím kódem.
[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(); }
Vytvoření aplikace API
Teď vytvoříte aplikace API
Přihlaste se k webu azure Portal.
Klikněte na
Vytvořit prostředku, vyhledejte a zvolteaplikace APIa potom klikněte na Vytvořit .Aktualizujte následující pole a potom klikněte na Vytvořit.
název aplikace :
Zadejte globálně jedinečný název aplikace APIpředplatné :
Zvolte stejný cíl Předplatné, ve které jste centrum oznámení vytvořili.skupina prostředků :
Zvolte stejnou skupinu prostředků jste vytvořili centrum oznámení.plán/umístění služby App Service:
Vytvoření nového plánu služby App ServicePoznámka
Změňte výchozí možnost na plán, který zahrnuje podporu SSL. Jinak budete muset při práci s mobilní aplikací provést příslušné kroky, abyste zabránili zablokování požadavků http.
Application Insights:
Ponechte navrženou možnost (pomocí názvu se vytvoří nový prostředek) nebo vyberte existující prostředek.Po zřízení aplikace API
přejděte na tento prostředek. Poznamenejte si vlastnost adresy URL
v souhrnu Essentials v horní částipřehledu . Tato adresa URL je váš back-endový koncový bod, který se použije později v tomto kurzu. Poznámka
Adresa URL používá název aplikace API, který jste zadali dříve, s formátem
https://<app_name>.azurewebsites.net
.V seznamu vyberte konfigurace
(v částinastavení ). Pro každé z níže uvedených nastavení klepněte na tlačítko Nové nastavení aplikace zadejte Název a Hodnotaa potom klepněte na tlačítko OK.
Jméno Hodnota Authentication:ApiKey
<api_key_value> NotificationHub:Name
<hub_name_value> NotificationHub:ConnectionString
<hub_connection_string_value> Poznámka
Jedná se o stejná nastavení, která jste definovali dříve v uživatelských nastaveních. Měli byste být schopni je zkopírovat. Nastavení Authentication:ApiKey se vyžaduje jenom v případě, že jste se rozhodli dokončit ověřování klientů pomocí oddílu klíč rozhraní API. V produkčních scénářích se můžete podívat na možnosti, jako je azure KeyVault. Ty byly přidány jako nastavení aplikace pro zjednodušení v tomto případě.
Po přidání všech nastavení aplikace klikněte na Uložita pak Pokračovat.
Publikování back-endové služby
Dále nasadíte aplikaci do aplikace API, aby byla přístupná ze všech zařízení.
Poznámka
Následující kroky jsou specifické pro visual Studio pro Mac. Pokud sledujete visual studio 2019 ve Windows, tok publikování se bude lišit. Viz Publikování do služby Azure App Service ve Windows.
Pokud jste to ještě neudělali, změňte konfiguraci z ladění na release.
ovládací prvek Klikněte projektu PushDemoApiPushDemoApi a pak v nabídce Publikovat zvoltePublikovat do Azure... .Pokud k tomu budete vyzváni, postupujte podle toku ověřování. Použijte účet, který jste použili v předchozím vytvoření oddílu aplikace API.
Vyberte aplikaci API služby Azure App Service, kterou jste vytvořili dříve ze seznamu jako cíl publikování, a potom klikněte na Publikovat.
Po dokončení průvodce publikuje aplikaci do Azure a pak aplikaci otevře. Poznamenejte si adresy URL
Ověřování publikovaného rozhraní API
V Nástroj Postman otevřít novou kartu, nastavte požadavek na PUT a zadejte adresu níže. Zástupný symbol nahraďte základní adresou, kterou jste si poznamenali v předchozím publikujte back-endovou službu oddílu.
https://<app_name>.azurewebsites.net/api/notifications/installations
Poznámka
Základní adresa by měla být ve formátu
https://<app_name>.azurewebsites.net/
Pokud jste se rozhodli dokončit Ověření klientů pomocí oddílu klíč rozhraní API, nezapomeňte nakonfigurovat hlavičky požadavku tak, aby zahrnovaly klíč rozhraní APIkey hodnotu.
Klíč Hodnota apikey <your_api_key> Zvolte možnost
nezpracované protextua pak v seznamu možností formátu vyberte JSON a pak do pole se seznamem možností formátu zadejte zástupný symbolJSON: {}
Klikněte na Odeslat.
Poznámka
Měli byste obdržet stav 422 UnprocessableEntity ze služby.
Opakujte kroky 1 až 4, ale tentokrát zadáním koncového bodu požadavků ověřte, že obdržíte odpověď 400 Chybný požadavek.
https://<app_name>.azurewebsites.net/api/notifications/requests
Poznámka
Rozhraní API zatím není možné otestovat pomocí platných dat požadavků, protože to bude vyžadovat informace specifické pro platformu z klientské mobilní aplikace.
Vytvoření multiplatformní aplikace Flutter
V této části vytvoříte Flutter mobilní aplikaci, která implementuje nabízená oznámení multiplatformně.
Umožňuje registraci a zrušení registrace z centra oznámení prostřednictvím back-endové služby, kterou jste vytvořili.
Výstraha se zobrazí, když je zadána akce a aplikace je v popředí. V opačném případě se oznámení zobrazí v centru oznámení.
Poznámka
Obvykle byste během příslušného bodu životního cyklu aplikace (nebo v rámci prvního spuštění) prováděli akce registrace (a zrušení registrace) bez explicitních vstupů registrace nebo registrace uživatele. Tento příklad však bude vyžadovat explicitní vstup uživatele, aby bylo možné tuto funkci prozkoumat a snadněji testovat.
Vytvoření řešení Flutter
Otevřete novou instanci editoru Visual Studio Code.
Otevřete paletu příkazů (Shift + Command + P).
Vyberte Flutter: New Project command then press Enter.
Zadejte
push_demo pro název projektua vyberte umístění projektu .Po zobrazení výzvy k tomu zvolte Získat balíčky.
Ovládací + Klikněte na ve složce kotlin (v části aplikace>>hlavnísrc) a pak zvolte Zobrazit ve Finderu. Potom podřízené složky (ve složce kotlin) přejmenujte na
com
,<your_organization>
apushdemo
.Poznámka
Při použití šablony Visual Studio Code tyto složky standardně com, příklad, <project_name>. Za předpokladu, že se
mobcat používá proorganizace, měla by se struktura složek zobrazovat jako: - kotlin
- modelu com
- mobcat
- pushdemo
- mobcat
- modelu com
- kotlin
Zpátky v Visual Studio Codeaktualizujte hodnotu applicationId v aplikaci android>>build.gradle na
com.<your_organization>.pushdemo
.Poznámka
Jako zástupný symbol <your_organization> byste měli použít vlastní název organizace. Například použití mobcat, protože organizace bude mít za následek název balíčku hodnotu com.mobcat.pushdemo.
Aktualizujte atribut balíčku
v souborech AndroidManifest.xml v částiladění ,src hlavní aprofilu src. Ujistěte se, že hodnoty odpovídají applicationId, které jste použili v předchozím kroku. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.<your_organization>.pushdemo>"> ... </manifest>
Aktualizujte atribut
android:label
v souboru AndroidManifest.xml v části src>hlavní na PushDemo. Potom přidejte atributandroid:allowBackup
přímo podandroid:label
a nastavte jeho hodnotu na false.<application android:name="io.flutter.app.FlutterApplication" android:label="PushDemo" android:allowBackup="false" android:icon="@mipmap/ic_launcher"> ... </application>
Otevřete soubor build.gradle na úrovni aplikace (android>app>build.gradle), aktualizujte compileSdkVersion (v části android) tak, aby používal rozhraní API 29. Potom aktualizujte hodnoty minSdkVersion a targetSdkVersion (z oddílu defaultConfig) na 26 a 29.
Poznámka
Pro účely tohoto kurzu jsou podporována pouze zařízení, na kterých běží rozhraní API úrovně 26 a vyšší, ale můžete je rozšířit tak, aby podporovala zařízení se staršími verzemi.
Ovládací prvek Klikněte na ve složceios a pak zvolte Otevřít v Xcode .V
Xcode klikněte na Runner ( xcodeproj nahoře, ne na složku). Pak vyberte cíl spouštěče a vyberte kartu Obecné. Pokud je vybraná konfigurace sestavení Všechna, aktualizujte identifikátor sady nacom.<your_organization>.PushDemo
.Poznámka
Jako zástupný symbol <your_organization> byste měli použít vlastní název organizace. Například použití mobcat, protože organizace bude mít za následek identifikátor sady hodnotu com.mobcat.PushDemo.
Klikněte na
Info.plist potom aktualizujte hodnotu název sadyPushDemo Zavřete Xcode a vraťte se do visual Studio Code.
Zpátky v Visual Studio Codeotevřete pubspec.yaml, přidejte balíčky http a flutter_secure_storageDart jako závislosti. Potom soubor uložte a po zobrazení výzvy klikněte na Získat balíčky.
dependencies: flutter: sdk: flutter http: ^0.12.1 flutter_secure_storage: ^3.3.3
V Terminalzměňte adresář na složku ios (pro váš projekt Flutter). Potom spuštěním příkazu pod install nainstalujte nové pody (vyžadované balíčkem flutter_secure_storage).
Ovládací prvek + Klikněte na ve složce lib a potom v nabídce zvolte Nový soubor pomocí main_page.dart jako název souboru. Pak přidejte následující kód.
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>[], ) ) ); } }
V main.dartnahraďte kód v šabloně následujícím kódem.
import 'package:flutter/material.dart'; import 'package:push_demo/main_page.dart'; final navigatorKey = GlobalKey<NavigatorState>(); void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
V Terminálsestavte a spusťte aplikaci na každé cílové platformě, abyste mohli otestovat, že aplikace šablony běží na vašich zařízeních. Ujistěte se, že jsou podporovaná zařízení připojená.
flutter run
Implementace komponent pro různé platformy
Ovládací Klikněte na ve složcelib a pak v nabídce zvolteNová složka pomocí modelůjako název složky název složky . Ovládací + Klikněte na ve složce modely a pak v nabídce zvolte Nový soubor pomocí device_installation.dart jako název souboru. Pak přidejte následující kód.
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, }; }
Do složky modelů přidejte nový soubor s názvem push_demo_action.dart definování výčtu podporovaných akcí v tomto příkladu.
enum PushDemoAction { actionA, actionB, }
Přidejte do projektu novou složku s názvem services pak do této složky přidejte nový soubor s názvem device_installation_service.dart s následující implementací.
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); } }
Poznámka
Jako zástupný symbol <your_organization> byste měli použít vlastní název organizace. Například použití mobcat, protože organizace bude mít za následek MethodChannel název com.mobcat.pushdemo/deviceinstallation.
Tato třída zapouzdřuje práci s základní nativní platformou za účelem získání požadovaných podrobností o instalaci zařízení. MethodChannel usnadňuje obousměrnou asynchronní komunikaci s podkladovými nativními platformami. V dalších krocích se vytvoří protějšek specifický pro danou platformu pro tento kanál.
Do této složky přidejte další soubor s názvem notification_action_service.dart s následující implementací.
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; } } }
Poznámka
Používá se jako jednoduchý mechanismus pro centralizaci zpracování akcí oznámení, aby je bylo možné zpracovávat napříč platformami pomocí výčtu silného typu. Služba umožňuje základní nativní platformě aktivovat akci, pokud je určená v datové části oznámení. Umožňuje také běžnému kódu retrospektivní kontrolu, zda byla během spuštění aplikace zadána akce, jakmile je Flutter připravena ji zpracovat. Například když se aplikace spustí klepnutím na oznámení z centra oznámení.
Přidejte nový soubor do složky services s názvem notification_registration_service.dart s následující implementací.
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; } } }
Poznámka
Tato třída zapouzdřuje použití DeviceInstallationService a požadavků na back-endovou službu k provedení požadovaných akcí registrace, zrušení registrace a aktualizace. Argument apiKey se vyžaduje jenom v případě, že jste se rozhodli dokončit Ověření klientů pomocí oddílu klíč rozhraní API.
Přidejte nový soubor do složky lib s názvem config.dart s následující implementací.
class Config { static String apiKey = "API_KEY"; static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT"; }
Poznámka
Používá se jako jednoduchý způsob, jak definovat tajné kódy aplikací. Zástupné hodnoty nahraďte vlastními hodnotami. Měli byste si je poznamenat při vytváření back-endové služby. Adresa URL aplikace api by měla být
https://<api_app_name>.azurewebsites.net/
. Člen apiKey je vyžadován pouze v případě, že jste se rozhodli dokončit Ověření klientů pomocí oddílu klíč rozhraní API.Nezapomeňte ho přidat do souboru Gitignore, abyste se vyhnuli potvrzení těchto tajných kódů do správy zdrojového kódu.
Implementace uživatelského rozhraní pro různé platformy
V main_page.dartnahraďte funkci build následujícím kódem.
@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, ), ], ), ), ); }
Přidejte požadované importy do horní části souboru main_page.dart.
import 'package:push_demo/services/notification_registration_service.dart'; import 'config.dart';
Přidejte do třídy _MainPageState pole pro uložení odkazu na NotificationRegistrationService.
final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
Ve třídě
_MainPageState implementujte obslužné rutiny událostí proRegister aDeregister tlačítkaudálostí . Volejte odpovídající metody Register/Deregister metody a zobrazte výstrahu, která bude indikovat výsledek.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(); }, ), ], ); }, ); }
Nyní v main.dartzajistěte, aby v horní části souboru byly přítomny následující importy.
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';
Deklarujte proměnnou pro uložení odkazu na instanci NotificationActionService a inicializujete ji.
final notificationActionService = NotificationActionService();
Přidání funkcí pro zpracování zobrazení výstrahy při aktivaci akce
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(); }, ), ], ); }, ); }
Aktualizujte hlavní funkci, abyste mohli sledovat NotificationActionServiceakceTriggered stream a kontrolovat všechny akce zachycené během spouštění aplikace.
void main() async { runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,)); notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); }); await notificationActionService.checkLaunchAction(); }
Poznámka
Stačí jen předvést příjem a šíření akcí nabízených oznámení. Obvykle se jedná o tiché zpracování, například přechod do konkrétního zobrazení nebo aktualizace některých dat místo zobrazení výstrahy v tomto případě.
Konfigurace nativního projektu Androidu pro nabízená oznámení
Přidání souboru JSON služeb Google
Ovládací prvek Klikněte na ve složceandroidu a pak zvolte Otevřít v android Studiu . Pak přepněte do zobrazení Projectu (pokud ještě není).Vyhledejte dříve stažený soubor
google-services.json při nastavování projektuPushDemo vkonzolyFirebase . Potom ho přetáhněte do kořenového adresáře modulu aplikace ( android android aplikace ).
Konfigurace nastavení a oprávnění sestavení
Přepněte zobrazení Projectu na android.
Otevřete
AndroidManifest.xml a potom přidejte oprávněníINTERNET aREAD_PHONE_STATE za prvek aplikacepřed pravou značku . <manifest> <application>...</application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> </manifest>
Přidání sad Firebase SDK
V Android Studiootevřete soubor build.gradle na úrovni projektu (gradle Scripts>build.gradle (Project: android)). a ujistěte se, že máte cestu ke třídě com.google.gms:google-services v
buildscript
>závislostech uzlu.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 // ... } }
Poznámka
Nezapomeňte odkazovat na nejnovější verzi podle pokynů uvedených v konzole Firebase při vytváření projektu Android Project.
V souboru
build.gradle na úrovni aplikace (Gradle Scripts build.gradle (modul: aplikace) ), použijtemodul plug-inGoogle Services Gradle . Použijte modul plug-in přímo nad uzlem android. // ... // Add the following line: apply plugin: 'com.google.gms.google-services' // Google Services plugin android { // ... }
Ve stejném souboru v závislosti uzlu přidejte závislost pro knihovnu Cloud Messaging Android.
dependencies { // ... implementation 'com.google.firebase:firebase-messaging:20.2.0' }
Poznámka
Ujistěte se, že odkazujete na nejnovější verzi podle klientské dokumentace ke cloudovému zasílání zpráv pro Android.
Uložte změny a potom klikněte na tlačítko Synchronizovat nyní (na příkazovém řádku panelu nástrojů) nebo Synchronizovat projekt se soubory Gradle.
Zpracování nabízených oznámení pro Android
V
Android Studio Klikněte na nacom. (your_organization složku balíčku .pushdemo aplikace kotlin ), v nabídceNový zvolteBalíček . Jako název zadejte služby a stiskněte klávesu Return.Ovládací prvek + Klikněte na ve složce služeb, v nabídce New zvolte Kotlin File/Class. Jako název zadejte DeviceInstallationService a stiskněte Return.
Implementujte
DeviceInstallationService pomocí následujícího kódu. 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" } }
Poznámka
Tato třída implementuje protějšk specifický pro platformu pro kanál
com.<your_organization>.pushdemo/deviceinstallation
. Tato možnost byla definována v části Flutter aplikace v DeviceInstallationService.dart. V tomto případě se volání provádí z běžného kódu na nativního hostitele. Nezapomeňte nahradit <your_organization> vlastní organizací bez ohledu na to, kde se používá.Tato třída poskytuje jedinečné ID (pomocí Secure.AndroidId) jako součást datové části registrace centra oznámení.
Do složky služeb s názvem NotificationRegistrationServicepřidejte další Kotlin File/Class a pak přidejte následující kód.
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) } }
Poznámka
Tato třída implementuje protějšk specifický pro platformu pro kanál
com.<your_organization>.pushdemo/notificationregistration
. To bylo definováno v části Flutter aplikace v NotificationRegistrationService.dart. V tomto případě se volání provádí z nativního hostitele do společného kódu. Znovu se zastarejte o nahrazení <your_organization> vaší vlastní organizací, ať se používá kdekoli.Do složky
služeb s názvemNotificationActionService přidejte dalšíKotlin File/Class. Pak přidejte následující kód. 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() } } } }
Poznámka
Tato třída implementuje protějšk specifický pro platformu pro kanál
com.<your_organization>.pushdemo/notificationaction
. To bylo definováno v části Flutter aplikace v NotificationActionService.dart. V tomto případě je možné volat v obou směrech. Nezapomeňte nahradit <your_organization> vlastní organizací bez ohledu na to, kde se používá.Do com přidejte nový kotlinový soubor nebo třída.<your_organization>balíček .pushdemo s názvem PushNotificationsFirebaseMessagingServicea pak implementujte následující kód.
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)) } } } }
Poznámka
Tato třída zodpovídá za zpracování oznámení, když je aplikace spuštěná v popředí. Podmíněně zavolá triggerAction na NotificationActionService pokud je akce zahrnuta do datové části oznámení přijaté v onMessageReceived. Tím se také zavolá
refreshRegistration NotificationRegistrationService, když Firebase token znovu vygeneruje přepsáním funkceonNewToken .Znovu se postaráme o nahrazení <your_organization> vaší vlastní organizací bez ohledu na to, kde se používá.
V AndroidManifest.xml (app>src>main), přidejte PushNotificationsFirebaseMessagingService na konec elementu aplikace s filtrem záměru
com.google.firebase.MESSAGING_EVENT
.<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>
Vraťte se zpět do DeviceInstallationService, ujistěte se, že v horní části souboru jsou přítomné následující importy.
package com.<your_organization>.pushdemo import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
Poznámka
Nahraďte <your_organization> vlastní hodnotou organizace.
Aktualizujte zástupný text, Placeholder_Get_Value_From_FirebaseMessagingService_Implementation získat hodnotu tokenu z 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 }
V MainActivity se ujistěte, že jsou v horní části souboru přítomny následující importy.
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
Poznámka
Nahraďte <your_organization> vlastní hodnotou organizace.
Přidejte proměnnou pro uložení odkazu na DeviceInstallationService.
private lateinit var deviceInstallationService: DeviceInstallationService
Přidejte funkci s názvem
processNotificationActions a zkontrolujte, jestli záměrumá další hodnotu s názvem akce . Podmíněně aktivujte tuto akci nebo ji uložte pro pozdější použití, pokud se akce zpracovává během spuštění aplikace.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) } } } }
Přepište funkci onNewIntent tak, aby volala processNotificationActions.
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) processNotificationActions(intent) }
Poznámka
Vzhledem k tomu, že
LaunchMode pro MainActivity je nastavená naSingleTop , záměruse odešle do existující instance aktivity prostřednictvím onNew. FunkceIntent místo funkceonCreate , a proto musíte zpracovat příchozíintent vonCreate ifunkce onNewIntent .Přepište funkci
onCreate , nastavtedeviceInstallationService na novou instanci DeviceInstallationService .override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) } }
Nastavte vlastnosti notificationActionService a notificationRegistrationService vlastnosti PushNotificationFirebaseMessagingServices .
flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it) PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it) }
Ve stejné funkci podmíněně volejte FirebaseInstanceId.getInstance().instanceId. Implementujte
OnCompleteListener a nastavte výslednou hodnotu tokenu na PushNotificationFirebaseMessagingService před volánímrefreshRegistration .if(deviceInstallationService?.playServicesAvailable) { FirebaseInstanceId.getInstance().instanceId .addOnCompleteListener(OnCompleteListener { task -> if (!task.isSuccessful) return@OnCompleteListener PushNotificationsFirebaseMessagingService.token = task.result?.token PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration() }) }
Stále v onCreate, volání processNotificationActions na konci funkce. Pro argument launchAction použijte true, který indikuje, že se tato akce zpracovává během spuštění aplikace.
processNotificationActions(this.intent, true)
Poznámka
Aplikaci je nutné znovu zaregistrovat pokaždé, když ji spustíte, a zastavit ji z ladicí relace, abyste mohli pokračovat v přijímání nabízených oznámení.
Konfigurace nativního projektu pro iOS pro nabízená oznámení
Konfigurace cíle spouštěče a souboru Info.plist
V
editoru Visual Studio Code Ovládací prvek ve složceKlikněte na ios a potom zvolteOtevřít v Xcode .V Xcode klikněte na Runner (xcodeproj v horní části, ne na složku), vyberte Runner cíl a pak Možnosti & podepisování. Pokud je vybraná konfigurace sestavení
Všechny , zvolte svůj vývojářský účet protýmu. Ujistěte se, že je zaškrtnutá možnost Automaticky spravovat podepisování a že jsou automaticky vybrány podpisové certifikáty a zřizovací profil. Poznámka
Pokud novou hodnotu zřizovacího profilu nevidíte, zkuste aktualizovat profily podpisové identity tak, že vyberete Xcode>Předvolby>Účet potom výběrem tlačítka Stáhnout ruční profily profily stáhnout.
Klikněte na + Schopnosta vyhledejte nabízená oznámení. tuto funkci přidáte poklikáním na na nabízených oznámení.
Otevřete
Info.plist a nastavte minimální systémovou verzi na13.0 .Poznámka
Pro účely tohoto kurzu jsou podporována pouze zařízení se systémem iOS 13.0 a vyššími, ale můžete je rozšířit tak, aby podporovala zařízení se staršími verzemi.
Otevřete
Runner.entitlements a ujistěte se, že je nastavení prostředí APS nastaveno na vývojový .
Zpracování nabízených oznámení pro iOS
Ovládací Klikněte na ve složce spouštěče(v projektu Runner) a pak jako název zvolte Nová skupina pomocíServices. Ovládací prvek Klikněte na ve složceServices a pak zvolte Nový soubor... . Pak zvolteSwift File a klikněte naDalší . Jako název zadejte DeviceInstallationService a klikněte na Vytvořit.Implementujte DeviceInstallationService.swift pomocí následujícího kódu.
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." } }
Poznámka
Tato třída implementuje protějšk specifický pro platformu pro kanál
com.<your_organization>.pushdemo/deviceinstallation
. Tato možnost byla definována v části Flutter aplikace v DeviceInstallationService.dart. V tomto případě se volání provádí z běžného kódu na nativního hostitele. Nezapomeňte nahradit <your_organization> vlastní organizací bez ohledu na to, kde se používá.Tato třída poskytuje jedinečné ID (pomocí hodnoty UIDevice.identifierForVendor) jako součást datové části registrace centra oznámení.
Do složky služby
Services přidejte další Swift File s názvemNotificationRegistrationService a pak přidejte následující kód.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) } }
Poznámka
Tato třída implementuje protějšk specifický pro platformu pro kanál
com.<your_organization>.pushdemo/notificationregistration
. To bylo definováno v části Flutter aplikace v NotificationRegistrationService.dart. V tomto případě se volání provádí z nativního hostitele do společného kódu. Znovu se zastarejte o nahrazení <your_organization> vaší vlastní organizací, ať se používá kdekoli.Do složky služby
Services s názvem NotificationAction Service přidejte dalšísoubor Swift File a pak přidejte následující kód.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) } } }
Poznámka
Tato třída implementuje protějšk specifický pro platformu pro kanál
com.<your_organization>.pushdemo/notificationaction
. To bylo definováno v části Flutter aplikace v NotificationActionService.dart. V tomto případě je možné volat v obou směrech. Nezapomeňte nahradit <your_organization> vlastní organizací bez ohledu na to, kde se používá.V AppDelegate.swiftpřidejte proměnné pro uložení odkazu na služby, které jste vytvořili dříve.
var deviceInstallationService : DeviceInstallationService? var notificationRegistrationService : NotificationRegistrationService? var notificationActionService : NotificationActionService?
Přidejte funkci s názvem processNotificationActions pro zpracování dat oznámení. Podmíněně aktivujte tuto akci nebo ji uložte pro pozdější použití, pokud se akce zpracovává během spuštění aplikace.
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) } } }
Přepište funkci didRegisterForRemoteNotificationsWithDeviceToken nastavením hodnoty tokenu pro DeviceInstallationService. Potom volejte refreshRegistrationNotificationRegistrationService.
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { deviceInstallationService?.token = deviceToken notificationRegistrationService?.refreshRegistration() }
Přepište funkci didReceiveRemoteNotification předávání argumentu userInfo funkci processNotificationActions.
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { processNotificationActions(userInfo: userInfo) }
Přepište funkci didFailToRegisterForRemoteNotificationsWithError zaprotokolujte chybu.
override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print(error); }
Poznámka
Toto je velmi zástupný symbol. Pro produkční scénáře budete chtít implementovat správné protokolování a zpracování chyb.
V
didFinishLaunchingWithOptions vytvořte instancideviceInstallationService , notificationRegistrationService anotificationActionService proměnných.let controller : FlutterViewController = window?.rootViewController as! FlutterViewController deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger) notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger) notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
Ve stejné funkci podmíněně požádejte o autorizaci a zaregistrujte vzdálená oznámení.
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() } } } }
Pokud
launchOptions obsahuje klíč remoteNotification , zavolejteprocessNotificationActions na koncididFinishLaunchingWithOptions funkce. Předejte výsledný objekt userInfo a pro argument launch Action použijte true. Hodnota true označuje, že se akce zpracovává během spouštění aplikace.if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] { processNotificationActions(userInfo: userInfo, launchAction: true) }
Otestování řešení
Teď můžete otestovat odesílání oznámení prostřednictvím back-endové služby.
Odeslání testovacího oznámení
Otevřete novou kartu v postman.
Nastavte požadavek na POSTa zadejte následující adresu:
https://<app_name>.azurewebsites.net/api/notifications/requests
Pokud jste se rozhodli dokončit Ověření klientů pomocí oddílu klíč rozhraní API, nezapomeňte nakonfigurovat hlavičky požadavku tak, aby zahrnovaly klíč rozhraní APIkey hodnotu.
Klíč Hodnota apikey <your_api_key> Zvolte možnost
nezpracované protextua pak v seznamu možností formátu vyberte JSON a pak do pole se seznamem možností formátu zadejte zástupný symbolJSON: { "text": "Message from Postman!", "action": "action_a" }
Vyberte tlačítko Code, které je pod tlačítkem Uložit v pravém horním rohu okna. Požadavek by měl vypadat podobně jako v následujícím příkladu při zobrazení HTML (v závislosti na tom, jestli jste zahrnuli hlavičku apikey):
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" }
Spusťte aplikaci PushDemo na jedné nebo obou cílových platformách (Android a iOS).
Poznámka
Pokud testujete na android ujistěte se, že v ladicíneběží, nebo pokud je aplikace nasazená spuštěním aplikace, vynuťte zavření aplikace a spusťte ji znovu od spouštěče.
V aplikaci PushDemo klepněte na tlačítko Zaregistrovat.
Zpátky v postmanzavřete okno Generovat fragmenty kódu (pokud jste to ještě neudělali) a klikněte na tlačítko Odeslat.
Ověřte, že se v Postman zobrazí odpověď 200 OK a že se v aplikaci zobrazí výstraha zobrazující akce ActionA přijatá.
Zavřete aplikaci PushDemo a potom znovu klikněte na tlačítko Odeslat v Postman.
Ověřte, že se v Postman znovu zobrazí odpověď 200 OK. Ověřte, že se v oznamovací oblasti aplikace PushDemo zobrazí oznámení se správnou zprávou.
Klepnutím na oznámení potvrďte, že se aplikace otevře a zobrazila akce ActionA přijatá upozornění.
Zpátky v postmanupravte předchozí text požadavku tak, aby se místo action_a pro hodnotu akce odeslalo tiché oznámení, které určuje action_b.
{ "action": "action_b", "silent": true }
Když je aplikace stále otevřená, klikněte na tlačítko Odeslat v Postman.
Ověřte, že se v postman zobrazí odpověď 200 OK a že se v aplikaci zobrazuje akce ActionB obdržela místo akce ActionA přijatá.
Zavřete aplikaci PushDemo a potom znovu klikněte na tlačítko Odeslat v Postman.
Ověřte, že se v Postman zobrazí odpověď 200 OK a že se v oznamovací oblasti nezobrazí tiché oznámení.
Řešení problémů
Žádná odpověď z back-endové služby
Při místním testování se ujistěte, že je back-endová služba spuštěná a že používá správný port.
Pokud testujete aplikace Azure API, zkontrolujte, jestli je služba spuštěná a je nasazená a spuštěná bez chyby.
Při testování prostřednictvím klienta nezapomeňte správně zkontrolovat základní adresu v Postman nebo v konfiguraci mobilní aplikace. Základní adresa by měla být při místním testování https://<api_name>.azurewebsites.net/
nebo https://localhost:5001/
.
Po spuštění nebo zastavení ladicí relace nepřicházejí oznámení v Androidu
Po spuštění nebo zastavení ladicí relace se ujistěte, že se znovu zaregistrujete. Ladicí program způsobí vygenerování nového tokenu Firebase. Instalace centra oznámení musí být také aktualizována.
Příjem stavového kódu 401 z back-endové služby
Ověřte, že nastavujete hlavičku požadavku apikey a tato hodnota odpovídá hlavičce požadavku, kterou jste nakonfigurovali pro back-endovou službu.
Pokud se při místním testování zobrazí tato chyba, ujistěte se, že hodnota klíče, kterou jste definovali v konfiguraci klienta, odpovídá hodnotě
Pokud testujete pomocíaplikace API
Poznámka
Pokud jste po nasazení back-endové služby vytvořili nebo změnili toto nastavení, musíte službu restartovat, aby se projevila.
Pokud jste se rozhodli nedokončíte Ověřovat klienty pomocí oddílu klíč rozhraní API, ujistěte se, že jste u třídy NotificationsController nepoužádali atribut Authorize.
Příjem stavového kódu 404 z back-endové služby
Ověřte správnost koncového bodu a metody požadavku HTTP. Například koncové body by měly být orientační:
-
[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
Nebo při místním testování:
-
[PUT]
https://localhost:5001/api/notifications/installations
-
[DELETE]
https://localhost:5001/api/notifications/installations/<installation_id>
-
[POST]
https://localhost:5001/api/notifications/requests
Při zadávání základní adresy v klientské aplikaci se ujistěte, že končí /
. Základní adresa by měla být při místním testování https://<api_name>.azurewebsites.net/
nebo https://localhost:5001/
.
Nejde zaregistrovat a zobrazí se chybová zpráva centra oznámení
Ověřte, že testovací zařízení má síťové připojení. Potom určete stavový kód odpovědi HTTP nastavením zarážky pro kontrolu hodnoty vlastnosti StatusCode v HttpResponse.
Projděte si předchozí návrhy řešení potíží, kde je to možné na základě stavového kódu.
Nastavte zarážku na řádcích, které vracejí tyto konkrétní stavové kódy pro příslušné rozhraní API. Pak zkuste při místním ladění volat back-endovou službu.
Ověřte, že back-endová služba funguje podle očekávání prostřednictvím Postman s použitím příslušné datové části. Použijte skutečnou datovou část vytvořenou kódem klienta pro danou platformu.
Projděte si oddíly konfigurace specifické pro danou platformu a ujistěte se, že nebyly zmeškané žádné kroky. Zkontrolujte, jestli se pro installation id
a token
proměnné pro příslušnou platformu řeší vhodné hodnoty.
Nejde vyřešit ID chybové zprávy zařízení
Projděte si oddíly konfigurace specifické pro danou platformu a ujistěte se, že nebyly zmeškané žádné kroky.
Související odkazy
- přehled služby Azure Notification Hubs
- Instalace flutteru v systému macOS
- instalace flutteru ve Windows
- sada Notification Hubs SDK pro back-endové operace
- sada Notification Hubs SDK na GitHubu
- Registrace v back-endovém aplikace
- správa registrací
- Práce se značkami
- Práce s vlastními šablonami
Další kroky
Teď byste měli mít základní aplikaci Flutter připojenou k centru oznámení prostřednictvím back-endové služby a můžou odesílat a přijímat oznámení.
Pravděpodobně budete muset přizpůsobit příklad použitý v tomto kurzu tak, aby vyhovoval vašemu vlastnímu scénáři. Doporučujeme také implementovat robustnější zpracování chyb, logiku opakování a protokolování.
Visual Studio App Center je možné rychle začlenit do mobilních aplikací, které poskytují analytické a diagnostické, které vám pomůžou při řešení potíží.