Wróć do bloga
/Aktualizacja /aplikacje mobilne/13 min czytania

Architektura Hotwire Native: kiedy mobilna aplikacja Rails oparta na webie ma sens

Praktyczny przewodnik architektoniczny: kiedy Hotwire Native pasuje do produktu Rails, które ścieżki pozostawić webowe i gdzie warto ponieść koszt komponentów natywnych.

Sebastian Tekieli

Chief AI Agents Officer i inżynier oprogramowania

Tworzenie aplikacji mobilnych od dawna stawia zespoły przed zasadniczym wyborem: budować osobne aplikacje natywne na każdą platformę czy postawić na rozwiązanie wieloplatformowe i zaakceptować kompromisy w wygodzie korzystania z aplikacji. Istnieje jednak trzecia droga. Można zbudować aplikację zgodną z konwencjami platformy, a jednocześnie wykorzystać kompetencje webowe zespołu i istniejącą aplikację Rails.

Hotwire Native pozwala przekształcić aplikację webową w aplikację mobilną z natywną powłoką. Zespół nadal może szybko rozwijać i łatwo utrzymywać warstwę webową, a jednocześnie korzystać z nawigacji i funkcji charakterystycznych dla iOS i Androida.

Jak zdecydować, czy Hotwire Native pasuje do produktu

Hotwire Native daje najwięcej korzyści, gdy produkt ma już architekturę opartą przede wszystkim na warstwie webowej (ang. web-first): to aplikacja renderowana po stronie serwera nadal określa, jak działa produkt, a najważniejsze funkcje to procesy dostępne po zalogowaniu i oparte na modelu domenowym Rails. Nie jest to skrót, który automatycznie zmieni każdą stronę internetową w dobrą aplikację mobilną. Właściwe pytanie brzmi: czy produkt może współdzielić implementację funkcji między platformami, a zarazem przestrzegać konwencji iOS i Androida?

Cecha produktuMocny argument za Hotwire NativeSygnał ostrzegawczy
Główne procesyFormularze, rekordy, współpraca, akceptacje, treściInterakcje oparte na rozbudowanej grafice lub ciągłe renderowanie w czasie rzeczywistym
Istniejący systemDojrzała, responsywna aplikacja RailsBrak stabilnego produktu webowego lub niespójny zestaw interfejsów API po stronie serwera
Rodzaj zmianLogika biznesowa zmienia się częstoWiększość zmian dotyczy natywnej prezentacji i obsługi funkcji urządzenia
ZespółDuże doświadczenie w Railsie i technologiach webowych, uzupełnione wybranymi kompetencjami natywnymiOsobne zespoły natywne, które już sprawnie publikują kolejne wersje
Praca offlineSporadyczny dostęp do danych z pamięci podręcznej i płynne wznawianie działania po odzyskaniu połączeniaDomena projektowana przede wszystkim do pracy offline, ze złożoną synchronizacją

Każdą ścieżkę użytkownika warto podzielić na trzy warstwy. Warstwa webowa odpowiada za reguły biznesowe, ekrany renderowane po stronie serwera, walidację i dane. Natywna powłoka przejmuje nawigację, cykl życia aplikacji, uprawnienia oraz konwencje platformy. Bridge Components należy zarezerwować dla funkcji, które wyraźnie zyskują na natywnej obsłudze, takich jak powiadomienia, aparat, biometria, systemowe menu udostępniania, lokalizacja lub kontrolka ściśle związana z daną platformą.

Tak wyznaczona granica chroni przed dwoma typowymi błędami. Pierwszy polega na ograniczeniu aplikacji do prostej powłoki strony, która sprawia wrażenie niedopracowanej, ponieważ ignoruje natywną nawigację i cykl życia aplikacji. Drugi polega na przeniesieniu do Swifta i Kotlina tak dużej części logiki, że zespół ponownie mierzy się z problemem dwóch baz kodu, którego Hotwire Native miał właśnie uniknąć.

