Udostępnij za pośrednictwem


Samouczek: wysyłanie powiadomień wypychanych do aplikacji Flutter przy użyciu usługi Azure Notification Hubs za pośrednictwem usługi zaplecza

Pobierz przykład Pobierz przykładową

  • zestawu narzędzi Xamarin.Forms
  • Flutter
  • Natywna React

W tym samouczku użyjesz usługi Azure Notification Hubs do wypychania powiadomień do aplikacji Flutter przeznaczonej dla systemu Android i systemu iOS.

Zaplecze internetowego interfejsu API platformy ASP.NET Core służy do obsługi rejestracji urządzeń dla klienta przy użyciu najnowszego i najlepszego podejścia instalacji. Usługa będzie również wysyłać powiadomienia wypychane w sposób międzyplatformowy.

Te operacje są obsługiwane przy użyciu zestawu SDK usługi Notification Hubs na potrzeby operacji zaplecza. Dalsze szczegółowe informacje na temat ogólnego podejścia przedstawiono w dokumentacji Rejestrowanie z zaplecza aplikacji.

Ten samouczek zawiera następujące kroki:

Warunki wstępne

Aby wykonać następujące czynności, wymagane są następujące elementy:

  • Subskrypcja platformy Azure , w której można tworzyć zasoby i zarządzać nimi.
  • Zestaw narzędzi Flutter (wraz z wymaganiami wstępnymi).
  • programu Visual Studio Code z zainstalowanymi wtyczk ami Flutter i Dart.
  • cocoaPods zainstalowane na potrzeby zarządzania zależnościami biblioteki.
  • Możliwość uruchamiania aplikacji na urządzeniach z systemem Android (fizycznych lub emulatorowych) lub systemu iOS (tylko urządzenia fizyczne).

W przypadku systemu Android musisz mieć następujące elementy:

  • Odblokowane urządzenie fizyczne dewelopera lub emulator (z zainstalowanym interfejsem API 26 lub nowszym z zainstalowanymi usługami Google Play).

W przypadku systemu iOS musisz mieć następujące elementy:

  • Aktywne konto dewelopera firmy Apple.
  • Fizyczne urządzenie z systemem iOS zarejestrowane na koncie dewelopera(z systemem iOS 13.0 lub nowszym).
  • Certyfikat dewelopera .p12zainstalowany w pęku kluczy umożliwia uruchamianie aplikacji na urządzeniu fizycznym.

Nuta

Symulator systemu iOS nie obsługuje powiadomień zdalnych, dlatego urządzenie fizyczne jest wymagane podczas eksplorowania tego przykładu w systemie iOS. Nie trzeba jednak uruchamiać aplikacji zarówno w android, jak i systemu iOS, aby ukończyć ten samouczek.

Możesz wykonać kroki opisane w tym przykładzie z pierwszymi zasadami bez wcześniejszego doświadczenia. Jednak skorzystasz z znajomości następujących aspektów.

Podane kroki dotyczą systemu macOS. W windows można śledzić, pomijając aspekty iOS.

Konfigurowanie usług powiadomień wypychanych i Usługi Azure Notification Hub

W tej sekcji skonfigurujesz usługę Firebase Cloud Messaging (FCM) i usług Apple Push Notification Services (APNS). Następnie utworzysz i skonfigurujesz centrum powiadomień do pracy z tymi usługami.

Tworzenie projektu Firebase i włączanie usługi Firebase Cloud Messaging dla systemu Android

  1. Zaloguj się do konsoli programu Firebase. Utwórz nowy projekt Firebase wprowadzający PushDemo jako nazwę projektu .

    Nuta

    Zostanie wygenerowana unikatowa nazwa. Domyślnie składa się to z małego wariantu podanej nazwy oraz wygenerowanej liczby rozdzielonej kreską. Możesz to zmienić, jeśli chcesz podać, że jest ona nadal unikatowa globalnie.

  2. Po utworzeniu projektu wybierz pozycję Dodaj bazę firebase do aplikacji systemu Android.

    Dodawanie bazy firebase do aplikacji systemu Android

  3. Na stronie Dodaj bazę firebase do aplikacji systemu Android wykonaj następujące kroki.

    1. W polu nazwa pakietu systemu Android wprowadź nazwę pakietu. Na przykład: com.<organization_identifier>.<package_name>.

      Określ nazwę pakietu

    2. Wybierz pozycję Zarejestruj aplikację.

    3. Wybierz pozycję Pobierz google-services.json. Następnie zapisz plik w folderze lokalnym do późniejszego użycia i wybierz pozycję Dalej.

      pobierz google-services.json

    4. Wybierz pozycję Dalej.

    5. Wybierz pozycję Kontynuuj, aby konsoli

      Nuta

      Jeśli przycisk Kontynuuj konsoli nie jest włączony, ponieważ sprawdzić instalacji, wybierz pozycję Pomiń ten krok.

  4. W konsoli Firebase wybierz koła zębatego dla projektu. Następnie wybierz pozycję Ustawienia projektu.

    wybierz pozycję Ustawienia projektu

    Nuta

    Jeśli nie pobrano pliku google-services.json, możesz go pobrać na tej stronie.

  5. Przejdź do karty Cloud Messaging u góry. Skopiuj i zapisz klucz serwera do późniejszego użycia. Ta wartość służy do konfigurowania centrum powiadomień.

    kopiowanie klucza serwera

Rejestrowanie aplikacji systemu iOS na potrzeby powiadomień wypychanych

Aby wysyłać powiadomienia wypychane do aplikacji systemu iOS, zarejestruj aplikację w usłudze Apple, a także zarejestruj się w celu otrzymywania powiadomień wypychanych.

  1. Jeśli aplikacja nie została jeszcze zarejestrowana, przejdź do portalu aprowizacji systemu iOS w Centrum deweloperów firmy Apple. Zaloguj się do portalu przy użyciu identyfikatora Apple ID, przejdź do pozycji certyfikaty , identyfikatory & profile, a następnie wybierz pozycję identyfikatory . Kliknij +, aby zarejestrować nową aplikację.

    stronie identyfikatorów aplikacji portalu aprowizacji systemu iOS

  2. Na ekranie Zarejestruj nowy identyfikator wybierz przycisk radiowy Identyfikatory aplikacji. Następnie wybierz pozycję Kontynuuj.

    portal aprowizacji systemu iOS rejestruje nową stronę identyfikatora

  3. Zaktualizuj następujące trzy wartości dla nowej aplikacji, a następnie wybierz pozycję Kontynuuj:

    • Opis: wpisz opisową nazwę aplikacji.

    • identyfikator pakietu: wprowadź identyfikator pakietu formularza com.<organization_identifier>.<product_name> jak wspomniano w przewodniku dystrybucji aplikacji . Na poniższym zrzucie ekranu wartość mobcat jest używana jako identyfikator organizacji, a wartość PushDemo jest używana jako nazwa produktu.

      stronie rejestrowania identyfikatora aplikacji w portalu aprowizacji systemu iOS

    • powiadomienia wypychane: sprawdź opcję powiadomienia wypychane w sekcji Capabilities (Możliwości ).

      formularz do zarejestrowania nowego identyfikatora aplikacji

      Ta akcja generuje identyfikator aplikacji i żąda potwierdzenia informacji. Wybierz pozycję Kontynuuj, a następnie wybierz pozycję Zarejestruj, aby potwierdzić nowy identyfikator aplikacji.

      potwierdzić nowego identyfikatora aplikacji

      Po wybraniu pozycji Zarejestrujzostanie wyświetlony nowy identyfikator aplikacji jako element wiersza na stronie Certificates, Identifiers & Profiles( Identyfikatory & Profiles).

  4. Na stronie Certificates (Certyfikaty) identyfikatory & Profiles w obszarze Identifiers (Identyfikatory) znajdź utworzony element wiersza Identyfikator aplikacji. Następnie wybierz wiersz, aby wyświetlić ekran Edytuj konfigurację identyfikatora aplikacji ekranu.

Tworzenie certyfikatu dla usługi Notification Hubs

Certyfikat jest wymagany, aby umożliwić centrum powiadomień pracę z usługą Apple Push Notification Services (APNS) i można je udostępnić na jeden z dwóch sposobów:

  1. Tworzenie certyfikatu wypychania p12, który można przekazać bezpośrednio do usługi Notification Hub (oryginalne podejście)

  2. Tworzenie certyfikatu p8, który może służyć do uwierzytelniania opartego na tokenach (nowsze i zalecane podejście)

Nowsze podejście ma wiele korzyści, jak opisano w uwierzytelnianie oparte na tokenach (HTTP/2) dla usługi APNS. Wymagana jest mniejsza liczba kroków, ale jest również wymagana w przypadku określonych scenariuszy. Jednak kroki zostały podane dla obu metod, ponieważ oba te metody będą działać na potrzeby tego samouczka.

