Ładowanie spekulacyjne w WebView

Opóźnienie nawigacji to kluczowy wskaźnik wrażeń użytkownika. Aby pomóc deweloperom zmniejszyć to opóźnienie, WebView udostępnia interfejsy API do ładowania spekulacyjnego i optymalizacji połączeń, dzięki czemu aplikacja może pobierać lub renderować treści, zanim użytkownik do nich przejdzie.

WebView obsługuje 3 główne typy spekulacyjnego wczytywania: wstępne nawiązywanie połączenia, wstępne pobieranie i wstępne renderowanie, a także wskazówki QUIC do optymalizacji negocjacji protokołu.

Wdrażając strategię ładowania spekulacyjnego, możesz osiągnąć następujące korzyści:

  • Znaczne skrócenie czasu oczekiwania na wczytanie treści internetowych: przenieś czas rozpoczęcia działania sieci na wcześniejszy etap cyklu życia aplikacji i używaj szybszych protokołów, takich jak HTTP/3.
  • Wyższy odsetek udanych nawigacji: dzięki wstępnemu przygotowaniu sieci i pamięci podręcznej nawigacje rzadziej kończą się niepowodzeniem z powodu przejściowych problemów z siecią.
  • Lepsza postrzegana szybkość reakcji: renderowanie wstępne umożliwia natychmiastowe przejścia, dzięki czemu aplikacja wydaje się znacznie szybsza.

Wybieranie strategii ładowania spekulacyjnego

Główna różnica między tymi strategiami polega na ich zakresie: interfejsy API wskazówek dotyczących wstępnego połączenia i QUIC są oparte na źródle, co oznacza, że wymagają tylko domeny docelowej. Interfejsy API wstępnego pobierania i wstępnego renderowania są oparte na adresach URL, co oznacza, że wymagają dokładnej ścieżki do strony.

Wskazówki dotyczące wstępnego nawiązywania połączenia i QUIC działają na poziomie źródła, więc możesz je wywoływać, zanim dowiesz się, do jakich konkretnych treści lub stron przejdzie użytkownik.

Poniższa tabela porównuje te 3 strategie, aby pomóc Ci wybrać odpowiednią dla Twojego przypadku:

Funkcja Preconnect Pobieranie z wyprzedzeniem Renderowanie wstępne
Cel główny Rozgrzej połączenie Pamięć podręczna tylko HTML (bez JavaScriptu ani CSS) Wstępne renderowanie całej strony
Zakres Poziom profilu (udostępniany w widokach WebView) Poziom profilu (udostępniany w widokach WebView) Poziom WebView (powiązany z konkretnym komponentem WebView)
Jetpack WebKit API androidx.webkit.Profile androidx.webkit.Profile androidx.webkit.WebViewCompat
Podstawowe metody interfejsu API preconnect(...) prefetchUrlAsync(...) prerenderUrlAsync(...)
Konfiguracja Nie dotyczy PrefetchCache.setMaxPrefetches()
PrefetchCache.setPrefetchTtlSeconds()
setMaxPrerenders()
Wykorzystanie zasobów Niska (sieć) Średnie (sieć, pamięć) Wysokie (procesor, pamięć, sieć)
Kiedy używać Gdy znane jest docelowe źródło, ale konkretny adres URL nie został jeszcze określony. Gdy dokładny adres URL jest znany, a nawigacja jest prawdopodobna, z pamięcią podręczną udostępnianą w widokach WebView. Gdy dokładny adres URL jest znany, a nawigacja w określonym widoku WebView jest bardzo pewna.
Zalety Szybsze konfigurowanie połączenia z dowolnym adresem URL w domenie źródłowej Szybsze wczytywanie sieci w przypadku dopasowanych adresów URL Prawdziwie natychmiastowa nawigacja po aktywacji

Nawiązywanie połączeń ze źródłami w trybie preconnect

Wstępne łączenie przyspiesza przyszłe ładowanie, ponieważ z wyprzedzeniem wykonuje wyszukiwanie DNS i uzgadnianie połączenia TCP/TLS lub QUIC dla określonego źródła.

W przeciwieństwie do pobierania z wyprzedzeniem i wstępnego renderowania, które wymagają dokładnego docelowego adresu URL, wstępne nawiązywanie połączenia jest oparte wyłącznie na pochodzeniu. Dzięki temu możesz wywołać Preconnect, zanim poznasz dokładny adres URL. Wskazówki dotyczące tego, kiedy wywoływać tę funkcję, znajdziesz w sekcji Implementacja.