Etapowy plan wdrożenia aplikacji

  1. Wybierz jedną reprezentatywną ścieżkę, obejmującą uwierzytelnianie i obsługę błędów.
  2. Zanim zaczniesz dopracowywać wygląd, określ konfigurację ścieżek i odpowiedzialność za nawigację.
  3. Dodaj analitykę, która odróżnia nawigację webową, akcje natywne i wywołania przez most.
  4. Przetestuj wolne połączenie, wygaśnięcie sesji, deep linki, aktualizacje aplikacji i przerwane procesy.
  5. Udostępnij wersję małej grupie odbiorców, zanim rozszerzysz zakres ekranów obsługiwanych przez warstwę webową.

Pierwszym kamieniem milowym nie powinno być po prostu „otwarcie strony w aplikacji”. Powinien nim być pełny proces, który działa poprawnie po zamknięciu aplikacji przez system, wygaśnięciu sesji, użyciu przycisku Wstecz, otwarciu zewnętrznego linku i wdrożeniu nowej treści renderowanej po stronie serwera.

Podejście hybrydowe: mocne strony obu środowisk

Tradycyjne sposoby tworzenia aplikacji mobilnych zmuszają zespoły do trudnych kompromisów:

  • Aplikacje w pełni natywne zapewniają dopracowany interfejs, lecz wymagają osobnych zespołów, baz kodu i kosztownego utrzymania
  • Frameworki wieloplatformowe umożliwiają ponowne wykorzystanie kodu, ale często kosztem optymalizacji dla konkretnej platformy i natywnego charakteru interfejsu

Hotwire Native zmienia ten układ dzięki architekturze hybrydowej. Aplikacja Rails staje się centrum logiki mobilnego produktu, a natywne komponenty iOS i Androida odpowiadają za prezentację oraz obsługę funkcji charakterystycznych dla platformy.

Najważniejszą decyzją nie jest to, czy opakować stronę internetową natywną powłoką. Trzeba ustalić, które ścieżki pozostaną obsługiwane przez web, które wymagają komponentów natywnych oraz jak w obu środowiskach będą działać nawigacja, uwierzytelnianie, wydawanie wersji i analityka. To rdzeń świadomie zaprojektowanej architektury Hotwire Native i systemów mobilnych, a nie dodatek wprowadzany na końcu projektu Rails.

Jak działa Hotwire Native

Hotwire Native opiera się na prostej, ale skutecznej zasadzie: to aplikacja webowa nadal definiuje logikę biznesową, zarządza danymi i realizuje główne funkcje. Natywne aplikacje mobilne stanowią powłokę, która wyświetla treści webowe, a jednocześnie zapewnia natywną nawigację, animacje i komponenty właściwe danej platformie.

Na początek wystarczy niewielka aplikacja natywna na iOS i Androida. Kilka linii kodu pozwala uruchomić aplikację mobilną opartą na Railsie.

Tyle wystarczy, aby zacząć na iOS:

import HotwireNative
import UIKit

let rootURL = URL(string: "https://hotwire-native-demo.dev")!

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    private let navigator = Navigator(configuration: .init(
        name: "main",
        startLocation: rootURL
    ))

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        window?.rootViewController = navigator.rootViewController
        navigator.start()
    }
}

Na Androidzie konfiguracja jest równie krótka:

package com.example.myapplication // update to match your project

import android.os.Bundle
import android.view.View
import androidx.activity.enableEdgeToEdge
import dev.hotwire.navigation.activities.HotwireActivity
import dev.hotwire.navigation.navigator.NavigatorConfiguration
import dev.hotwire.navigation.util.applyDefaultImeWindowInsets

class MainActivity : HotwireActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<View>(R.id.main_nav_host).applyDefaultImeWindowInsets()
    }

    override fun navigatorConfigurations() = listOf(
        NavigatorConfiguration(
            name = "main",
            startLocation = "https://hotwire-native-demo.dev",
            navigatorHostId = R.id.main_nav_host
        )
    )
}

A co z treścią? Za nią odpowiada Rails.

Most między Rails a aplikacją mobilną

Komunikację między aplikacją webową i natywnymi komponentami mobilnymi zapewniają Bridge Components. Komponent webowy wysyła przez most komunikat zawierający nazwę zdarzenia i dane. Odpowiadający mu komponent w aplikacji iOS lub Android odbiera komunikat, korzysta z odpowiedniej funkcji systemu, a w razie potrzeby odsyła wynik do warstwy webowej. Dzięki temu aplikacja Rails może na przykład skorzystać z aparatu lub uwierzytelniania biometrycznego, wyświetlić systemowe menu udostępniania albo niestandardowy element interfejsu bez przenoszenia całego procesu biznesowego z warstwy webowej.

Most nie zastępuje kodu natywnego. Każda obsługiwana funkcja wymaga implementacji i rejestracji odpowiedniego komponentu osobno na iOS i Androidzie, a przy zmianie kontraktu komunikatów trzeba zachować zgodność z już zainstalowanymi wersjami aplikacji. Dlatego Bridge Components najlepiej stosować punktowo, tam gdzie korzyść dla użytkownika uzasadnia koszt utrzymania obu implementacji.

Diagram architektury

Taka architektura przynosi kilka istotnych korzyści:

  • Jedna główna baza kodu: aplikacja Rails obsługuje logikę biznesową, zarządzanie danymi i najważniejsze funkcje
  • Natywna wydajność tam, gdzie ma znaczenie: wybrane optymalizacje i komponenty interfejsu mogą korzystać bezpośrednio z możliwości platformy
  • Szybkie aktualizacje: po pierwszej akceptacji aplikacji w App Store i Google Play zmiany dotyczące ekranów i logiki realizowanej przez aplikację Rails można wdrażać bez kolejnej publikacji w sklepach
  • Krótszy cykl rozwoju: zmiany w warstwie webowej są od razu widoczne w aplikacjach mobilnych
  • Integracja z platformą: Bridge Components zapewniają dostęp do funkcji iOS i Androida
  • Zgodność z wymaganiami sklepów: właściwa integracja natywna pomaga spełnić wymagania App Store i Google Play

Nie wszystkie aktualizacje omijają jednak proces publikacji w sklepach. Zmiany w natywnej powłoce, Bridge Components, uprawnieniach czy konfiguracji platformy nadal wymagają nowej kompilacji i standardowej weryfikacji. Hotwire Native nie usuwa też potrzeby testowania obu platform, obsługi niestabilnego połączenia i dbania o zgodność między serwerem a starszymi wersjami aplikacji.

Dlaczego Hotwire Native ma znaczenie

Hotwire Native inaczej rozkłada koszty projektu mobilnego. Zamiast wybierać wyłącznie między natywną wydajnością a tempem tworzenia aplikacji webowej, zespół może współdzielić implementację głównych funkcji produktu i inwestować w kod natywny tylko w tych miejscach, w których przynosi on odczuwalną wartość. Podejście szczególnie dobrze pasuje do:

  • Startupów, które muszą szybko wprowadzać zmiany i mają ograniczone kompetencje mobilne
  • Firm rozwijających głównie produkt webowy, które chcą rozszerzyć jego zasięg na urządzenia mobilne
  • Zespołów, które chcą utrzymywać jedną główną bazę kodu, a jednocześnie tworzyć interfejs zgodny z konwencjami platformy
  • Aplikacji, w których logika biznesowa często się zmienia

Hotwire Native zaciera tradycyjną granicę między tworzeniem produktów webowych i mobilnych. Pozwala programistom webowym budować rozbudowane aplikacje mobilne bez opanowywania od razu całych platform i nowych języków. Nie zwalnia jednak z projektowania granic odpowiedzialności ani z rozwijania konkretnych kompetencji w Swift i Kotlinie. O powodzeniu decyduje świadomy podział: Rails zarządza regułami i danymi, natywna powłoka odpowiada za integrację z platformą, a most łączy oba środowiska tylko tam, gdzie jest naprawdę potrzebny.

Wcześniejsza wersja tego artykułu ukazała się na Blog Visuality.pl.

Chcesz porozmawiać na ten temat?

Zamieńmy ten pomysł w praktyczną architekturę i plan wdrożenia.

Umów konsultację