Strona główna / Artykuły / Przekierowywanie powiadomień typu push przez deep linki w React Native

Przekierowywanie powiadomień typu push przez deep linki w React Native

Ustaw linki uniwersalne i linki aplikacji, połącz Pusher Beams z aplikacją React Native oraz powiąż adresy URL w sieci z ekranami natywnymi, aby kliknięcie powiadomienia otwierało właściwe miejsce.

1898 słów

Powiadomienie typu push jest przydatne tylko wtedy, gdy po jego kliknięciu użytkownik trafia na ekran, o którym mówi. Wyobraź sobie aplikację React Native przeznaczoną dla studentów zagranicznych wybierających uczelnie: e-maile pozostają niewyświetlone, a SMS-y są niepewne w różnych krajach, dlatego powiadomienia typu push muszą działać poprawnie, gdy ktoś z zespołu rekrutacyjnego pisze do nich. Tutaj skonfigurujesz łączenia głębokie na obu platformach, dołączysz adres strony internetowej do każdego powiadomienia Pusher Beams oraz przetłumaczysz ten adres na ścieżkę w React Navigation, testując przy tym każdy etap.

Dlaczego łączenia głębokie zawierają adres docelowy powiadomienia

Gdy tworzono tę konfigurację, pakiety Pusher używane w tym przypadku nie były w stanie przekazać spersonalizowanego ciężaru danych powiadomienia do części JavaScript aplikacji React Native na Androidzie. Najprostszym rozwiązaniem, podobnym do prośby o zmianę w Android SDK, jest wykorzystanie głębokiego łączenia: powiadomienie na Androidzie zawiera zwykły link do strony internetowej, kliknięcie w niego jest traktowane jak kliknięcie w ten link, a istniejąca w aplikacji funkcja obsługi głębokich łączeń decyduje, jakie ekran ma zostać otwarte.

Sytuacja ta mogła się od tamtej pory zmienić, dlatego najpierw sprawdź aktualne wersje SDK Beams. Warstwa routingu jest przydatna we wszystkich przypadkach, ponieważ obsługuje również linki z e-maili, SMS-ów lub czatów.

Krótka podsumowanie głębokiego łączenia

Deep linking umożliwia aplikacji przypisywanie sobie linków do własnej strony internetowej i ich otwieranie w sposób natywny. Link taki jak https://test.com/message/abc powinien otwierać aplikację bezpośrednio na wiadomości abc, zamiast uruchamiać przeglądarkę. iOS nazywa to uniwersalnymi linkami, a Android – linkami aplikacyjnymi; obie platformy wymagają jednak, aby twój domenowy serwer opublikował plik potwierdzający, że ufa aplikacji.

Ustawianie deep linking na obu platformach

Opublikuj pliki weryfikacyjne w katalogu .well-known

Stwórz katalog /.well-known/ w korzeniu swojej strony internetowej. Dla Androida dodaj plik /.well-known/assetlinks.json, który informuje, że twoja aplikacja może obsługiwać wszystkie linki w tym domenie. Zastąp miejsca zastępcze nazwą pakietu twojej aplikacji oraz wartością SHA-256 certyfikatu, który ją podpisuje:

[{
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
        "namespace": "android_app",
        "package_name": "package_name",
        "sha256_cert_fingerprints":
        ["package_cert_fingerprint"]
    }
}]

Jeśli Google Play ponownie podpisuje Twoje aplikacje, użyj odcisku palca klucza podpisywania Play, a nie klucza używanego do przesyłania plików – w przeciwnym razie weryfikacja zawiedzie tylko w środowisku produkcyjnym.

Dla iOS dodaj plik o nazwie /.well-known/apple-app-site-association (bez rozszerzenia). Zawiera on identyfikator Twojej aplikacji, który łączy ID zespołu i ID paczki, oraz ścieżki URL, które aplikacja powinna przechwytywać:

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "appId",
                "paths": [ "/paths-you-want-to-support", "/messenger"]
            }
        ]
    }
}

Serwuj oba pliki przez HTTPS z dokładnie tym samym domenem, bez przekierowań. To klasyczna struktura applinks; Apple dodało później nowszy format, więc sprawdź aktualną dokumentację.

Włącz powiązane domeny w iOS

iOS wymaga również uprawnień, które wskazują mu, do których domen należy aplikacja. W Xcode otwórz Capabilities, włącz Associated Domains i dodaj każdą domenę, którą chcesz połączyć, zazwyczaj w formie applinks:twojadomena.com.

Ogłaszanie filtrów intencji w Androidzie

W systemie Android głębokie linki są deklarowane za pomocą filtrów intencji w pliku AndroidManifest.xml. Aby obsłużyć linki typu /messenger/*, główna aktywność musi mieć filtr intencji dla działania VIEW z kategoriami DEFAULT i BROWSABLE, a także element data określający schemat https, hosta oraz prefiks ścieżki /messenger. Dodanie parametru android:autoVerify="true" poleca systemowi sprawdzenie pliku assetlinks.json, dzięki czemu aplikacja może otwierać te linki bez pokazywania okna wyboru.

Słuchanie połączeń w komponencie korzeniowym

Komponent główny aplikacji powinien wykonywać dwie czynności: odczytywać URL, który uruchomił aplikację przy pierwszym starcie, oraz przysłuchiwać się do URL-ów przychodzących w trakcie jej działania. Moduł Linking w React Native zapewnia obie te funkcje za pomocą metody getInitialURL() oraz słuchacza zdarzeń url. Oba powinny wywoływać ten sam obsługujący funkcję, który na razie może jedynie zapisywać URL do logu:

const handleDeepLink = (url: string) => console.log(url);

Przetestuj linki przed dodawaniem powiadomień

Zanim dodasz funkcję powiadomień, sprawdź najpierw działanie głębokiego łączenia. Prostym sposobem jest wysłanie linku do siebie za pośrednictwem aplikacji do komunikacji, takiej jak Slack, na każdym urządzeniu testowym i jego otwarcie. Jeśli konfiguracja jest poprawna, link otworzy twoją aplikację zamiast przeglądarki, a zapisany URL będzie odpowiadał temu, który otworzyłeś. Izolacja tej warstwy oznacza, że późniejsze błędy w routowaniu powiadomień będą dotyczyć wyłącznie problemów z przesyłaniem danych.

Dodawanie Pusher Beams do aplikacji

Wymagania wstępne i most społecznościowy

Potrzebujesz konta Pusher Beams oraz musisz ukończyć kroki konfiguracji dla usługi push Apple oraz Google Firebase.

Należy pamiętać, że w momencie pisania tej integracji Pusher nie oferował oficjalnego pakietu dla React Native. Mostem użytym tutaj jest pakiet społecznościowy react-native-pusher-push-notifications, który łączy natywne SDK Beams z JavaScript i nie jest wspierany przez Pusher. Wymagał on niewielkich modyfikacji, aby działać w tym ustawieniu. Na Androidzie kluczową zmianą była odmiana SDK push-notifications-android firmy Pusher, która przekształca kliknięcie powiadomienia w otwarcie łącza głębokiego. Nieoficjalny most w połączeniu z odmianą SDK stanowi obowiązek konserwacyjny: należy utrzymywać określone wersje i ponownie rozważyć tę opcję, gdy zmienią się oficjalne SDK.

Zainstaluj SDK Swift na iOS

Część dla iOS polega na użyciu Swift SDK od Pusher, które instaluje się tutaj za pomocą Carthage. Dodaj następujący wiersz do pliku /ios/Cartfile, a następnie uruchom polecenie carthage bootstrap, aby je pobrać i zbudować:

github "pusher/push-notifications-swift" ~> 1.3.0

Ta wersja była aktualna dla tej integracji; nowsze projekty prawdopodobnie będą używać nowszego SDK oraz innego menedżera zależności.

Następnie postępuj zgodnie z instrukcjami ręcznej instalacji pakietu mostowego dla obu platform, ponieważ elementy natively zaimplementowane są dostosowywane indywidualnie.

Wysyłanie testowej powiadomienia

Powiadomienia na iOS docierają tylko do urządzeń fizycznych, a nie do symulatorów, więc miej pod ręką prawdziwy iPhone.

Aby wysłać testowy komunikat push, użyj konsoli Debug w panelu sterowania Pusher lub klienta HTTP takiego jak Postman, który wywołuje API Beams publish. Wystarczy ciało żądania zawierające sekcję iOS i sekcję Android; w tym ustawieniu część dla iOS ustala liczbę odznak na 5, a część dla Android zawiera adres URL strony internetowej, która powinna zostać otwarta.

Gdy wszystko jest poprawnie skonfigurowane, iOS sam przetwarza treść powiadomienia, natomiast Android otwiera aplikację za pomocą intencji View z adresem URL twojej strony. Na obu platformach twój obsługiwacz powinien zapisywać coś w rodzaju https://yourdomain/messenger/abcde. Na iOS ikona aplikacji powinna dodatkowo pokazywać odznakę z numerem 5.

Zmiana URL na trasy React Navigation

Ostatnim krokiem jest zastąpienie tymczasowego mechanizmu logowania rzeczywistym routowaniem. Powszechnie stosowanym rozwiązaniem jest użycie React Router na stronie internetowej oraz React Navigation w aplikacji React Native. Mała biblioteka pomocnicza, która mapuje ścieżki internetowe na ścieżki natywne, umożliwia wspólne wykorzystanie logiki i zapobiega temu, by przemianowana ścieżka internetowa potajemnie zakłócała nawigację w aplikacji.

Dzielenie się stałymi ścieżek pomiędzy wersją internetową a natywną

Oba zbiory kodu definiują swoje ścieżki jako stałe. W wersji internetowej narzędzie do budowania ścieżek zwraca albo konkretną ścieżkę, albo wzorzec, z którym React Router dokonuje dopasowania; w wersji natywnej odpowiednikiem jest nazwa ekranu, przy czym identyfikator rozmowy jest przekazywany oddzielnie jako parametr nawigacji:

// Web:
ROUTE = {
    MESSENGER_CONVERSATION: (conversationId?: string) =>
        conversationId
            ? `/messenger/${conversationId}`
            : "/messenger/:conversationId"
}// Native:
APP_STACK_ROUTE: {
    MESSENGER_CONVERSATION_SCREEN:
        "app_stack_routes/messenger_conversation"
}
// native then has a params object with conversationId included

Gdy obie strony są wyrażone jako stałe, można w jednej tabeli określić, która ścieżka internetowa odpowiada której ekranowi natywnemu:

const ROUTE_MATCHES: IRouteMatches = [
    {
        webPath: ROUTE.MESSENGER_CONVERSATION(),
        rnPath: APP_STACK_ROUTES.MESSENGER_CONVERSATION_SCREEN
    }
];

Wywołanie ROUTE.MESSENGER_CONVERSATION() bez żadnego argumentu zwraca wzorzec /messenger/:conversationId, więc tabela przechowuje ten sam wzorzec, który używa router strony internetowej. Przeniesienie nazwy trasy webowej automatycznie aktualizuje mapowanie. Aby ponownie zapoznać się z funkcjonowaniem tych wzorców webowych, sprawdź podstawy React Router.

Odbijanie nadchodzących URL-ów

Obsługa czasami uruchamia się więcej niż raz na jeden kliknięcie, na przykład gdy zarówno sprawdzenie początkowego URL-u, jak i słuchacz zgłaszają istnienie łącza, co powoduje pojawienie się duplikatowych ekranów. Przesyłanie każdego URL-u przez Subject w RxJS oraz zastosowanie funkcji debounceTime(100) sprowadza serię wywołań do jednego, które następnie trafia do processUrl:

export const handleDeepLink = (url: string): void => {
    if (!url) return;
    onChangeUrl$.next(url);
};
const onChangeUrl$: Subject<string> = new Subject<string>();
const urlSubscription: Observable<string> = onChangeUrl$.pipe(debounceTime(100));
urlSubscription.subscribe(processUrl);

Kompromis: dwa różne linki w ciągu 100 ms łączą się w jeden ostatni, co jest akceptowalne przy klikaniu w powiadomienia.

Rozbicie URL na części

processUrl najpierw dzieli URL na protokół, hosta, ścieżkę i ciąg zapytania za pomocą wyrażenia regularnego (narzędzie takie jak RegExr pomaga przy jego dostosowywaniu). Dekonstrukcja pomija pełne dopasowanie oraz grupę zapytania, która nadal zawiera ?:

const REGEX_DECONSTRUCT_URL = /^(.*?):\/\/(.*?)(\/.*?)(\?(.*))?$/;const deconstructedUrl = REGEX_DECONSTRUCT_URL.exec(url);
    if (!deconstructedUrl) return;
    const [originalUrl, protocol, tld, path, ignore, querystring] = deconstructedUrl;

Należy pamiętać, że to wzorzec wymaga ścieżki: prosty https://yourdomain bez końcowej kreski nie zostanie dopasowany, a funkcja zwróci wynik wcześniej. Jest to w porządku dla linków powiadomień, ale warto o tym wiedzieć, jeśli używasz tego narzędzia gdzie indziej.

Dopasowanie ścieżki do tabeli tras

Gdy elementy zostały wydobyte, mechanizm obsługi przechodzi dalej tylko do linków HTTPS w Twoim domenie, a następnie przegląda ROUTE_MATCHES aż do momentu, gdy jakaś pozycja zaakceptuje daną ścieżkę:

if (protocol === "https" && tld.includes("yourdomain")) {
    for (let i = 0; i < ROUTE_MATCHES.length; i++) {
        if (matchPath(ROUTE_MATCHES[i], path, querystring)) {
            // loop until one matches
            break;
        }
    }
}

Sprawdzenie tld.includes("twojadomena") jest wygodne, ale niewystarczające – zaakceptowałoby ono również hosta taki jak twojadomena.attacker.example. System operacyjny weryfikuje linki uniwersalne i aplikacyjne, więc ryzyko jest ograniczone, ale dokładna lista dopuszczalnych hostów to tanie rozwiązanie poprawiające bezpieczeństwo, szczególnie gdy mechanizm obsługi jest współdzielony z innymi źródłami URL.

Wewnątrz matchPath wzorzec webPath jest sprawdzany w odniesieniu do dostarczonej ścieżki za pomocą path-to-regexp – tej samej biblioteki, od której korzysta React Router. Gdy następuje dopasowanie, wydobyte parametry, takie jak conversationId, stają się parametrami odpowiadającego ekranu rnPath, a aplikacja przechodzi tam. Ponieważ ta operacja odbywa się poza jakimkolwiek komponentem, uruchamia ją niewielka usługa nawigacyjna przechowująca referencję do głównego navigatora, jak opisano w dokumentacji React Navigation dla nawigacji bez użycia właściwości navigation.

Podsumowanie

Gdy te elementy są już w miejscu, aplikacja obsługuje dwa zadania poprzez jedną ścieżkę kodu:

  • Linki do Twojej strony internetowej, niezależnie od tego, czy pochodzą z e-maila, SMS-a czy czatu, otwierają odpowiedni ekran w aplikacji natywnej.
  • Powiadomienia typu push wykorzystują tę samą metodę obsługi głębokich linków, dzięki czemu kliknięcie przenosi użytkownika bezpośrednio do odpowiedniej rozmowy.
  • To, co ułatwia utrzymanie tego rozwiązania, to traktowanie adresu URL strony jako jedynego opisu celu, przy czym tabela służy do konwertowania adresów URL na lokalne ścieżki. Testuj każdą warstwę osobno, wzmocnij kontrolę hosta i obserwuj oficjalne SDK Beams: jeśli przekazują one dane do JavaScript, możesz zrezygnować z własnej wersji i zachować warstwę routingu.

    Powiązane materiały