OPCJA 1. Tworzenie certyfikatu wypychania p12, który można przekazać bezpośrednio do centrum powiadomień
  1. Na komputerze Mac uruchom narzędzie Keychain Access. Można go otworzyć z folderu Utilities lub folderu Other na launchpad.

  2. Wybierz dostępu do pęku kluczy, rozwiń Asystent certyfikatów, a następnie wybierz pozycję Zażądaj certyfikatu zurzędu certyfikacji.

    użyj dostępu łańcucha kluczy, aby zażądać nowego certyfikatu

    Nuta

    Domyślnie dostęp do pęku kluczy wybiera pierwszy element na liście. Może to być problem, jeśli jesteś w kategorii certyfikatów i Urząd certyfikacji Relacji deweloperów firmy Apple nie jest pierwszym elementem na liście. Przed wygenerowaniem żądania CSR (żądanie podpisania certyfikatu) upewnij się, że masz element inny niż klucz lub urzędu certyfikacji Apple Worldwide Developer Relations Authority.

  3. Wybierzadres e-mail użytkownika , wprowadź wartość nazwa pospolita, upewnij się, że określono Zapisano na dysku, a następnie wybierz pozycję Kontynuuj. Pozostaw adres e-mail urzędu certyfikacji puste, ponieważ nie jest to wymagane.

    oczekiwane informacje o certyfikacie

  4. Wprowadź nazwę pliku żądania podpisania certyfikatu (CSR) w Zapisz jakowybierz lokalizację w Gdzie, a następnie wybierz Zapisz.

    Wybierz nazwę pliku dla certyfikatu

    Ta akcja zapisuje plik CSR w wybranej lokalizacji. Domyślną lokalizacją jest Desktop. Zapamiętaj lokalizację wybraną dla pliku.

  5. Po powrocie do strony Certificates, Identifiers & Profiles na stronie iOS Provisioning Portalprzewiń w dół do zaznaczonej opcji Wypychane powiadomienia, a następnie wybierz pozycję Konfiguruj, aby utworzyć certyfikat.

    edytowanie strony identyfikatora aplikacji

  6. Zostanie wyświetlone okno Certyfikat y TLS/SSL usługi Apple Push Notification Service. Wybierz przycisk Utwórz certyfikat w sekcji Programowanie certyfikatu TLS/SSL.

    przycisk Utwórz certyfikat dla identyfikatora aplikacji

    Zostanie wyświetlony ekran tworzenie nowego certyfikatu .

    Nuta

    W tym samouczku jest używany certyfikat programowania. Ten sam proces jest używany podczas rejestrowania certyfikatu produkcyjnego. Podczas wysyłania powiadomień upewnij się, że używasz tego samego typu certyfikatu.

  7. Wybierz pozycję Wybierz plik, przejdź do lokalizacji, w której zapisano plik CSR, a następnie kliknij dwukrotnie nazwę certyfikatu, aby go załadować. Następnie wybierz pozycję Kontynuuj.

  8. Po utworzeniu certyfikatu w portalu wybierz przycisk Pobierz. Zapisz certyfikat i zapamiętaj lokalizację, do której został zapisany.

    strona pobierania certyfikatu wygenerowanego

    Certyfikat jest pobierany i zapisywany na komputerze w folderze Pobrane.

    lokalizowanie pliku certyfikatu w folderze Pobrane

    Nuta

    Domyślnie pobrany certyfikat dewelopera ma nazwę aps_development.cer.

  9. Kliknij dwukrotnie pobrany certyfikat wypychania aps_development.cer. Ta akcja powoduje zainstalowanie nowego certyfikatu w łańcucha kluczy, jak pokazano na poniższej ilustracji:

    lista certyfikatów dostępu łańcucha kluczy z wyświetlonymi nowymi certyfikatów

    Nuta

    Mimo że nazwa certyfikatu może być inna, nazwa będzie poprzedzona Apple Development iOS Push Services i ma skojarzony z nim odpowiedni identyfikator pakietu.

  10. W obszarze Dostęp do pęku kluczy Kontrolakliknij na nowym certyfikacie wypychania utworzonym w kategorii certyfikatów . Wybierz pozycję Eksportuj, nadaj plikowi nazwę, wybierz format p12, a następnie wybierz pozycję Zapisz.

    Eksportuj certyfikat jako formatu p12

    Możesz wybrać ochronę certyfikatu przy użyciu hasła, ale hasło jest opcjonalne. Kliknij przycisk OK, jeśli chcesz pominąć tworzenie haseł. Zanotuj nazwę pliku i lokalizację wyeksportowanego certyfikatu p12. Są one używane do włączania uwierzytelniania za pomocą usługi APNs.

    Nuta

    Nazwa i lokalizacja pliku p12 mogą być inne niż to, co zostało na zdjęciu w tym samouczku.

OPCJA 2: Tworzenie certyfikatu p8, który może być używany do uwierzytelniania opartego na tokenach
  1. Zanotuj następujące szczegóły:

    • prefiks identyfikatora aplikacji (identyfikator zespołu)
    • identyfikator pakietu
  2. Po powrocie do certyfikatów identyfikatory & Profileskliknij pozycję Keys.

    Nuta

    Jeśli masz już klucz skonfigurowany dla usługi APNS, możesz ponownie użyć certyfikatu p8 pobranego bezpośrednio po jego utworzeniu. Jeśli tak, możesz zignorować kroki 3 za pośrednictwem 5.

  3. Kliknij przycisk + (lub przycisk Utwórz klucz), aby utworzyć nowy klucz.

  4. Podaj odpowiednią wartość Nazwa klucza, a następnie zaznacz opcję Apple Push Notifications Service (APNS), a następnie kliknij przycisk Kontynuuj, a następnie Zarejestruj na następnym ekranie.

  5. Kliknij Pobierz, a następnie przenieś plik p8 (poprzedzony AuthKey_) do bezpiecznego katalogu lokalnego, a następnie kliknij przycisk Gotowe.

    Nuta

    Pamiętaj, aby zachować plik p8 w bezpiecznym miejscu (i zapisać kopię zapasową). Po pobraniu klucza nie można go ponownie pobrać, ponieważ kopia serwera zostanie usunięta.

  6. Na Kluczekliknij utworzony klucz (lub istniejący klucz, jeśli chcesz go użyć).

  7. Zanotuj wartość identyfikatora klucza .

  8. Otwórz certyfikat p8 w odpowiedniej wybranej aplikacji, takiej jak Visual Studio Code. Zanotuj wartość klucza (między kluczem prywatnym -----BEGIN----- a -----END PRIVATE KEY-----).

    -----BEGIN KLUCZ PRYWATNY-----
    <key_value>
    -----END PRIVATE KEY-----

    Nuta

    Jest to wartość tokenu , która będzie używana później do konfigurowania Notification Hub.

Na końcu tych kroków powinny być dostępne następujące informacje do późniejszego użycia w Konfigurowanie centrum powiadomień przy użyciu informacji usługi APNS:

  • identyfikator zespołu (zobacz krok 1)
  • identyfikator pakietu (zobacz krok 1)
  • identyfikator klucza (zobacz krok 7)
  • wartość tokenu (wartość klucza p8 uzyskana w kroku 8)

Tworzenie profilu aprowizacji dla aplikacji

  1. Wróć do portalu aprowizacji systemu iOS, wybierz pozycję certyfikaty , identyfikatory & profile, wybierz pozycję profile z menu po lewej stronie, a następnie wybierz pozycję +, aby utworzyć nowy profil. Zostanie wyświetlony ekran Rejestrowanie nowego profilu aprowizacji.

  2. Wybierz pozycję tworzenie aplikacji systemu iOS w obszarze Development jako typ profilu aprowizacji, a następnie wybierz pozycję Kontynuuj.

    lista profilów aprowizacji

  3. Następnie wybierz identyfikator aplikacji utworzony z listy rozwijanej Identyfikator aplikacji, a następnie wybierz pozycję Kontynuuj.

    Wybierz identyfikatora aplikacji

  4. W oknie Wybierz certyfikaty wybierz certyfikat dewelopera używany do podpisywania kodu, a następnie wybierz pozycję Kontynuuj.

    Nuta

    Ten certyfikat nie jest certyfikatem wypychania utworzonym w poprzednim kroku . Jest to certyfikat dewelopera. Jeśli taki nie istnieje, musisz go utworzyć, ponieważ jest to wymagania wstępne dla tego samouczka. Certyfikaty deweloperów można utworzyć w witrynie Apple Developer Portalza pośrednictwem Xcode lub programu Visual Studio.

  5. Wróć do strony certyfikatów , identyfikatorów & profilów, wybierz pozycję Profile z menu po lewej stronie, a następnie wybierz pozycję +, aby utworzyć nowy profil. Zostanie wyświetlony ekran Rejestrowanie nowego profilu aprowizacji.

  6. W oknie Wybierz certyfikaty wybierz utworzony certyfikat dewelopera. Następnie wybierz pozycję Kontynuuj.

  7. Następnie wybierz urządzenia do użycia do testowania, a następnie wybierz pozycję Kontynuuj.

  8. Na koniec wybierz nazwę profilu w Nazwa profilu aprowizacji, a następnie wybierz pozycję Wygeneruj.

    Wybierz nazwę profilu aprowizacji

  9. Po utworzeniu nowego profilu aprowizacji wybierz pozycję Pobierz. Zapamiętaj lokalizację, do której został zapisany.

  10. Przejdź do lokalizacji profilu aprowizacji, a następnie kliknij go dwukrotnie, aby zainstalować go na maszynie dewelopera.

Tworzenie centrum powiadomień

W tej sekcji utworzysz centrum powiadomień i skonfigurujesz uwierzytelnianie za pomocą usługi APNS. Możesz użyć certyfikatu wypychania p12 lub uwierzytelniania opartego na tokenach. Jeśli chcesz użyć centrum powiadomień, które zostało już utworzone, możesz przejść do kroku 5.

  1. Zaloguj się do usługi Azure.

  2. Kliknij pozycję Utwórz zasób, a następnie wyszukaj i wybierz pozycję Notification Hub, a następnie kliknij pozycję Utwórz.

  3. Zaktualizuj następujące pola, a następnie kliknij pozycję Utwórz:

    PODSTAWOWE SZCZEGÓŁY

    subskrypcja : wybierz docelową subskrypcję z listy rozwijanej
    grupa zasobów: Utwórz nową grupę zasobów (lub wybierz istniejącą)

    SZCZEGÓŁY PRZESTRZENI NAZW

    przestrzeń nazw centrum powiadomień: wprowadź globalnie unikatową nazwę Notification Hub przestrzeni nazw

    Nuta

    Upewnij się , że dla tego pola jest wybrana opcja Utwórz nowy.

    SZCZEGÓŁY CENTRUM POWIADOMIEŃ

    Notification Hub: wprowadź nazwę usługi Notification Hub
    Lokalizacja: Wybierz odpowiednią lokalizację z listy rozwijanej
    Warstwa cenowa: Zachowaj domyślną opcję Bezpłatna

    Nuta

    Chyba że osiągnięto maksymalną liczbę centrów w warstwie Bezpłatna.

  4. Po aprowizowaniu usługi Notification Hub przejdź do tego zasobu.

  5. Przejdź do nowego centrum powiadomień .

  6. Wybierz zasady dostępu z listy (w obszarze ZARZĄDZAJ).

  7. Zanotuj wartości nazwa zasad wraz z odpowiednimi wartościami parametrów połączenia .

Konfigurowanie centrum powiadomień przy użyciu informacji usługi APNS

W obszarze Notification Serviceswybierz pozycję apple a następnie wykonaj odpowiednie kroki na podstawie podejścia wybranego wcześniej w sekcji Tworzenie certyfikatu dla usługi Notification Hubs.

Nuta

Użyj produkcyjnej dla trybu aplikacji tylko wtedy, gdy chcesz wysyłać powiadomienia wypychane do użytkowników, którzy kupili aplikację ze sklepu.

OPCJA 1: Używanie certyfikatu wypychania p12

  1. Wybierz pozycję Certificate.

  2. Wybierz ikonę pliku.

  3. Wybierz wyeksportowany wcześniej plik p12, a następnie wybierz pozycję Otwórz.

  4. W razie potrzeby określ poprawne hasło.

  5. Wybierz tryb piaskownicy .

  6. Wybierz pozycję Zapisz.

OPCJA 2: Używanie uwierzytelniania opartego na tokenach

  1. Wybierz pozycję Token.

  2. Wprowadź następujące wartości uzyskane wcześniej:

    • identyfikator klucza
    • identyfikator pakietu
    • identyfikator zespołu
    • tokenu
  3. Wybierz pozycję Piaskownica.

  4. Wybierz pozycję Zapisz.

Konfigurowanie centrum powiadomień przy użyciu informacji o usłudze FCM

  1. Wybierz pozycję Google (GCM/FCM) w sekcji ustawienia w menu po lewej stronie.
  2. Wprowadź klucz serwera zanotowany w konsoli Google Firebase Console.
  3. Wybierz pozycję Zapisz na pasku narzędzi.

Tworzenie aplikacji zaplecza internetowego interfejsu API platformy ASP.NET Core

W tej sekcji utworzysz zaplecze internetowego interfejsu API ASP.NET Core w celu obsługi rejestracji urządzeń oraz wysyłania powiadomień do aplikacji mobilnej Flutter.

Tworzenie projektu internetowego

  1. W programu Visual Studiowybierz pozycję plik >nowe rozwiązanie.

  2. Wybierz pozycję .NET Core>App>ASP.NET Core>API>Next.

  3. W oknie dialogowym Konfigurowanie nowego internetowego interfejsu API ASP.NET Core wybierz pozycję Target Framework platformy .NET Core 3.1.

  4. Wprowadź PushDemoApi dla nazwa projektu, a następnie wybierz pozycję Utwórz.

  5. Rozpocznij debugowanie (Command + Enter), aby przetestować aplikację szablonu.

    Nuta

    Aplikacja szablonu jest skonfigurowana do używania WeatherForecastController jako launchUrl. Jest on ustawiany w Właściwości>launchSettings.json.

    Jeśli zostanie wyświetlony monit o znaleziono nieprawidłowy certyfikat programowania komunikat:

    1. Kliknij przycisk Tak, aby wyrazić zgodę na uruchomienie narzędzia "dotnet dev-certs https", aby rozwiązać ten problem. Narzędzie "dotnet dev-certs https" wyświetli monit o wprowadzenie hasła do certyfikatu i hasła dla pęku kluczy.

    2. Kliknij pozycję Tak po wyświetleniu monitu o Install and trust the new certificate(Zainstaluj i ufaj nowemu certyfikatowi), a następnie wprowadź hasło dla pęku kluczy.

  6. Rozwiń folder kontrolerów , a następnie usuń WeatherForecastController.cs.

  7. Usuń WeatherForecast.cs.

  8. Skonfiguruj lokalne wartości konfiguracji przy użyciu narzędzia Secret Manager. Oddzielenie wpisów tajnych z rozwiązania gwarantuje, że nie zostaną one zakończone w kontroli źródła. Otwórz Terminal następnie przejdź do katalogu pliku projektu i uruchom następujące polecenia:

    dotnet user-secrets init
    dotnet user-secrets set "NotificationHub:Name" <value>
    dotnet user-secrets set "NotificationHub:ConnectionString" <value>
    

    Zastąp wartości symboli zastępczych własną nazwą centrum powiadomień i wartościami parametrów połączenia. Zanotuj je w sekcji tworzenia centrum powiadomień. W przeciwnym razie możesz wyszukać je w usłudze Azure.

    NotificationHub:Name:
    Zobacz Name (Nazwa) w podsumowaniu Essentials w górnej części Overview.

    NotificationHub:ConnectionString:
    Zobacz DefaultFullSharedAccessSignature w zasadach dostępu

    Nuta

    W przypadku scenariuszy produkcyjnych możesz zapoznać się z opcjami, takimi jak Azure KeyVault, aby bezpiecznie przechowywać parametry połączenia. Dla uproszczenia wpisy tajne zostaną dodane do ustawień aplikacji Azure App Service.

Uwierzytelnianie klientów przy użyciu klucza interfejsu API (opcjonalnie)

Klucze interfejsu API nie są tak bezpieczne jak tokeny, ale wystarczy do celów tego samouczka. Klucz interfejsu API można łatwo skonfigurować za pomocą oprogramowania pośredniczącego ASP.NET.

  1. Dodaj klucz interfejsu API do wartości konfiguracji lokalnej.

    dotnet user-secrets set "Authentication:ApiKey" <value>
    

    Nuta

    Należy zastąpić wartość symbolu zastępczego własną wartością i zanotować ją.

  2. Control + Kliknij w projekcie PushDemoApi wybierz pozycję Nowy folder z menu Dodaj, a następnie kliknij pozycję Dodaj przy użyciu uwierzytelniania jako nazwę folderu .

  3. ControlKliknij w folderze uwierzytelniania , a następnie wybierz pozycję Nowy plik... z menu Dodaj.

  4. Wybierz pozycję OgólneEmpty Class, wprowadź ApiKeyAuthOptions.cs dlanazwa , a następnie kliknij przycisk New dodając następującą implementację.

    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; }
        }
    }
    
  5. Dodaj kolejny Empty Class do folderu Authentication o nazwie ApiKeyAuthHandler.cs, a następnie dodaj następującą implementację.

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

    Nuta

    Program obsługi uwierzytelniania to typ implementujący zachowanie schematu, w tym przypadku niestandardowy schemat klucza interfejsu API.

  6. Dodaj kolejny Empty Class do folderu Authentication o nazwie ApiKeyAuthenticationBuilderExtensions.cs, a następnie dodaj następującą implementację.

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

    Nuta

    Ta metoda rozszerzenia upraszcza kod konfiguracji oprogramowania pośredniczącego w Startup.cs co sprawia, że jest bardziej czytelny i ogólnie łatwiejszy do naśladowania.

  7. W Startup.cszaktualizuj metodę ConfigureServices, aby skonfigurować uwierzytelnianie klucza interfejsu API poniżej wywołania usług . 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);
    }
    
  8. Nadal w Startup.cszaktualizuj metodę Configure, aby wywołać metodę UseAuthentication i useAuthorization extension methods w aplikacji IApplicationBuilder. Upewnij się, że te metody są wywoływane po UseRouting i przed aplikacji. Użyjpunktów końcowych.

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

    Nuta

    Wywoływanie UseAuthentication rejestruje oprogramowanie pośredniczące korzystające z wcześniej zarejestrowanych schematów uwierzytelniania (z ConfigureServices). Należy to wywołać przed każdym oprogramowaniem pośredniczącym, które zależy od uwierzytelnienia użytkowników.

Dodawanie zależności i konfigurowanie usług

ASP.NET Core obsługuje wzorzec projektowania zależności (DI), który jest techniką osiągnięcia Inversion of Control (IoC) między klasami a ich zależnościami.

Korzystanie z centrum powiadomień i zestawu SDK usługi Notification Hubs na potrzeby operacji zaplecza jest hermetyzowane w ramach usługi. Usługa jest zarejestrowana i udostępniana za pośrednictwem odpowiedniej abstrakcji.

  1. control + Click on the Dependencies folder, a następnie wybierz pozycję Zarządzaj pakietami NuGet....

  2. Wyszukaj Microsoft.Azure.NotificationHubs i upewnij się, że jest zaznaczone.

  3. Kliknij przycisk Dodaj pakiety, a następnie kliknij pozycję Akceptuj po wyświetleniu monitu o zaakceptowanie postanowień licencyjnych.

  4. Control + Click w projekcie PushDemoApi wybierz pozycję New Folder z menu Dodaj, a następnie kliknij pozycję Dodaj przy użyciu Models jako nazwę folderu .

  5. Control + Kliknij w folderze Models, a następnie wybierz pozycję Nowy plik... z menu Dodaj.

  6. Wybierz pozycję OgólneEmpty Class, wprowadź PushTemplates.cs dlaName, a następnie kliknij przycisk New dodanie następującej implementacji.

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

    Nuta

    Ta klasa zawiera tokenizowane ładunki powiadomień dla ogólnych i dyskretnych powiadomień wymaganych przez ten scenariusz. Ładunki są definiowane poza Instalacja, aby umożliwić eksperymentowanie bez konieczności aktualizowania istniejących instalacji za pośrednictwem usługi. Obsługa zmian w instalacjach w ten sposób jest poza zakresem tego samouczka. W przypadku środowiska produkcyjnego rozważ szablony niestandardowe.

  7. Dodaj kolejny Empty Class do folderu Models o nazwie DeviceInstallation.cs, a następnie dodaj następującą implementację.

    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>();
        }
    }
    
  8. Dodaj kolejny Empty Class do folderu Models o nazwie NotificationRequest.cs, a następnie dodaj następującą implementację.

    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; }
        }
    }
    
  9. Dodaj kolejny Empty Class do folderu Models o nazwie NotificationHubOptions.cs, a następnie dodaj następującą implementację.

    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class NotificationHubOptions
        {
            [Required]
            public string Name { get; set; }
    
            [Required]
            public string ConnectionString { get; set; }
        }
    }
    
  10. Dodaj nowy folder do projektu PushDemoApi o nazwie Services.

  11. Dodaj pusty interfejs do folderu services Services o nazwie INotificationService.cs, a następnie dodaj następującą implementację.

    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);
        }
    }
    
  12. Dodaj Empty Class do folderu Services o nazwie NotificationHubsService.cs, a następnie dodaj następujący kod, aby zaimplementować interfejs INotificationService:

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

    Nuta

    Wyrażenie tagu dostarczone do SendTemplateNotificationAsync jest ograniczone do 20 tagów. Jest on ograniczony do 6 dla większości operatorów, ale wyrażenie zawiera tylko jednostki ORS (||) w tym przypadku. Jeśli w żądaniu istnieje więcej niż 20 tagów, należy je podzielić na wiele żądań. Aby uzyskać więcej szczegółów, zobacz dokumentację Routing i Wyrażenia tagów.

  13. W Startup.cszaktualizuj metodę ConfigureServices, aby dodać NotificationHubsService jako pojedynczą implementację 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();
    }
    

Tworzenie interfejsu API powiadomień

  1. controlClick on the Controllers folder, a następnie wybierz pozycję New File... z menu Add (Dodaj).

  2. Wybierz ASP.NET CoreWeb API Controller Class, wprowadź NotificationsController dlanazwa , a następnie kliknij Nowy.

    Nuta

    Jeśli korzystasz z Visual Studio 2019, wybierz kontroler interfejsu API z akcjami odczytu/zapisu szablonu.

  3. Dodaj następujące przestrzenie nazw na początku pliku.

    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;
    
  4. Zaktualizuj szablon kontrolera, aby pochodził z ControllerBase i jest ozdobiony atrybutem ApiController.

    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    {
        // Templated methods here
    }
    

    Nuta

    Kontroler kontroler klasy bazowej zapewnia obsługę widoków, ale nie jest to konieczne w tym przypadku i dlatego można użyć ControllerBase. Jeśli korzystasz z Visual Studio 2019, możesz pominąć ten krok.

  5. Jeśli zdecydujesz się ukończyć uwierzytelniać klientów przy użyciu klucza interfejsu API, należy również ozdobić NotificationsController za pomocą atrybutu Autoryzuj.

    [Authorize]
    
  6. Zaktualizuj konstruktor, aby akceptował zarejestrowane wystąpienie usługi INotificationService jako argument i przypisz go do elementu członkowskiego readonly.

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  7. W launchSettings.json (w folderze właściwości ) zmień launchUrl z na api/notifications, aby pasować do adresu URL określonego w atrybucie RegistrationsControllerRoute.

  8. Rozpocznij debugowanie (Command + Enter), aby sprawdzić, czy aplikacja współpracuje z nowym NotificationsController i zwraca stan 401 Brak autoryzacji.

    Nuta

    Program Visual Studio może nie uruchamiać automatycznie aplikacji w przeglądarce. Użyjesz postman do przetestowania interfejsu API od tego momentu.

  9. Na nowej karcie Postman ustaw żądanie GET. Wprowadź poniższy adres zastępując symbol zastępczy <applicationUrl> ciągiem https applicationUrl znalezionym w Properties>launchSettings.json.

    <applicationUrl>/api/notifications
    

    Nuta

    applicationUrl powinien mieć wartość "" dla profilu domyślnego. Jeśli używasz IIS (domyślnie w programie Visual Studio 2019 w systemie Windows), należy zamiast tego użyć applicationUrl określonego w elemencie iisSettings. Jeśli adres jest niepoprawny, otrzymasz odpowiedź 404.

  10. Jeśli wybrano opcję ukończenia Uwierzytelnianie klientów przy użyciu klucza interfejsu API, pamiętaj, aby skonfigurować nagłówki żądań tak, aby zawierały wartość apikey.

    Klucz Wartość
    apikey <your_api_key>
  11. Kliknij przycisk Wyślij .

    Nuta

    Powinien zostać wyświetlony stan 200 OK z zawartością JSON.

    Jeśli zostanie wyświetlone ostrzeżenie weryfikacji certyfikatu SSL, możesz przełączyć żądanie weryfikacji certyfikatu SSL Postman ustawienie w ustawieniach .

  12. Zastąp metody klas szablonu w NotificationsController.cs następującym kodem.

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

Tworzenie aplikacji interfejsu API

Teraz utworzysz aplikację interfejsu API w usłudze Azure App Service na potrzeby hostowania usługi zaplecza.

  1. Zaloguj się do witryny Azure Portal.

  2. Kliknij pozycję Utwórz zasób, a następnie wyszukaj i wybierz pozycję API App, a następnie kliknij pozycję Utwórz.

  3. Zaktualizuj następujące pola, a następnie kliknij pozycję Utwórz.

    nazwa aplikacji :
    Wprowadź globalnie unikatową nazwę aplikacji interfejsu API

    subskrypcja :
    Wybierz ten sam docelowy Subskrypcja, w którym utworzono centrum powiadomień.

    grupa zasobów :
    Wybierz tę samą grupę zasobów utworzoną w centrum powiadomień.

    plan/lokalizacja usługi App Service:
    Tworzenie nowego planu usługi App Service

    Nuta

    Zmień opcję domyślną na plan obejmujący obsługę SSL. W przeciwnym razie należy wykonać odpowiednie kroki podczas pracy z aplikacją mobilną, aby zapobiec zablokowaniu żądań http http.

    Application Insights:
    Zachowaj sugerowaną opcję (nowy zasób zostanie utworzony przy użyciu tej nazwy) lub wybierz istniejący zasób.

  4. Po aprowizacji aplikacji interfejsu API przejdź do tego zasobu.

  5. Zanotuj właściwość adresu URL w podsumowaniu Essentials w górnej częściPrzegląd . Ten adres URL to punkt końcowy zaplecza, który będzie używany w dalszej części tego samouczka.

    Nuta

    Adres URL używa określonej wcześniej nazwy aplikacji interfejsu API z formatem https://<app_name>.azurewebsites.net.

  6. Wybierz pozycję Configuration z listy (w obszarze Settings).

  7. Dla każdego z poniższych ustawień kliknij nowe ustawienie aplikacji, aby wprowadzić Nazwa i wartość , a następnie kliknij przycisk OK.

    Nazwa Wartość
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Nuta

    Są to te same ustawienia zdefiniowane wcześniej w ustawieniach użytkownika. Powinno być możliwe skopiowanie tych kopii. Ustawienie Authentication:ApiKey jest wymagane tylko w przypadku wybrania opcji ukończenia Uwierzytelnianie klientów przy użyciu klucza interfejsu API. W przypadku scenariuszy produkcyjnych można zapoznać się z opcjami, takimi jak azure KeyVault. Zostały one dodane jako ustawienia aplikacji dla uproszczenia w tym przypadku.

  8. Po dodaniu wszystkich ustawień aplikacji kliknij pozycję Zapisz, a następnie Kontynuuj.