Ta strategia na poziomie profilu, która wymaga niewielkich zasobów, zmniejsza początkowe opóźnienie w przypadku udostępniania w dowolnym widoku WebView w tym profilu, pod warunkiem że źródło nie zostało jeszcze odwiedzone. Połączenie pozostaje otwarte przez około 30 sekund, co ułatwia kolejne żądania HTTP ze współdzieleniem zasobów z innych domen, nawigacje i zasoby podrzędne, ponieważ eliminuje narzut związany z uzgadnianiem połączenia. Wynik wyszukiwania DNS jest przechowywany w pamięci podręcznej dłużej niż połączenie, więc późniejsze żądania do serwera źródłowego mogą nadal pomijać wyszukiwanie po zamknięciu połączenia.

Implementacja

Aby zainicjować wstępne połączenie, zadzwoń pod numer preconnect(String url) na instancji Profile. Ten interfejs API musi być wywoływany w wątku UI i wymaga obsługi WebViewFeature.PRECONNECT.

Interfejs API działa na źródle, ale dla wygody można podać pełny adres URL (np. https://www.example.com/index.html). Jest to automatycznie traktowane jako wywołanie źródła (np. https://www.example.com). Z tym interfejsem API można połączyć wiele źródeł, wywołując go wielokrotnie.

Kotlin

// Must be called on the @UiThread
if (WebViewFeature.isFeatureSupported(WebViewFeature.PRECONNECT)) {
    profile.preconnect("https://www.example.com/index.html")
    // This initiates a connection to the origin https://www.example.com
}

Java

// Must be called on the @UiThread
if (WebViewFeature.isFeatureSupported(WebViewFeature.PRECONNECT)) {
    profile.preconnect("https://www.example.com/index.html");
    // This initiates a connection to the origin https://www.example.com
  }

Wskazywanie obsługi protokołu QUIC za pomocą wskazówek QUIC

HTTP/3 (który działa w protokole transportowym QUIC) zapewnia znacznie mniejsze opóźnienia niż HTTP/2, w tym uzgadnianie połączenia 0-RTT, większą odporność połączenia i eliminację blokowania na początku kolejki w przypadku utraty pakietów.

Domyślnie WebView próbuje nawiązać połączenie QUIC tylko wtedy, gdy ma informację, że pochodzenie obsługuje QUIC, np. z nagłówka Alt-Svc lub rekordu DNS HTTPS z poprzedniej interakcji. Bez tej wiedzy WebView używa protokołu HTTP/2 lub HTTP/1.1 do nawiązania połączenia początkowego.

Wywołanie addQuicHints wstępnie wypełnia informacje o obsłudze protokołu, co umożliwia WebView natychmiastowe połączenie przy użyciu QUIC podczas pierwszego połączenia z określonymi źródłami.

Połączenie w trybie preconnect z użyciem wskazówek QUIC

Zarówno wskazówki dotyczące wstępnego nawiązywania połączenia, jak i QUIC to optymalizacje na poziomie źródła w przypadku Profile, ale pełnią różne, uzupełniające się role:

  • preconnect: aktywnie otwiera i utrzymuje połączenie sieciowe (wyszukiwanie DNS i uzgadnianie połączenia TCP/TLS lub QUIC) przez około 30 sekund. Ponieważ utrzymuje otwarte aktywne połączenia sieciowe, zużywa zasoby urządzenia i sieci, dlatego należy go używać tylko w przypadku docelowych źródeł o wysokim prawdopodobieństwie.
  • addQuicHints: Nie powoduje natychmiastowego ruchu w sieci. Aktualizuje właściwości serwera w pamięci Profile stosu sieciowego, aby rejestrować obsługę protokołu. Ponieważ ma on znikome obciążenie, możesz bezpiecznie skonfigurować wskazówki QUIC podczas uruchamiania aplikacji dla wszystkich znanych źródeł obsługujących HTTP/3.

Aby uzyskać optymalną skuteczność, zadzwoń pod numer addQuicHints przed zadzwonieniem pod numer preconnect,prefetchUrlAsync lub loadUrl. Dzięki temu wszystkie kolejne połączenia wstępne lub żądania stron będą od początku negocjować protokół HTTP/3.

Implementacja

Aby skonfigurować wskazówki QUIC, wywołaj addQuicHints(Set<String> urls) na instancji Profile. Ten interfejs API musisz wywołać w wątku UI i sprawdzić, czy komponent WebView obsługuje funkcję WebViewFeature.ADD_QUIC_HINTS_V1.

Podobnie jak preconnect, addQuicHints działa na podstawie źródeł, ale można podać pełne adresy URL (np. https://www.example.com/index.html), które są automatycznie normalizowane do źródła (https://www.example.com).

Ta metoda jest addytywna: wywołanie jej kilka razy powoduje scalenie podanych domen w Profile.

Kotlin

// Must be called on the @UiThread
@OptIn(Profile.ExperimentalAddQuicHints::class)
if (WebViewFeature.isFeatureSupported(WebViewFeature.ADD_QUIC_HINTS_V1)) {
    val quicOrigins = setOf(
        "https://www.example.com",
        "https://api.example.com"
    )
    profile.addQuicHints(quicOrigins)
    // WebView now prioritizes HTTP/3 over QUIC for connections to these origins
}

Java

// Must be called on the @UiThread
// Requires @Profile.ExperimentalAddQuicHints annotation or suppression
if (WebViewFeature.isFeatureSupported(WebViewFeature.ADD_QUIC_HINTS_V1)) {
    Set<String> quicOrigins = new HashSet<>(Arrays.asList(
        "https://www.example.com",
        "https://api.example.com"
    ));
    profile.addQuicHints(quicOrigins);
    // WebView now prioritizes HTTP/3 over QUIC for connections to these origins
}

Typowa konfiguracja: PrefetchParameters i PrerenderParameters

Zarówno w przypadku wstępnego pobierania, jak i wstępnego renderowania do dostosowywania żądania używa się PrefetchParameters lub PrerenderParameters. Te klasy umożliwiają podawanie dodatkowych nagłówków i wskazówek dotyczących dopasowywania adresów URL, np. konfiguracji No-Vary-Search.

Kotlin

// Isolated configuration specifically for Cache-Level Prefetching
val prefetchParams = PrefetchParameters.Builder()
    .addAdditionalHeader("X-Custom-Client", "Android-App-V2")
    .setExpectedNoVarySearchHeader(
        NoVarySearchHeader.varyExcept(true, listOf("session_id", "click_ref"))
    )
    .build()

Java

PrefetchParameters prefetchParams = new PrefetchParameters.Builder()
    .addAdditionalHeader("X-Custom-Header", "value")
    /**
     * Hint to ignore specific query parameters during cache matching.
     * This allows the cache to match even if the tracking_id differs.
     */
    .setExpectedNoVarySearchHeader(
        NoVarySearchHeader.varyExcept(true, Arrays.asList("tracking_id"))
    )
    /**
     * Determines if Client Hints are sent.
     * NOTE: This is ignored for Prerendering API requests, which default to
     * the WebView's WebSettings.getJavaScriptEnabled() value.
     */
    .setJavaScriptEnabled(true)
    .build();

Pobieranie treści z wyprzedzeniem

Pobieranie z wyprzedzeniem pobiera główny zasób HTML adresu URL i przechowuje go w pamięci podręcznej sieci profilu. W komponencie WebView obiekt Profile pełni funkcję kontenera danych przeglądarki, w tym plików cookie, pamięci podręcznej HTTP i procesów roboczych usługi. Prefetch to operacja na poziomie profilu, więc każdy WebView powiązany z tym profilem może korzystać z odpowiedzi w pamięci podręcznej.

Implementacja

Aby zainicjować wstępne pobieranie, wywołaj metodę prefetchUrlAsync() w instancji Profile. Ta operacja obsługuje tylko schemat HTTPS.

Kotlin

profile.prefetchUrlAsync(
    url,
    prefetchParams,
    cancellationSignal,
    executor,
    object : WebViewOutcomeReceiver<PrefetchResult, PrefetchException> {
        override fun onResult(result: PrefetchResult) {
            if (result.wasDuplicate()) {
                // URL and No-Vary-Search permutations already exist in the cache layer
            } else {
                // The HTML payload has been successfully secured in the HTTP cache
            }
        }

        override fun onError(error: PrefetchException) {
            when (error) {
                is PrefetchNetworkException -> {
                    // Isolates network layer or server-side HTTP anomalies
                    val code = error.httpStatusCode
                    // Facilitates rapid diagnosis of 4xx or 5xx server responses
                }
                else -> {
                    // Catches generalized execution failures and system constraints
                }
            }
        }
    }
)

Java

profile.prefetchUrlAsync(
    url,
    prefetchParams,
    cancellationSignal,
    executor,
    new WebViewOutcomeReceiver<PrefetchResult, PrefetchException>() {
        @Override
        public void onResult(PrefetchResult result) {
            if (result.wasDuplicate()) {
                // URL and No-Vary-Search permutations already exist in the cache layer
            } else {
                // The HTML payload has been successfully secured in the HTTP cache
            }
        }

        @Override
        public void onError(PrefetchException error) {
            if (error instanceof PrefetchNetworkException) {
                // Isolates network layer or server-side HTTP anomalies
                int code = ((PrefetchNetworkException) error).httpStatusCode;
                // Facilitates rapid diagnosis of 4xx or 5xx server responses
            } else {
                // Catches generalized execution failures and system constraints
            }
        }
    }
);

Cykl życia przechwytywania

Prośba o wstępne pobranie WebView zmienia moment i sposób wywoływania shouldInterceptRequest() wywołania zwrotnego. Ma to bezpośredni wpływ na to, czy wstępnie pobrane treści zostaną użyte, dlatego ważne jest, aby poznać 2-etapowy cykl życia:

Diagram przedstawiający dwuetapowy cykl życia przechwytywania wstępnego pobierania WebView podczas fazy spekulacyjnej i nawigacji.
Rysunek 1. Dwuetapowy cykl życia przechwytywania żądań i nawigacji w przypadku wstępnego pobierania WebView.

1. Faza spekulacyjna (żądanie wstępnego pobrania)

Gdy wywoływana jest funkcja prefetchUrlAsync(), WebView pobiera w tle główny zasób HTML. shouldInterceptRequest() jest całkowicie pomijany w przypadku tego żądania w tle. Żadna niestandardowa logika, tokeny autoryzacji ani wstrzykiwanie nagłówków, które są zwykle obsługiwane w interceptorze, nie są stosowane do wstępnie pobranego zasobu HTML.

2. Faza nawigacji (aktywacja użytkownika)

Gdy aplikacja wyraźnie przechodzi do adresu URL (np. za pomocą WebViewCompat.navigate lub loadUrl) albo użytkownik kliknie pasujący link, komponent WebView sprawdza, czy może użyć wstępnie pobranej pamięci podręcznej:

  • Ocena głównego kodu HTML: w tym momencie WebView wywoła shouldInterceptRequest() dla głównego kodu HTML. Aby strona została wyświetlona z pamięci podręcznej pobierania wstępnego, przechwytujący musi zwrócić wartość null. Jeśli zwrócisz niestandardowyWebResourceResponse, WebView uwzględni Twój przechwytujący i całkowicie pominie pamięć podręczną wstępnego pobierania.

  • Ocena zasobów podrzędnych: po tym, jak wstępnie pobrany kod HTML zostanie dopuszczony do użycia,shouldInterceptRequest() tagi są zwykle wywoływane w przypadku wszystkich kolejnych zasobów podrzędnych (takich jak obrazy, skrypty i arkusze CSS) wymaganych do zakończenia renderowania strony.

Kluczowe zachowania

Sposób, w jaki WebView inicjuje żądania wstępnego pobierania i nimi zarządza, zależy od tych cech operacyjnych i sprawdzania kryteriów:

  • Bezpieczeństwo wątków: żądania można inicjować z dowolnego wątku.
  • Kwalifikacja: przed rozpoczęciem pobierania WebView sprawdza, czy żądanie jest bezpieczne i odpowiednie w kontekście, wykonując te czynności:
    • Istniejące pliki cookie: aby chronić prywatność użytkowników i zapobiegać efektom ubocznym podobnym do CSRF, WebView może pominąć wstępne pobieranie, jeśli żądanie wymaga określonych uwierzytelnionych plików cookie, które mogą spowodować zmianę stanu na serwerze.
    • Obecność skryptu service worker: jeśli skrypt service worker kontroluje już zakres adresu URL, komponent WebView może przekazać obsługę pobierania do skryptu service worker zamiast inicjować standardowe pobieranie z wyprzedzeniem z sieci.
    • Dostępność serwera proxy: komponent WebView sprawdza, czy bieżąca ścieżka sieciowa (w tym skonfigurowane serwery proxy) jest stabilna, aby uniknąć niepowodzeń spekulacyjnych żądań w przypadku złożonych konfiguracji sieci.
  • Jeśli wstępne pobieranie nie rozpocznie się (nawet z prawidłowymi parametrami), często dzieje się tak, ponieważ komponent WebView uznał, że żądanie w tle może zakłócić bieżącą sesję użytkownika lub stan bezpieczeństwa.
  • Anulowanie: użyj parametru CancellationSignal, aby zakończyć trwające żądanie i zapobiec jego zapisaniu w pamięci podręcznej.

Renderowanie wstępne stron

Renderowanie wstępne tworzy ukryte „treści z internetu”, aby w pełni renderować stronę w tle, w tym wykonywać skrypty i pobierać zasoby podrzędne. Wstępne renderowanie korzysta z tej samej infrastruktury co wstępne pobieranie. Jeśli aplikacja zainicjuje wstępne renderowanie, komponent WebView najpierw pobierze wstępnie odpowiedź, aby obsłużyć nawigację wstępnego renderowania, unikając zbędnej aktywności sieciowej.

Implementacja

Wstępne renderowanie to operacja na poziomie instancji WebView. Wywołaj funkcję prerenderUrlAsync() za pomocą funkcji WebViewCompat z wątku UI.

Kotlin

WebViewCompat.prerenderUrlAsync(
    webView,
    url,
    cancellationSignal,
    executor,
    params,
    object : PrerenderOperationCallback {
        override fun onPrerenderActivated() {
            // Called when the user navigates to the URL and the hidden page is swapped in
        }

        override fun onError(exception: Throwable) {
            // exception is an instance of PrerenderException
            // Handle prerender failure (for example, memory pressure or disallowed JavaScript APIs)
        }
    }
)

Java

WebViewCompat.prerenderUrlAsync(webView, url, cancellationSignal, executor, params, new PrerenderOperationCallback() {
    @Override
    public void onPrerenderActivated() {
        // Called when the user navigates to the URL and the hidden page is swapped in.
    }

    @Override
    public void onError(@NonNull Throwable exception) {
        // Handle prerender failure (for example, resource constraints or disallowed APIs).
    }
});

Zarówno pobieranie z wyprzedzeniem, jak i wstępne renderowanie są w pełni asynchroniczne. prefetchUrlAsync() można wywołać z dowolnego wątku, a prerenderUrlAsync() musi zostać zainicjowany z wątku UI.

Ograniczenia techniczne

Aby zachować równowagę między natychmiastową nawigacją a stanem systemu, WebView wymusza te ograniczenia w czasie działania:

  • Obciążenie pamięci: WebView anuluje wstępnie wyrenderowane adresy URL, jeśli urządzenie ma mało pamięci RAM.
  • Niedozwolone interfejsy API: wszelkie próby uzyskania przez JavaScript dostępu do niektórych interfejsów API (np. odtwarzania dźwięku, alertów) w kontekście tła spowodują natychmiastowe zakończenie wstępnego renderowania.
  • Limit instancji: liczba aktywnych wstępnie renderowanych adresów URL dozwolonych w każdym widoku WebView jest ograniczona.

Dopasowywanie adresów URL i dyrektywa No-Vary-Search (NVS)

WebView wymaga niezawodnego algorytmu dopasowywania, aby mieć pewność, że wstępnie wczytany zasób będzie wyświetlany tylko w przypadku zamierzonej nawigacji.

Dopasowanie ścisłe a dopasowanie NVS

Domyślnie wstępne pobieranie i wstępne renderowanie wymagają dokładnego dopasowania adresu URL. Jeśli adres URL, do którego nastąpiło przekierowanie, jest identyczny z wstępnie załadowanym adresem URL, jest on natychmiast obsługiwany z pamięci podręcznej. Jeśli parametry zapytania się różnią, WebView stosuje te reguły No-Vary-Search (NVS):

  • Wskazówka: deweloperzy podają setExpectedNoVarySearchHeader() wskazówkę podczas inicjowania. Jeśli adres URL, do którego nastąpiło przejście, pasuje do adresu URL żądania bez parametrów podpowiedzi, WebView na krótko blokuje działanie, aby poczekać na rzeczywiste nagłówki serwera.
  • Nagłówek serwera: nagłówek odpowiedzi NVS z serwera jest ostatecznym źródłem informacji. Jeśli serwer potwierdzi, że różnice w zapytaniu należy zignorować, dopasowanie zostanie wyświetlone z pamięci podręcznej. W przeciwnym razie WebView przechodzi do zimnego wczytywania sieci.

Dyrektywa No-Vary-Search (NVS) jest przeznaczona do zaawansowanego użytku i większość deweloperów może jej nie potrzebować, ponieważ przekazują ten sam adres URL zarówno do pobierania z wyprzedzeniem, jak i do nawigacji (WebViewCompat.navigate lub loadUrl). Te wskazówki są potrzebne tylko wtedy, gdy występują różnice w parametrach zapytania między adresem URL pobierania z wyprzedzeniem a adresem URL nawigacji.

Konfiguracja globalna

Dostosuj działanie ładowania spekulacyjnego na poziomie profilu, konfigurując PrefetchCachelimity i maksymalną liczbę wstępnych renderowań. Możesz też przywrócić niestandardowe limity wstępnego pobierania do ustawień domyślnych:

Kotlin

// Configure prefetch cache limits
profile.prefetchCache.setMaxPrefetches(10)
profile.prefetchCache.setPrefetchTtlSeconds(60)

// Reset to system defaults when needed
profile.prefetchCache.clearMaxPrefetches()

// Configure maximum active prerenders
profile.setMaxPrerenders(2)

Java

// Configure prefetch cache limits
PrefetchCache prefetchCache = profile.getPrefetchCache();
prefetchCache.setMaxPrefetches(10);
prefetchCache.setPrefetchTtlSeconds(60);

// Reset to system defaults when needed
prefetchCache.clearMaxPrefetches();

// Configure maximum active prerenders
profile.setMaxPrerenders(2);

Obsługa błędów i wyjątków

Operacje spekulacyjne używają symbolu OutcomeReceiverCompat lub PrerenderOperationCallback do raportowania wyników.

Wyjątki podstawowe

Gdy operacja ładowania spekulacyjnego zakończy się niepowodzeniem, moduł obsługi błędów zgłosi jeden z tych głównych typów wyjątków, aby ułatwić Ci diagnozowanie konkretnych scenariuszy niepowodzenia:

  • PrefetchException: klasa bazowa dla wszystkich błędów asynchronicznego pobierania z wyprzedzeniem.
  • PrefetchNetworkException: wskazuje błąd na poziomie sieci lub serwera. Może zawierać pole httpStatusCode (np. 404 lub 503), które pomaga diagnozować problemy po stronie serwera.
  • PrerenderException: klasa nadrzędna wszystkich błędów związanych z wstępnym renderowaniem, np. błędów spowodowanych brakiem pamięci lub użyciem w tle niedozwolonych interfejsów API (takich jak odtwarzanie dźwięku).

Strategie optymalizacji

Aby zmaksymalizować korzyści wynikające z ładowania spekulacyjnego, a jednocześnie oszczędzać zasoby systemu, postępuj zgodnie z tymi zaleceniami:

  • Wcześniejsze inicjowanie: wstępne pobieranie danych należy rozpocząć podczas uruchamiania aplikacji lub gdy tylko pojawi się prawdopodobieństwo, że użytkownik przejdzie do miejsca docelowego nawigacji.
  • Łączenie wskazówek QUIC z wstępnym rozgrzewaniem połączenia: wywołaj addQuicHints() przed rozpoczęciem nawigacji preconnect(), prefetchUrlAsync() lub standardowej, aby mieć pewność, że WebView podejmie próbę nawiązania połączeń za pomocą protokołu HTTP/3.
  • Strategia zintegrowana: jeśli wstępnie renderujesz adres URL, który jest już w pamięci podręcznej wstępnego pobierania, nawigacja wstępnego renderowania jest obsługiwana z tej pamięci podręcznej, co pozwala uniknąć zbędnych żądań sieciowych.
  • Monitoruj limity: wstępne renderowanie jest zasobożerne. W przypadku kilku prawdopodobnych kandydatów preferuj wstępne pobieranie, a wstępne renderowanie rezerwuj dla najbardziej prawdopodobnej nawigacji.
  • Obsługa schematu: upewnij się, że wszystkie adresy URL korzystają z obowiązkowego schematu HTTPS. Nieprawidłowe schematy lub puste dane wejściowe wywołują synchroniczną funkcję IllegalArgumentException.

Dodatkowe materiały

Więcej informacji o debugowaniu aplikacji internetowych, optymalizowaniu wydajności uruchamiania WebView i obsłudze zakończenia procesu renderowania znajdziesz w tych materiałach: