Latensi navigasi adalah metrik penting untuk pengalaman pengguna. Untuk membantu developer mengurangi latensi ini, WebView menyediakan API untuk pemuatan spekulatif dan pengoptimalan koneksi, sehingga memungkinkan aplikasi Anda mengambil atau merender konten sebelum pengguna secara eksplisit membuka konten tersebut.
WebView mendukung tiga jenis pemuatan spekulatif utama: Preconnect, Prefetch, dan Prerender, bersama dengan petunjuk QUIC untuk mengoptimalkan negosiasi protokol.
Dengan menerapkan strategi pemuatan spekulatif, Anda dapat mencapai hal berikut:
- Pengurangan signifikan pada latensi pemuatan konten web: Pindahkan waktu mulai jaringan ke lebih awal dalam siklus proses aplikasi dan pilih protokol yang lebih cepat seperti HTTP/3.
- Tingkat keberhasilan navigasi yang lebih tinggi: Dengan memanaskan jaringan dan cache sebelumnya, navigasi cenderung tidak gagal karena masalah jaringan sementara.
- Respons yang lebih baik: Khususnya, pra-rendering memungkinkan transisi instan yang membuat aplikasi terasa jauh lebih cepat.
Memilih strategi pemuatan spekulatif
Pembeda utama antara strategi ini terletak pada cakupannya: API petunjuk QUIC dan Preconnect berbasis origin, yang berarti hanya memerlukan domain target. API Prefetch dan Prerender berbasis URL, yang berarti API tersebut memerlukan jalur halaman web yang tepat.
Karena petunjuk Preconnect dan QUIC beroperasi di tingkat origin, Anda dapat memulainya lebih awal dalam siklus proses aplikasi, bahkan sebelum Anda mengetahui konten atau halaman tertentu yang akan dibuka pengguna.
Tabel berikut membandingkan ketiga strategi ini untuk membantu Anda memilih strategi yang tepat untuk kasus penggunaan Anda:
| Fitur | Prakoneksi | Prefetch | Pra-render |
|---|---|---|---|
| Sasaran utama | Memanaskan koneksi | Hanya meng-cache HTML (tanpa JavaScript atau CSS) | Melakukan pra-render seluruh halaman |
| Cakupan | Tingkat profil (dibagikan di seluruh WebView) | Tingkat profil (dibagikan di seluruh WebView) | Tingkat WebView (terikat ke WebView tertentu) |
| Jetpack WebKit API | androidx.webkit.Profile |
androidx.webkit.Profile |
androidx.webkit.WebViewCompat |
| Metode API inti | preconnect(...) |
prefetchUrlAsync(...) |
prerenderUrlAsync(...) |
| Konfigurasi | T/A | PrefetchCache.setMaxPrefetches()PrefetchCache.setPrefetchTtlSeconds() |
setMaxPrerenders() |
| Penggunaan resource | Rendah (jaringan) | Sedang (jaringan, memori) | Tinggi (CPU, memori, jaringan) |
| Kapan digunakan | Saat origin target diketahui, tetapi URL spesifik belum ditentukan. | Saat URL persis diketahui dan navigasi mungkin terjadi, dengan berbagi caching di seluruh WebView. | Saat URL persisnya diketahui dan navigasi sangat pasti dalam WebView tertentu. |
| Manfaat | Penyiapan koneksi yang lebih cepat untuk URL apa pun di origin | Pemuatan jaringan yang lebih cepat untuk URL yang cocok | Navigasi yang benar-benar instan saat aktivasi |
Melakukan prakoneksi ke origin
Melakukan pra-koneksi mempercepat pemuatan di masa mendatang dengan melakukan pencarian DNS dan handshake TCP/TLS atau QUIC secara preemptif untuk origin tertentu.
Tidak seperti Pengambilan Data Awal dan Pra-render, yang memerlukan URL tujuan yang persis sama, Preconnect berbasis origin. Dengan demikian, Anda dapat melakukan panggilan Preconnect jauh lebih awal daripada Prefetch dan Prerender.
Strategi tingkat Profil dengan resource rendah ini mengurangi latensi awal untuk berbagi WebView yang menggunakan Profil tersebut, asalkan origin belum dikunjungi. Koneksi tetap terbuka selama sekitar 30 detik, sehingga menguntungkan setiap permintaan HTTP lintas origin, navigasi, atau subresource berikutnya dengan menghilangkan overhead handshake.
Penerapan
Untuk memulai prakoneksi, panggil preconnect(String url) di instance Profile. API ini harus dipanggil di thread UI dan memerlukan dukungan
WebViewFeature.PRECONNECT.
API beroperasi di origin, tetapi untuk mempermudah, URL lengkap dapat diberikan
(seperti https://www.example.com/index.html). URL ini akan otomatis diperlakukan sebagai
panggilan ke origin (misalnya, https://www.example.com). Beberapa origin
dapat dihubungkan dengan memanggil API ini beberapa kali.
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
}
Menunjukkan dukungan protokol QUIC dengan petunjuk QUIC
HTTP/3 (yang berjalan melalui protokol transport QUIC) menawarkan peningkatan latensi yang signifikan dibandingkan HTTP/2, termasuk handshake 0-RTT, peningkatan ketahanan koneksi, dan penghapusan pemblokiran head-of-line selama kehilangan paket.
Secara default, WebView hanya mencoba koneksi QUIC jika memiliki indikasi bahwa
origin mendukung QUIC, seperti dari header Alt-Svc atau catatan HTTPS DNS
dari interaksi sebelumnya. Tanpa pengetahuan sebelumnya ini, WebView menggunakan HTTP/2 atau HTTP/1.1 untuk koneksi awal.
Memanggil addQuicHints akan mengisi otomatis informasi dukungan protokol ini, sehingga
WebView dapat terhubung menggunakan QUIC segera pada koneksi pertama ke
origin yang ditentukan.
Melakukan pra-koneksi dengan petunjuk QUIC
Meskipun petunjuk Preconnect dan QUIC adalah pengoptimalan tingkat origin pada Profile, keduanya memiliki peran yang berbeda dan saling melengkapi:
preconnect: Membuka dan mempertahankan koneksi jaringan secara aktif (pencarian DNS dan handshake TCP/TLS atau QUIC) selama sekitar 30 detik. Karena mempertahankan koneksi jaringan aktif yang terbuka, aplikasi ini menggunakan resource perangkat dan jaringan, sehingga harus dicadangkan untuk asal target dengan probabilitas tinggi.addQuicHints: Tidak menimbulkan traffic jaringan langsung. API ini memperbarui properti server dalam memori stack jaringanProfileuntuk merekam dukungan protokol. Karena memiliki overhead yang dapat diabaikan, Anda dapat mengonfigurasi petunjuk QUIC dengan aman selama startup aplikasi untuk semua origin yang diketahui kompatibel dengan HTTP/3.
Untuk performa optimal, panggil addQuicHints sebelum memanggil preconnect,
prefetchUrlAsync, atau loadUrl. Hal ini memastikan bahwa setiap permintaan halaman atau preconnect berikutnya menegosiasikan HTTP/3 sejak awal.
Penerapan
Untuk mengonfigurasi petunjuk QUIC, panggil addQuicHints(Set<String> urls) pada instance Profile. Anda harus memanggil API ini di UI thread dan memverifikasi bahwa WebView mendukung fitur WebViewFeature.ADD_QUIC_HINTS_V1.
Seperti preconnect, addQuicHints beroperasi di origin, tetapi URL lengkap dapat
diberikan (seperti https://www.example.com/index.html) dan secara otomatis
dinormalisasi ke originnya (https://www.example.com).
Metode ini bersifat aditif: memanggilnya beberapa kali akan menggabungkan origin yang diberikan di seluruh 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
}
Konfigurasi umum: PrefetchParameters dan PrerenderParameters
Prefetch dan Prerender menggunakan PrefetchParameters atau
PrerenderParameters untuk menyesuaikan permintaan. Class ini memungkinkan Anda memberikan
header dan petunjuk tambahan untuk pencocokan URL, seperti konfigurasi 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();
Mengambil konten
Pengambilan data terlebih dahulu mendownload aset HTML utama URL dan menyimpannya di cache jaringan profil. Di WebView, Profile bertindak sebagai penampung untuk data browser, termasuk cookie, cache HTTP, dan pekerja layanan. Karena pengambilan data di awal adalah operasi tingkat profil, setiap WebView yang terkait dengan profil tersebut dapat memanfaatkan respons yang di-cache.
Penerapan
Untuk memulai pengambilan data di awal, panggil prefetchUrlAsync() pada instance Profile. Operasi
ini hanya mendukung skema 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
}
}
}
);
Siklus proses pencegatan
Permintaan pengambilan data di awal WebView mengubah kapan dan bagaimana callback shouldInterceptRequest() dipicu. Karena hal ini berdampak langsung pada keberhasilan penggunaan konten yang telah diambil sebelumnya, Anda harus memahami siklus proses dua langkah berikut:
1. Fase spekulatif (Permintaan pengambilan data di awal)
Saat prefetchUrlAsync() dipanggil, WebView mendownload resource HTML utama di latar belakang. shouldInterceptRequest() dilewati sepenuhnya untuk permintaan
latar belakang ini. Setiap logika kustom, token otorisasi, atau penyisipan header yang biasanya ditangani di dalam interceptor Anda tidak diterapkan ke resource HTML yang telah diambil sebelumnya.
2. Fase navigasi (aktivasi pengguna)
Saat aplikasi secara eksplisit membuka URL (misalnya, menggunakan
WebViewCompat.navigate atau loadUrl) atau pengguna mengklik link yang cocok, WebView menentukan apakah dapat menggunakan cache yang telah di-prefetch:
Evaluasi HTML utama: WebView akan memicu
shouldInterceptRequest()untuk HTML utama pada saat ini. Agar halaman berhasil ditayangkan dari cache pengambilan data awal, pemroses Anda harus menampilkannull. Jika Anda menampilkanWebResourceResponsekustom, WebView akan mematuhi interceptor Anda dan sepenuhnya melewati cache pengambilan data sebelumnya.Evaluasi sub-resource: Setelah HTML yang telah di-prefetch siap digunakan,
shouldInterceptRequest()biasanya dipicu untuk semua sub-resource berikutnya (seperti gambar, skrip, dan CSS) yang diperlukan untuk menyelesaikan rendering halaman.
Perilaku utama
Karakteristik operasional dan pemeriksaan kelayakan berikut mengatur cara WebView memulai dan mengelola permintaan pengambilan data terlebih dahulu:
- Keamanan thread: Permintaan dapat dimulai dari thread mana pun.
- Kelayakan: Sebelum memulai pengambilan, WebView memastikan permintaan aman dan sesuai secara kontekstual dengan memeriksa hal berikut:
- Cookie yang ada: Untuk melindungi privasi pengguna dan mencegah efek samping seperti CSRF, WebView mungkin melewati pengambilan data sebelumnya jika permintaan memerlukan cookie yang diautentikasi tertentu yang dapat memicu perubahan status di server.
- Kehadiran pekerja layanan: Jika Service Worker sudah mengontrol cakupan URL, WebView dapat menunda ke handler pengambilan data Service Worker daripada memulai pengambilan data jaringan standar.
- Ketersediaan proxy: WebView memverifikasi bahwa jalur jaringan saat ini (termasuk proxy yang dikonfigurasi) stabil untuk menghindari kegagalan permintaan spekulatif dalam konfigurasi jaringan yang kompleks.
- Jika pengambilan data di awal gagal dimulai (bahkan dengan parameter yang valid), hal ini sering kali disebabkan karena WebView telah menentukan bahwa permintaan latar belakang dapat mengganggu sesi pengguna saat ini atau status keamanan.
- Pembatalan: Gunakan
CancellationSignaluntuk menghentikan permintaan yang sedang berlangsung dan mencegahnya di-cache.
Melakukan pra-rendering halaman
Pra-rendering membuat "konten web" tersembunyi untuk merender halaman sepenuhnya di latar belakang, termasuk eksekusi skrip dan pengambilan subresource. Pra-rendering mengandalkan infrastruktur pokok yang sama dengan pengambilan data terlebih dahulu. Jika aplikasi memulai pra-render, WebView akan melakukan pengambilan data respons terlebih dahulu untuk menayangkan navigasi pra-render, sehingga menghindari aktivitas jaringan yang berlebihan.
Penerapan
Pra-rendering adalah operasi tingkat instance WebView. Panggil prerenderUrlAsync()
menggunakan WebViewCompat dari UI thread.
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).
}
});
Prefetch dan pra-render sepenuhnya bersifat asinkron. prefetchUrlAsync() dapat dipanggil dari thread mana pun, sementara prerenderUrlAsync() harus dimulai dari UI thread.
Batasan teknis
Untuk menyeimbangkan navigasi instan dengan kesehatan sistem, WebView menerapkan batasan runtime berikut:
- Tekanan memori: WebView membatalkan URL yang telah di-pra-render jika perangkat memiliki RAM rendah.
- API yang tidak diizinkan: Setiap upaya oleh JavaScript untuk mengakses API tertentu (misalnya, pemutaran audio, pemberitahuan) dalam konteks latar belakang akan segera menghentikan pra-render.
- Batas instance: Ada batas jumlah URL yang telah di-prerender dan aktif yang diizinkan per WebView.
Pencocokan URL dan No-Vary-Search (NVS)
WebView memerlukan algoritma pencocokan yang andal untuk memastikan resource yang dimuat sebelumnya hanya ditayangkan untuk navigasi yang dimaksud.
Pencocokan persis versus pencocokan NVS
Secara default, pengambilan data di awal dan pra-render memerlukan kecocokan URL yang persis. Jika URL yang dibuka identik dengan URL yang telah dimuat sebelumnya, URL tersebut akan segera disajikan dari cache. Jika parameter kueri berbeda, WebView menggunakan aturan No-Vary-Search (NVS) berikut:
- Petunjuk: Developer memberikan petunjuk
setExpectedNoVarySearchHeader()selama inisiasi. Jika URL yang dibuka cocok dengan URL permintaan dikurangi parameter yang disarankan, WebView akan memblokir sebentar untuk menunggu header aktual server. - Header server: Header respons NVS dari server adalah otoritas terakhir. Jika server mengonfirmasi bahwa perbedaan kueri harus diabaikan, kecocokan akan ditayangkan dari cache. Jika tidak, WebView akan kembali ke pemuatan jaringan dingin.
No-Vary-Search (NVS) ditujukan untuk penggunaan lanjutan, dan sebagian besar developer mungkin tidak memerlukannya karena mereka meneruskan URL yang sama persis ke pengambilan data di awal dan navigasi (WebViewCompat.navigate atau loadUrl). Panduan ini hanya diperlukan jika ada perbedaan dalam parameter kueri antara URL pengambilan data di awal dan URL yang dinavigasi.
Konfigurasi global
Sesuaikan perilaku pemuatan spekulatif di tingkat profil dengan mengonfigurasi
batas PrefetchCache dan pra-render maksimum. Anda juga dapat mereset batas pengambilan data di awal kustom kembali ke default sistem:
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);
Penanganan error dan pengecualian
Operasi spekulatif menggunakan OutcomeReceiverCompat atau
PrerenderOperationCallback untuk melaporkan hasil.
Pengecualian utama
Jika operasi pemuatan spekulatif gagal, pengendali error Anda akan melaporkan salah satu jenis pengecualian utama berikut untuk membantu Anda mendiagnosis skenario kegagalan tertentu:
PrefetchException: Class dasar untuk semua error pengambilan data di awal secara asinkron.PrefetchNetworkException: Menunjukkan kegagalan tingkat jaringan atau server. Respons ini dapat menyertakan kolomhttpStatusCode(seperti, 404 atau 503) untuk membantu mendiagnosis masalah sisi server.PrerenderException: Superclass untuk semua error terkait pra-render, seperti kegagalan karena tekanan memori atau penggunaan API yang tidak diizinkan (seperti pemutaran audio) di latar belakang.
Strategi pengoptimalan
Ikuti rekomendasi berikut untuk memaksimalkan manfaat pemuatan spekulatif sekaligus menghemat resource sistem:
- Mulai lebih awal: Mulai pengambilan data lebih awal selama startup aplikasi atau segera setelah tujuan navigasi diperkirakan.
- Pasangkan petunjuk QUIC dengan pemanasan awal koneksi: Panggil
addQuicHints()sebelum memulaipreconnect(),prefetchUrlAsync(), atau navigasi standar untuk memastikan WebView mencoba membuat koneksi menggunakan HTTP/3. - Strategi terintegrasi: Jika Anda melakukan pra-render URL yang sudah ada di cache pengambilan data di awal, navigasi pra-render akan ditayangkan dari cache tersebut, sehingga tidak ada permintaan jaringan yang berlebihan.
- Pantau kuota: Pra-rendering memerlukan banyak resource. Lebih memilih pengambilan data terlebih dahulu untuk beberapa kandidat yang mungkin dan mencadangkan pra-rendering untuk navigasi yang paling mungkin.
- Dukungan skema: Pastikan semua URL menggunakan skema HTTPS wajib. Skema
yang tidak valid atau input null memicu
IllegalArgumentExceptionsinkron.
Referensi lainnya
Untuk mempelajari lebih lanjut cara men-debug aplikasi web, mengoptimalkan performa peluncuran WebView, dan menangani penghentian proses perender, lihat referensi berikut:
- Navigasi halaman yang ditingkatkan dengan metode
WebViewCompat.navigate - Men-debug aplikasi web
- Mengoptimalkan startup WebView
- Menangani penghentian proses perender WebView