Publikowanie usługi zaplecza

Następnie wdrożysz aplikację w aplikacji interfejsu API, aby była dostępna ze wszystkich urządzeń.

Nuta

Poniższe kroki są specyficzne dla programu Visual Studio dla komputerów Mac. Jeśli korzystasz z Visual Studio 2019 w systemie Windows, przepływ publikowania będzie inny. Zobacz Publikowanie w usłudze Azure App Service w systemie Windows.

  1. Zmień konfigurację z Debugowanie na Release, jeśli jeszcze tego nie zrobiono.

  2. ControlKliknij projektu PushDemoApi, a następnie wybierz pozycję Publikuj na platformie Azure... z menu Publikowanie .

  3. Jeśli zostanie wyświetlony monit, postępuj zgodnie z przepływem uwierzytelniania. Użyj konta użytego w poprzedniej utworzyć sekcję App interfejsu API.

  4. Wybierz aplikację interfejsu API usługi Azure App Service utworzoną wcześniej z listy jako element docelowy publikowania, a następnie kliknij pozycję Publikuj.

Po zakończeniu pracy kreatora publikuje ona aplikację na platformie Azure, a następnie otwiera aplikację. Zanotuj adres URL , jeśli jeszcze tego nie zrobiono. Ten adres URL to punkt końcowy zaplecza używany w dalszej części tego samouczka.

Weryfikowanie opublikowanego interfejsu API

  1. W Postman otwórz nową kartę, ustaw żądanie na PUT i wprowadź poniższy adres. Zastąp symbol zastępczy adresem podstawowym zanotowanymi w poprzedniej opublikować sekcję usługi zaplecza.

    https://<app_name>.azurewebsites.net/api/notifications/installations
    

    Nuta

    Adres podstawowy powinien mieć format https://<app_name>.azurewebsites.net/

  2. Jeśli wybrano opcję ukończenia Uwierzytelnianie klientów przy użyciu klucza interfejsu API, pamiętaj, aby skonfigurować nagłówki żądań tak, aby zawierały wartość apikey.

    Klucz Wartość
    apikey <your_api_key>
  3. Wybierz opcję raw dla Body, a następnie wybierz JSON z listy opcji formatowania, a następnie dołącz symbol zastępczy zawartości JSON:

    {}
    
  4. Kliknij pozycję Wyślij.

    Nuta

    Z usługi powinien zostać wyświetlony stan 422 UnprocessableEntity.

  5. Wykonaj ponownie kroki 1–4, ale tym razem określając punkt końcowy żądań w celu zweryfikowania, czy otrzymasz odpowiedź 400 Nieprawidłowe żądanie.

    https://<app_name>.azurewebsites.net/api/notifications/requests
    

Nuta

Nie można jeszcze przetestować interfejsu API przy użyciu prawidłowych danych żądania, ponieważ będzie to wymagać informacji specyficznych dla platformy z aplikacji mobilnej klienta.

Tworzenie międzyplatformowej aplikacji Flutter

W tej sekcji utworzysz Flutter aplikacji mobilnej implementowania powiadomień wypychanych w sposób międzyplatformowy.

Umożliwia ona rejestrowanie i wyrejestrowanie z centrum powiadomień za pośrednictwem utworzonej usługi zaplecza.

Alert jest wyświetlany po określeniu akcji, a aplikacja znajduje się na pierwszym planie. W przeciwnym razie powiadomienia są wyświetlane w centrum powiadomień.

Nuta

Zazwyczaj wykonuje się akcje rejestracji (i wyrejestrowania) w odpowiednim punkcie cyklu życia aplikacji (lub w ramach środowiska pierwszego uruchomienia) bez jawnego rejestrowania/wyrejestrowania danych wejściowych użytkownika. Jednak w tym przykładzie wymagane będą jawne dane wejściowe użytkownika, aby umożliwić łatwiejsze eksplorowanie i przetestowanie tej funkcji.

Tworzenie rozwiązania Flutter

  1. Otwórz nowe wystąpienie programu Visual Studio Code.

  2. Otwórz Command Palette (Shift + Command + P).

  3. Wybierz polecenie Flutter: New Project i naciśnij Enter.

  4. Wprowadź push_demo w polu Nazwa projektu , a następnie wybierz lokalizację projektu .

  5. Po wyświetleniu monitu o to wybierz pozycję Pobierz pakiety.

  6. Control + Click on the kotlin folder (w obszarze app>src>main), a następnie wybierz pozycję Reveal in Finder. Następnie zmień nazwę folderów podrzędnych (w folderze kotlin) na odpowiednio com, <your_organization>i pushdemo.

    Nuta

    W przypadku korzystania z szablonu programu Visual Studio Code te foldery są domyślnie com, przykład, project_name. Przy założeniu, że mobcat jest używany dla organizacji , struktura folderów powinna być widoczna jako:

    • kotlin
      • Com
        • mobcat
          • pushdemo
  7. Po powrocie do programu Visual Studio Code zaktualizuj wartość applicationId androidappbuild.gradle, aby .

    Nuta

    Jako symbol zastępczy <your_organization> należy użyć własnej nazwy organizacji. Na przykład użycie mobcat jako organizacji spowoduje nazwę pakietu wartość com.mobcat.pushdemo.

  8. Zaktualizuj atrybut pakietu w plikach AndroidManifest.xml w obszarze srcdebugowania, srcgłównegoi profilu src. Upewnij się, że wartości są zgodne z identyfikatorem applicationId użytym w poprzednim kroku.

    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.<your_organization>.pushdemo>">
        ...
    </manifest>
    
  9. Zaktualizuj atrybut android:label w pliku AndroidManifest.xml w obszarze src>main, aby PushDemo. Następnie dodaj atrybut android:allowBackup bezpośrednio w obszarze android:label, ustawiając jego wartość na wartość false.

    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="PushDemo"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher">
        ...
    </application>
    
  10. Otwórz plik build.gradle (appappbuild.gradle), a następnie zaktualizuj compileSdkVersion (w sekcji android), aby użyć interfejsu API 29. Następnie zaktualizuj wartości minSdkVersion i targetSdkVersion (z sekcji defaultConfig), aby odpowiednio 26 i 29.

    Nuta

    Tylko te urządzenia z systemem interfejsu API na poziomie 26 i wyższym są obsługiwane na potrzeby tego samouczka, ale można rozszerzyć go na urządzenia obsługujące starsze wersje.

  11. Control + Kliknij w folderze systemu ios, a następnie wybierz pozycję Otwórz w programie Xcode.

  12. W Xcode kliknij pozycję Runner (xcodeproj u góry, a nie folderu). Następnie wybierz docelowy element docelowy modułu uruchamiającego i wybierz kartę Ogólne. Po wybraniu konfiguracji kompilacji Wszystkie zaktualizuj identyfikator pakietu , aby .

    Nuta

    Jako symbol zastępczy <your_organization> należy użyć własnej nazwy organizacji. Na przykład użycie mobcat jako organizacji spowoduje wartość identyfikatora pakietu wartości com.mobcat.PushDemo.

  13. Kliknij Info.plist, a następnie zaktualizuj wartość nazwa pakietu , aby PushDemo

  14. Zamknij Xcode i wróć do programu Visual Studio Code.

  15. Po powrocie do programu Visual Studio Code otwórz pubspec.yaml, dodaj http i pakiety flutter_secure_storageDart jako zależności. Następnie zapisz plik i kliknij przycisk Pobierz pakiety po wyświetleniu monitu o to.

    dependencies:
      flutter:
        sdk: flutter
    
      http: ^0.12.1
      flutter_secure_storage: ^3.3.3
    
  16. W terminaluzmień katalog na folder systemu ios (dla projektu Flutter). Następnie wykonaj polecenie zasobnik zainstaluj, aby zainstalować nowe zasobniki (wymagane przez pakiet flutter_secure_storage).

  17. control + Click on the lib folder, a następnie wybierz New File z menu przy użyciu main_page.dart jako nazwy pliku. Następnie dodaj następujący kod.

    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>[],
            )
          )
        );
      }
    }
    
  18. W main.dartzastąp kod szablonu poniższym kodem.

    import 'package:flutter/material.dart';
    import 'package:push_demo/main_page.dart';
    
    final navigatorKey = GlobalKey<NavigatorState>();
    
    void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
    
  19. W terminaluskompiluj i uruchom aplikację na każdej platformie docelowej, aby przetestować działanie szablonu aplikacji na urządzeniach. Upewnij się, że obsługiwane urządzenia są połączone.

    flutter run
    

Implementowanie składników międzyplatformowych

  1. control + Click on the lib folder, a następnie wybierz New Folder z menu przy użyciu modeli jako nazwy folderu .

  2. control + Click on the models folder, a następnie wybierz New File z menu przy użyciu device_installation.dart jako nazwy pliku. Następnie dodaj następujący kod.

    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,
        };
    }
    
  3. Dodaj nowy plik do folderu models o nazwie push_demo_action.dart definiujący wyliczanie akcji obsługiwanych w tym przykładzie.

    enum PushDemoAction {
      actionA,
      actionB,
    }
    
  4. Dodaj nowy folder do projektu o nazwie services następnie dodaj nowy plik do tego folderu o nazwie device_installation_service.dart z następującą implementacją.

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

    Nuta

    Jako symbol zastępczy <your_organization> należy użyć własnej nazwy organizacji. Na przykład użycie mobcat, ponieważ organizacja spowoduje MethodChannel nazwę com.mobcat.pushdemo/deviceinstallation.

    Ta klasa hermetyzuje pracę z podstawową platformą natywną w celu uzyskania szczegółowych informacji o wymaganej instalacji urządzenia. MethodChannel ułatwia dwukierunkową asynchroniczną komunikację z podstawowymi platformami natywnymi. Odpowiedni odpowiednik specyficzny dla platformy dla tego kanału zostanie utworzony w kolejnych krokach.

  5. Dodaj kolejny plik do tego folderu o nazwie notification_action_service.dart z następującą implementacją.

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

    Nuta

    Jest to używany jako prosty mechanizm umożliwiający scentralizowanie obsługi akcji powiadomień, dzięki czemu można je obsłużyć w sposób międzyplatformowy przy użyciu silnie typizowanego wyliczenia. Usługa umożliwia podstawowej platformie natywnej wyzwalanie akcji po określeniu jej w ładunku powiadomień. Umożliwia również wspólne kodowi retrospektywne sprawdzanie, czy akcja została określona podczas uruchamiania aplikacji, gdy flutter jest gotowy do jego przetworzenia. Na przykład po uruchomieniu aplikacji przez naciśnięcie powiadomienia z centrum powiadomień.

  6. Dodaj nowy plik do folderu usług o nazwie notification_registration_service.dart z następującą implementacją.

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

    Nuta

    Ta klasa hermetyzuje użycie DeviceInstallationService oraz żądań do usługi zaplecza w celu wykonania wymaganych akcji rejestracji, wyrejestrowania i odświeżania. Argument apiKey jest wymagany tylko w przypadku wybrania uwierzytelnienia klientów przy użyciu klucza interfejsu API.

  7. Dodaj nowy plik do folderu lib o nazwie config.dart z następującą implementacją.

    class Config {
      static String apiKey = "API_KEY";
      static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
    }
    

    Nuta

    Jest to prosty sposób definiowania wpisów tajnych aplikacji. Zastąp wartości symboli zastępczych własnymi. Podczas tworzenia usługi zaplecza należy zanotować te informacje. Adres URL aplikacji interfejsu API powinien być . Element członkowski apiKey jest wymagany tylko w przypadku wybrania uwierzytelnienia klientów przy użyciu klucza interfejsu API.

    Pamiętaj, aby dodać go do pliku gitignore, aby uniknąć zatwierdzania tych wpisów tajnych do kontroli źródła.

Implementowanie międzyplatformowego interfejsu użytkownika

  1. W pliku main_page.dartzastąp funkcję kompilacji następującym kodem.

    @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,
              ),
            ],
          ),
        ),
      );
    }
    
  2. Dodaj wymagane importy na początku pliku main_page.dart.

    import 'package:push_demo/services/notification_registration_service.dart';
    import 'config.dart';
    
  3. Dodaj pole do klasy _MainPageState, aby zapisać odwołanie do NotificationRegistrationService.

    final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
    
  4. W klasie _MainPageState zaimplementuj programy obsługi zdarzeń dla Register i deregister przycisków onPressed. Wywołaj odpowiednie metody Register/Deregister, a następnie wyświetl alert wskazujący wynik.

    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();
                  },
                ),
              ],
            );
          },
        );
      }
    
  5. Teraz w main.dartupewnij się, że w górnej części pliku znajdują się następujące 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';
    
  6. Zadeklaruj zmienną do przechowywania odwołania do wystąpienia NotificationActionService i zainicjuj je.

    final notificationActionService = NotificationActionService();
    
  7. Dodaj funkcje do obsługi wyświetlania alertu po wyzwoleniu akcji.

    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();
                },
              ),
            ],
          );
        },
      );
    }
    
  8. Zaktualizuj funkcję main, aby obserwować akcję NotificationActionServiceTriggered strumienia i sprawdzać wszystkie akcje przechwycone podczas uruchamiania aplikacji.

    void main() async {
      runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,));
      notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); });
      await notificationActionService.checkLaunchAction();
    }
    

    Nuta

    Jest to po prostu zademonstrowanie potwierdzenia i propagacji akcji powiadomień wypychanych. Zazwyczaj są one obsługiwane w trybie dyskretnym, na przykład przejście do określonego widoku lub odświeżenie niektórych danych zamiast wyświetlania alertu w tym przypadku.

Konfigurowanie natywnego projektu systemu Android na potrzeby powiadomień wypychanych

Dodawanie pliku JSON usług Google Services

  1. Control + Click on the android folder, a następnie wybierz pozycję Otwórz w programie Android Studio. Następnie przejdź do widoku Project (jeśli jeszcze tego nie ma).

  2. Znajdź pobrany wcześniej plik google-services.json podczas konfigurowania projektu PushDemo w programie Firebase Console. Następnie przeciągnij go do katalogu głównego modułu app (android>>app).

Konfigurowanie ustawień i uprawnień kompilacji

  1. Przełącz widok Project na Android.

  2. Otwórz AndroidManifest.xml, a następnie dodaj uprawnienia INTERNET i READ_PHONE_STATE po elemecie aplikacji przed tagiem zamykającym .

    <manifest>
        <application>...</application>
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    </manifest>
    

Dodawanie zestawów SDK programu Firebase

  1. W Android Studio otwórz plik build.gradle (Gradle Scriptsbuild.gradle (Project: android)). i upewnij się, że masz ścieżkę klasy "com.google.gms:google-services" w węźle buildscript>zależności.

    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
        // ...
      }
    }
    

    Nuta

    Upewnij się, że odwołujesz się do najnowszej wersji zgodnie z instrukcjami podanymi w konsoli programu Firebase podczas tworzenia programu Android Project.

  2. W pliku build.gradle (Gradle Scriptsbuild.gradle (Module: app)) zastosuj wtyczkę Google Services Gradle. Zastosuj wtyczkę bezpośrednio nad węzłem android.

    // ...
    
    // Add the following line:
    apply plugin: 'com.google.gms.google-services'  // Google Services plugin
    
    android {
      // ...
    }
    
  3. W tym samym pliku w węźle zależności dodaj zależność dla biblioteki Cloud Messaging Android.

    dependencies {
        // ...
        implementation 'com.google.firebase:firebase-messaging:20.2.0'
    }
    

    Nuta

    Upewnij się, że odwołujesz się do najnowszej wersji zgodnie z dokumentacją klienta Cloud Messaging dla systemu Android.

  4. Zapisz zmiany, a następnie kliknij przycisk Synchronizuj teraz (w wierszu polecenia paska narzędzi) lub Sync Project with Gradle Files.

Obsługa powiadomień wypychanych dla systemu Android

  1. W Android Studio Control + Click click on the com.<your_organization>.pushdemo package folder (app>src>main>kotlin) wybierz pozycję Package z menu New. Wprowadź services jako nazwę, a następnie naciśnij Return.

  2. ControlKliknij w folderze usług , wybierz pozycję plik/klasa Kotlin z menu Nowy. Wprowadź DeviceInstallationService jako nazwę, a następnie naciśnij Return.

  3. Zaimplementuj DeviceInstallationService przy użyciu następującego kodu.

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

    Nuta

    Ta klasa implementuje odpowiedni odpowiednik specyficzny dla platformy dla kanału com.<your_organization>.pushdemo/deviceinstallation. Zostało to zdefiniowane w części Flutter aplikacji w DeviceInstallationService.dart. W takim przypadku wywołania są wykonywane z wspólnego kodu do hosta natywnego. Pamiętaj, aby zastąpić <your_organization> własną organizacją, gdziekolwiek jest używana.

    Ta klasa udostępnia unikatowy identyfikator (przy użyciu Secure.AndroidId) w ramach ładunku rejestracji centrum powiadomień.

  4. Dodaj kolejny plik/klasę Kotlin do folderu usług o nazwie NotificationRegistrationService, a następnie dodaj następujący kod.

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

    Nuta

    Ta klasa implementuje odpowiedni odpowiednik specyficzny dla platformy dla kanału com.<your_organization>.pushdemo/notificationregistration. Zostało to zdefiniowane w części Flutter aplikacji w NotificationRegistrationService.dart. W takim przypadku wywołania są wykonywane z hosta natywnego do wspólnego kodu. Ponownie zastąp <your_organization> własną organizacją wszędzie tam, gdzie jest używana.

  5. Dodaj kolejny plików/klas Kotlin do folderu usług o nazwie NotificationActionService, a następnie dodaj następujący kod.

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

    Nuta

    Ta klasa implementuje odpowiedni odpowiednik specyficzny dla platformy dla kanału com.<your_organization>.pushdemo/notificationaction. To zostało zdefiniowane w części Flutter aplikacji w NotificationActionService.dart. Wywołania mogą być wykonywane w obu kierunkach w tym przypadku. Pamiętaj, aby zastąpić <your_organization> własną organizacją, gdziekolwiek jest używana.

  6. Dodaj nowy plik/klasę Kotlin do witryny com.<your_organization>.pushdemo o nazwie PushNotificationsFirebaseMessagingService, a następnie zaimplementuj przy użyciu następującego kodu.

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

    Nuta

    Ta klasa jest odpowiedzialna za obsługę powiadomień, gdy aplikacja jest uruchomiona na pierwszym planie. Warunkowo wywoła triggerAction w NotificationActionService, jeśli akcja zostanie uwzględniona w ładunku powiadomienia odebranym w onMessageReceived. Spowoduje to również wywołanie refreshRegistration w NotificationRegistrationService, gdy token Firebase zostanie wygenerowany ponownie przez zastąpienie funkcji onNewToken.

    Po raz kolejny zastąp <your_organization> własną organizacją wszędzie tam, gdzie jest używana.

  7. W AndroidManifest.xml (app>src>main), dodaj PushNotificationsFirebaseMessagingService do dołu aplikacji z filtrem intencji 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>
    
  8. Po powrocie do DeviceInstallationServiceupewnij się, że w górnej części pliku znajdują się następujące importy.

    package com.<your_organization>.pushdemo
    import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
    

    Nuta

    Zastąp <your_organization> własną wartością organizacji.

  9. Zaktualizuj tekst zastępczy Placeholder_Get_Value_From_FirebaseMessagingService_Implementation, aby uzyskać wartość 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
    }
    
  10. W MainActivityupewnij się, że w górnej części pliku znajdują się następujące 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
    

    Nuta

    Zastąp <your_organization> własną wartością organizacji.

  11. Dodaj zmienną do przechowywania odwołania do DeviceInstallationService.

    private lateinit var deviceInstallationService: DeviceInstallationService
    
  12. Dodaj funkcję o nazwie processNotificationActions, aby sprawdzić, czy Intent ma dodatkową wartość o nazwie action. Warunkowo wyzwól akcję lub zapisz ją do użycia później, jeśli akcja jest przetwarzana podczas uruchamiania aplikacji.

     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)
                }
            }
        }
    }
    
  13. Zastąpij funkcję onNewIntent w celu wywołania processNotificationActions.

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        processNotificationActions(intent)
    }
    

    Nuta

    Ponieważ LaunchMode dla MainActivity jest ustawiona na SingleTop, intencja zostanie wysłana do istniejącego wystąpienia działania za pośrednictwem onNe Funkcja, a nie onCreate, dlatego należy obsługiwać przychodzące Intent zarówno w onCreate, jak i onNewIntent functions.

  14. Zastąpij funkcję onCreate, ustaw deviceInstallationService na nowe wystąpienie DeviceInstallationService.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        flutterEngine?.let {
            deviceInstallationService = DeviceInstallationService(context, it)
        }
    }
    
  15. Ustaw właściwości notificationActionService i notificationRegistrationService w PushNotificationFirebaseMessagingServices.

    flutterEngine?.let {
      deviceInstallationService = DeviceInstallationService(context, it)
      PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it)
      PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it)
    }
    
  16. W tej samej funkcji warunkowo wywołaj FirebaseInstanceId.getInstance().instanceId. Zaimplementuj wartość OnCompleteListener, aby ustawić wynikowy token na PushNotificationFirebaseMessagingService przed wywołaniem refreshRegistration.

    if(deviceInstallationService?.playServicesAvailable) {
        FirebaseInstanceId.getInstance().instanceId
            .addOnCompleteListener(OnCompleteListener { task ->
                if (!task.isSuccessful)
                    return@OnCompleteListener
    
                PushNotificationsFirebaseMessagingService.token = task.result?.token
                PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration()
            })
    }
    
  17. Nadal w onCreatewywołaj metodę processNotificationActions na końcu funkcji. Użyj true dla argumentu launchAction , aby wskazać, że ta akcja jest przetwarzana podczas uruchamiania aplikacji.

    processNotificationActions(this.intent, true)
    

Nuta

Musisz ponownie zarejestrować aplikację przy każdym uruchomieniu i zatrzymać ją z sesji debugowania, aby kontynuować odbieranie powiadomień wypychanych.

Konfigurowanie natywnego projektu systemu iOS na potrzeby powiadomień wypychanych

Konfigurowanie elementu docelowego modułu uruchamiającego i pliku Info.plist

  1. WVisual Studio Code ControlKliknij w folderze ios, a następnie wybierz pozycję Otwórz w programie Xcode.

  2. W Xcode kliknij pozycję Runner (xcodeproj u góry, a nie folderu), a następnie wybierz element docelowy modułu uruchamiającego , a następnie możliwości podpisywania &. Po wybraniu konfiguracji kompilacji Wszystkie wybierz konto dewelopera dlazespołu . Upewnij się, że opcja "Automatyczne zarządzanie podpisywaniem" jest zaznaczona, a certyfikat podpisywania i profil aprowizacji są wybierane automatycznie.

    Nuta

    Jeśli nie widzisz nowej wartości profilu aprowizacji, spróbuj odświeżyć profile tożsamości podpisywania, wybierając pozycję preferencje programu Xcode>>konto następnie wybierz przycisk Pobierz profile ręczne, aby pobrać profile.

  3. Kliknij pozycję + capability, a następnie wyszukaj push notifications. kliknij dwukrotniepowiadomienia wypychane, aby dodać tę możliwość.

  4. Otwórz Info.plist i ustaw minimalną wersję systemu na 13.0.

    Nuta

    Tylko te urządzenia z systemem iOS 13.0 lub nowszym są obsługiwane na potrzeby tego samouczka, jednak można rozszerzyć go na urządzenia obsługujące starsze wersje.

  5. Otwórz Runner.entitlements i upewnij się, że ustawienie APS Environment jest ustawione na programowanie.

Obsługa powiadomień wypychanych dla systemu iOS

  1. Control + Click on the Runner folder (w projekcie Moduł uruchamiający), a następnie wybierz pozycję Nowa grupa przy użyciu usługi Services jako nazwy.

  2. ControlKliknij w folderze usług Services, a następnie wybierz pozycję Nowy plik.... Następnie wybierz plik Swift i kliknij przycisk Dalej. Określ DeviceInstallationService jako nazwę, a następnie kliknij pozycję Utwórz.

  3. Zaimplementuj DeviceInstallationService.swift przy użyciu następującego kodu.

    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."
        }
    }
    

    Nuta

    Ta klasa implementuje odpowiedni odpowiednik specyficzny dla platformy dla kanału com.<your_organization>.pushdemo/deviceinstallation. Zostało to zdefiniowane w części Flutter aplikacji w DeviceInstallationService.dart. W takim przypadku wywołania są wykonywane z wspólnego kodu do hosta natywnego. Pamiętaj, aby zastąpić <your_organization> własną organizacją, gdziekolwiek jest używana.

    Ta klasa udostępnia unikatowy identyfikator (przy użyciu wartości UIDevice.identifierForVendor) w ramach ładunku rejestracji centrum powiadomień.

  4. Dodaj kolejny plik Swift do folderu usług Services o nazwie NotificationRegistrationService, a następnie dodaj następujący kod.

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

    Nuta

    Ta klasa implementuje odpowiedni odpowiednik specyficzny dla platformy dla kanału com.<your_organization>.pushdemo/notificationregistration. Zostało to zdefiniowane w części Flutter aplikacji w NotificationRegistrationService.dart. W takim przypadku wywołania są wykonywane z hosta natywnego do wspólnego kodu. Ponownie zastąp <your_organization> własną organizacją wszędzie tam, gdzie jest używana.

  5. Dodaj kolejny plik Swift do folderu usług o nazwie NotificationActionService, a następnie dodaj następujący kod.

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

    Nuta

    Ta klasa implementuje odpowiedni odpowiednik specyficzny dla platformy dla kanału com.<your_organization>.pushdemo/notificationaction. To zostało zdefiniowane w części Flutter aplikacji w NotificationActionService.dart. Wywołania mogą być wykonywane w obu kierunkach w tym przypadku. Pamiętaj, aby zastąpić <your_organization> własną organizacją, gdziekolwiek jest używana.

  6. W AppDelegate.swiftdodaj zmienne do przechowywania odwołania do utworzonych wcześniej usług.

    var deviceInstallationService : DeviceInstallationService?
    var notificationRegistrationService : NotificationRegistrationService?
    var notificationActionService : NotificationActionService?
    
  7. Dodaj funkcję o nazwie processNotificationActions do przetwarzania danych powiadomień. Warunkowo wyzwól akcję lub zapisz ją do użycia później, jeśli akcja jest przetwarzana podczas uruchamiania aplikacji.

    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)
            }
        }
    }
    
  8. Zastąp funkcję nieRegisterForRemoteNotificationsWithDeviceToken ustawiając wartość tokenu dlaDeviceInstallationService. Następnie wywołaj refreshRegistrationNotificationRegistrationService.

    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      deviceInstallationService?.token = deviceToken
      notificationRegistrationService?.refreshRegistration()
    }
    
  9. Zastąp funkcję didReceiveRemoteNotification przekazującą argument userInfo do funkcji processNotificationActions.

    override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        processNotificationActions(userInfo: userInfo)
    }
    
  10. Zastąp funkcję didFailToRegisterForRemoteNotificationsWithError, aby zarejestrować błąd.

    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error);
    }
    

    Nuta

    Jest to bardzo symbol zastępczy. W scenariuszach produkcyjnych należy zaimplementować odpowiednie rejestrowanie i obsługę błędów.

  11. W finishLaunchingWithOptions utwórz wystąpienie zmiennych deviceInstallationService, notificationRegistrationServicei notificationActionService.

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    
    deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger)
    notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger)
    notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
    
  12. W tej samej funkcji warunkowo żądaj autoryzacji i zarejestruj się w celu otrzymywania powiadomień zdalnych.

    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()
              }
          }
      }
    }
    
  13. Jeśli launchOptions zawiera klucz remoteNotification, wywołaj processNotificationActions na końcu funkcji didFinishLaunchingWithOptions. Przekaż wynikowy obiekt userInfo i użyj true dla argumentu launchAction . Wartość true oznacza, że akcja jest przetwarzana podczas uruchamiania aplikacji.

    if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {
        processNotificationActions(userInfo: userInfo, launchAction: true)
    }
    

Testowanie rozwiązania

Teraz możesz przetestować wysyłanie powiadomień za pośrednictwem usługi zaplecza.

Wysyłanie powiadomienia testowego

  1. Otwórz nową kartę w programie Postman.

  2. Ustaw żądanie na POST, a następnie wprowadź następujący adres:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    
  3. Jeśli wybrano opcję ukończenia Uwierzytelnianie klientów przy użyciu klucza interfejsu API, pamiętaj, aby skonfigurować nagłówki żądań tak, aby zawierały wartość apikey.

    Klucz Wartość
    apikey <your_api_key>
  4. Wybierz opcję raw dla Body, a następnie wybierz JSON z listy opcji formatowania, a następnie dołącz symbol zastępczy zawartości JSON:

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Wybierz przycisk kod , który znajduje się pod przyciskiem Zapisz w prawym górnym rogu okna. Żądanie powinno wyglądać podobnie do poniższego przykładu wyświetlanego dla HTML (w zależności od tego, czy dołączono nagłówek 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"
    }
    
  6. Uruchom aplikację PushDemo na jednej lub obu platformach docelowych ( Android i iOS).

    Nuta

    Jeśli testujesz android upewnij się, że nie działasz w Debugowanielub jeśli aplikacja została wdrożona, uruchamiając aplikację, wymuś zamknięcie aplikacji i uruchom ją ponownie z poziomu modułu uruchamiania.

  7. W aplikacji PushDemo naciśnij przycisk Zarejestruj.

  8. Po powrocie Postmanzamknij okno Generuj fragmenty kodu (jeśli jeszcze tego nie zrobiono), a następnie kliknij przycisk Wyślij.

  9. Sprawdź, czy otrzymasz odpowiedź 200 OK w Postman, a alert zostanie wyświetlony w aplikacji z akcję ActionA odebraną.

  10. Zamknij aplikację PushDemo, a następnie ponownie kliknij przycisk Wyślij w Postman.

  11. Sprawdź, czy ponownie 200 OK odpowiedzi w Postman. Sprawdź, czy powiadomienie jest wyświetlane w obszarze powiadomień dla aplikacji PushDemo z poprawnym komunikatem.

  12. Naciśnij powiadomienie, aby potwierdzić otwarcie aplikacji i wyświetlenie akcji ActionA odebranych alertu.

  13. Wróć Postman, zmodyfikuj poprzednią treść żądania, aby wysłać powiadomienie dyskretne określające action_b zamiast action_a dla wartości akcji .

    {
        "action": "action_b",
        "silent": true
    }
    
  14. Po otwarciu aplikacji kliknij przycisk Wyślij w Postman.

  15. Sprawdź, czy otrzymasz odpowiedź 200 OK w Postman i że alert jest wyświetlany w aplikacji z akcję ActionB odebraną zamiast odebranej akcji ActionA.

  16. Zamknij aplikację PushDemo, a następnie ponownie kliknij przycisk Wyślij w Postman.

  17. Sprawdź, czy otrzymasz odpowiedź 200 OK w Postman i że powiadomienie dyskretne nie jest wyświetlane w obszarze powiadomień.

Rozwiązywanie problemów

Brak odpowiedzi z usługi zaplecza

Podczas testowania lokalnego upewnij się, że usługa zaplecza jest uruchomiona i używa poprawnego portu.

Jeśli testowanie pod kątem aplikacji interfejsu API platformy Azure, sprawdź, czy usługa jest uruchomiona i została wdrożona i została uruchomiona bez błędów.

Upewnij się, że adres podstawowy został poprawnie określony w postman lub w konfiguracji aplikacji mobilnej podczas testowania za pośrednictwem klienta. Adres podstawowy powinien wskazywać https://<api_name>.azurewebsites.net/ lub https://localhost:5001/ podczas testowania lokalnego.

Nie otrzymuję powiadomień w systemie Android po uruchomieniu lub zatrzymaniu sesji debugowania

Upewnij się, że zarejestrujesz się ponownie po uruchomieniu lub zatrzymaniu sesji debugowania. Debuger spowoduje wygenerowanie nowego tokenu Firebase. Należy również zaktualizować instalację centrum powiadomień.

Odbieranie kodu stanu 401 z usługi zaplecza

Sprawdź, czy ustawiasz nagłówek żądania apikey, a ta wartość jest zgodna z wartością skonfigurowaną dla usługi zaplecza.

Jeśli ten błąd występuje podczas testowania lokalnego, upewnij się, że wartość klucza zdefiniowana w konfiguracji klienta jest zgodna z wartością Authentication:ApiKey wartością ustawienia użytkownika używaną przez interfejs API .

Jeśli testujesz przy użyciuaplikacji interfejsu API , upewnij się, że wartość klucza w pliku konfiguracji klienta jest zgodna z ustawieniem aplikacji Authentication:ApiKey aplikacji używanym w aplikacji interfejsu API .

Nuta

Jeśli to ustawienie zostało utworzone lub zmienione po wdrożeniu usługi zaplecza, musisz ponownie uruchomić usługę w celu jej zastosowania.

Jeśli nie chcesz ukończyć uwierzytelniać klientów przy użyciu klucza interfejsu API, upewnij się, że nie zastosowano atrybutu Authorize do klasy NotificationsController.

Odbieranie kodu stanu 404 z usługi zaplecza

Sprawdź, czy punkt końcowy i metoda żądania HTTP są poprawne. Na przykład punkty końcowe powinny wskazywać na:

  • [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

Lub podczas testowania lokalnego:

  • [PUT]https://localhost:5001/api/notifications/installations
  • [DELETE]https://localhost:5001/api/notifications/installations/<installation_id>
  • [POST]https://localhost:5001/api/notifications/requests

Podczas określania adresu podstawowego w aplikacji klienckiej upewnij się, że kończy się /. Adres podstawowy powinien wskazywać https://<api_name>.azurewebsites.net/ lub https://localhost:5001/ podczas testowania lokalnego.

Nie można zarejestrować i zostanie wyświetlony komunikat o błędzie centrum powiadomień

Sprawdź, czy urządzenie testowe ma łączność sieciową. Następnie określ kod stanu odpowiedzi Http, ustawiając punkt przerwania w celu sprawdzenia wartości właściwości StatusCode w HttpResponse.

Przejrzyj poprzednie sugestie dotyczące rozwiązywania problemów, jeśli mają zastosowanie na podstawie kodu stanu.

Ustaw punkt przerwania w wierszach, które zwracają te określone kody stanu dla odpowiedniego interfejsu API. Następnie spróbuj wywołać usługę zaplecza podczas lokalnego debugowania.

Sprawdź, czy usługa zaplecza działa zgodnie z oczekiwaniami za pośrednictwem Postman przy użyciu odpowiedniego ładunku. Użyj rzeczywistego ładunku utworzonego przez kod klienta dla danej platformy.

Przejrzyj sekcje konfiguracji specyficzne dla platformy, aby upewnić się, że nie pominięto żadnych kroków. Sprawdź, czy odpowiednie wartości są rozpoznawane dla zmiennych installation id i token dla odpowiedniej platformy.

Nie można rozpoznać identyfikatora komunikatu o błędzie urządzenia

Przejrzyj sekcje konfiguracji specyficzne dla platformy, aby upewnić się, że nie pominięto żadnych kroków.

Następne kroki

Teraz powinna istnieć podstawowa aplikacja Flutter połączona z centrum powiadomień za pośrednictwem usługi zaplecza i może wysyłać i odbierać powiadomienia.

Prawdopodobnie musisz dostosować przykład użyty w tym samouczku, aby dopasować go do własnego scenariusza. Zalecane jest również zaimplementowanie bardziej niezawodnej obsługi błędów, logiki ponawiania prób i rejestrowania.

programu Visual Studio App Center można szybko włączyć do aplikacji mobilnych, zapewniając analizy i diagnostyki, aby ułatwić rozwiązywanie problemów.