導覽延遲是評估使用者體驗的重要指標。為協助開發人員縮短延遲時間,WebView 提供推測載入的 API,讓應用程式在使用者明確瀏覽內容前,就能擷取或算繪內容。
WebView 支援三種主要推測載入類型:預先連線、預先擷取和預先算繪。
實作推測載入策略可達成下列目標:
- 大幅縮短網頁內容載入延遲時間:將網路啟動時間移至應用程式生命週期的較早階段。
- 提高瀏覽成功率:預先暖機網路和快取,可減少因暫時性網路問題導致瀏覽失敗的機率。
- 提升回應速度:預先算繪功能可實現即時轉換,讓應用程式速度大幅提升。
選擇推測載入策略
這兩種策略的主要差異在於範圍:preconnect API 是以來源為準,因此只需要目標網域。預先擷取和預先算繪 API 是以網址為準,因此需要確切的網頁路徑。
由於預先連線是在來源層級運作,因此可以在應用程式生命週期中更早啟動,甚至在您知道使用者將前往的特定內容或頁面之前啟動。
下表比較這三種策略,協助您為自己的用途選擇合適的策略:
| 功能 | 預先連線 | 預先擷取 | 預先算繪 |
|---|---|---|---|
| 主要目標 | 暖身 | 僅快取 HTML (不含 JavaScript 或 CSS) | 預先算繪整個頁面 |
| 範圍 | 設定檔層級 (在 WebView 之間共用) | 設定檔層級 (在 WebView 之間共用) | WebView 層級 (繫結至特定 WebView) |
| Jetpack WebKit API | androidx.webkit.Profile |
androidx.webkit.Profile |
androidx.webkit.WebViewCompat |
| 核心 API 方法 | preconnect(...) |
prefetchUrlAsync(...) |
prerenderUrlAsync(...) |
| 設定 | 不適用 | PrefetchCache.setMaxPrefetches()PrefetchCache.setPrefetchTtlSeconds() |
setMaxPrerenders() |
| 資源使用情況 | 低 (網路) | 中 (網路、記憶體) | 高 (CPU、記憶體、網路) |
| 使用時機 | 目標來源已知,但尚未確定特定網址。 | 當確切網址已知且可能進行導覽時,系統會跨 WebView 共用快取。 | 確切網址已知,且特定 WebView 內導覽高度確定時。 |
| 福利 | 為來源上的任何網址加快連線設定速度 | 加快相符網址的網路載入速度 | 啟用後即可立即導航 |
預先連結至來源
預先連線會預先執行指定來源的 DNS 查詢和 TCP/TLS 握手程序,加快日後的載入速度。
與需要確切到達網址的預先擷取和預先算繪不同,預先連線嚴格來說是以來源為準。因此,您可以在比預先擷取和預先算繪更早的時間點發出 Preconnect 呼叫。
這項低資源的設定檔層級策略可減少任何設定檔的 WebView 分享初始延遲時間,前提是尚未造訪來源。連線會保持開啟約 30 秒,藉此消除交握作業負擔,讓後續的跨來源 HTTP 要求、導覽或子資源受益。
導入作業
如要啟動預先連線,請在 Profile 例項上呼叫 preconnect(String url)。這個 API 必須在 UI 執行緒上呼叫,且需要支援 WebViewFeature.PRECONNECT。
API 會在來源上運作,但為方便起見,您可以提供完整網址 (例如 https://www.example.com/index.html)。系統會自動將這視為對來源的呼叫 (例如 https://www.example.com)。您可以多次呼叫這個 API,連結多個來源。
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
}
常見設定:PrefetchParameters 和 PrerenderParameters
預先擷取和預先算繪都會使用 PrefetchParameters 或 PrerenderParameters 自訂要求。這些類別可讓您提供網址比對的其他標頭和提示,例如 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();
預先擷取內容
預先擷取會下載網址的主要 HTML 資源,並儲存在設定檔的網路快取中。在 WebView 中,Profile 會做為瀏覽器資料的容器,包括 Cookie、HTTP 快取和 Service Worker。由於預先擷取是設定檔層級的作業,因此與該設定檔相關聯的任何 WebView 都可以運用快取回應。
導入作業
如要啟動預先擷取,請在 Profile 例項上呼叫 prefetchUrlAsync()。這項作業僅支援 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
}
}
}
);
攔截生命週期
WebView 預先擷取要求會改變 shouldInterceptRequest() 回呼的觸發時間和方式。這會直接影響預先擷取的內容是否能順利使用,因此請務必瞭解兩階段生命週期:
1. 推測階段 (預先擷取要求)
系統叫用 prefetchUrlAsync() 時,WebView 會在背景下載主要 HTML 資源。系統會完全略過這項背景要求的 shouldInterceptRequest()。通常在攔截器內處理的任何自訂邏輯、授權權杖或標頭插入作業,都不會套用至預先擷取的 HTML 資源。
2. 導覽階段 (使用者啟用)
當應用程式明確導覽至網址 (例如使用 loadUrl()) 或使用者點選相符連結時,WebView 會判斷是否可以使用預先擷取的快取:
主要 HTML 評估:WebView 會在此時觸發主要 HTML 的
shouldInterceptRequest()。如要從預先擷取快取成功提供網頁,攔截器必須傳回null。如果您傳回自訂WebResourceResponse,WebView 會遵守攔截器,並完全略過預先擷取快取。子資源評估:預先擷取的 HTML 獲得使用權後,
shouldInterceptRequest()會正常觸發,以取得完成網頁算繪所需的所有後續子資源 (例如圖片、指令碼和 CSS)。
主要行為
下列運作特性和資格檢查會控管 WebView 發起及管理預先擷取要求的方式:
- 執行緒安全:要求可從任何執行緒啟動。
- 資格條件:WebView 會先檢查下列項目,確保要求安全無虞且符合情境,再啟動擷取作業:
- 現有 Cookie:為保護使用者隱私權及避免類似 CSRF 的副作用,如果要求需要特定的已驗證 Cookie,可能會在伺服器上觸發狀態變更,WebView 就可能會略過預先擷取。
- Service Worker 是否存在:如果 Service Worker 已控管網址範圍,WebView 可以延後處理,改為使用 Service Worker 的擷取處理常式,而非啟動標準網路預先擷取。
- Proxy 可用性:WebView 會驗證目前的網路路徑 (包括任何已設定的 Proxy) 是否穩定,避免在複雜的網路設定下,推測性要求失敗。
- 如果預先擷取作業無法啟動 (即使參數有效),通常是因為 WebView 判斷背景要求可能會干擾使用者目前的工作階段或安全狀態。
- 取消:使用
CancellationSignal終止進行中的要求,並防止要求遭到快取。
預先算繪網頁
預先轉譯會建立隱藏的「網頁內容」,在背景完整轉譯網頁,包括執行指令碼和擷取子資源。預先算繪與預先擷取採用相同的底層基礎架構。如果應用程式啟動預先算繪,WebView 會先預先擷取回應,以提供預先算繪的導覽功能,避免多餘的網路活動。
導入作業
預先算繪是 WebView 執行個體層級的作業。從 UI 執行緒使用 WebViewCompat 呼叫 prerenderUrlAsync()。
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).
}
});
預先擷取和預先算繪都是完全非同步的作業。prefetchUrlAsync() 可從任何執行緒呼叫,但 prerenderUrlAsync() 必須從 UI 執行緒啟動。
技術限制
為兼顧即時導覽和系統健康狀態,WebView 會強制執行下列執行階段限制:
- 記憶體壓力:如果裝置的 RAM 不足,WebView 會取消預先算繪的網址。
- 不允許的 API:如果 JavaScript 嘗試在背景環境中存取特定 API (例如音訊播放、快訊),系統會立即終止預先算繪。
- 執行個體限制:每個 WebView 允許的有效預先算繪網址數量有限。
網址比對和 No-Vary-Search (NVS)
WebView 需要可靠的相符演算法,確保預先載入的資源只會用於預期的導覽。
完全比對與 NVS 比對
根據預設,預先擷取和預先算繪功能必須完全比對網址。如果導向的網址與預先載入的網址相同,系統會立即從快取提供該網址。如果查詢參數不同,WebView 會使用下列「不因搜尋而異」(NVS) 規則:
- 提示:開發人員會在啟動期間提供
setExpectedNoVarySearchHeader()提示。如果導覽的網址與要求網址 (扣除提示參數) 相符,WebView 會短暫封鎖,等待伺服器的實際標頭。 - 伺服器標頭:伺服器傳回的 NVS 回應標頭是最終的授權單位。如果伺服器確認應忽略查詢差異,系統會從快取提供相符項目。如果沒有,WebView 會改用冷網路載入。
No-Vary-Search (NVS) 適用於進階用途,大多數開發人員可能不需要這項功能,因為他們會將完全相同的網址傳遞至預先擷取和 loadUrl()。如果預先擷取網址和 loadUrl() 網址的查詢參數不同,才需要遵循這項指引。
全域設定
在設定檔層級調整推測載入行為,方法是設定PrefetchCache限制和預先算繪上限。你也可以將自訂預先擷取限制重設為系統預設值:
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);
錯誤處理和例外狀況
推測作業會使用 OutcomeReceiverCompat 或 PrerenderOperationCallback 回報結果。
主要例外狀況
如果推測載入作業失敗,錯誤處理常式會回報下列其中一種主要例外狀況類型,協助您診斷特定失敗情境:
PrefetchException:所有非同步預先擷取錯誤的基礎類別。PrefetchNetworkException:表示網路或伺服器層級發生故障。其中可能包含httpStatusCode欄位 (例如 404 或 503),有助於診斷伺服器端問題。PrerenderException:所有預先算繪相關錯誤的超類別,例如因記憶體壓力或在背景使用不允許的 API (如音訊播放) 而導致的失敗。
最佳化策略
請遵循下列建議,盡量發揮預測載入的優點,同時節省系統資源:
- 提早啟動:在應用程式啟動期間或可能前往導覽目的地時,立即開始預先擷取。
- 整合策略:如果您預先算繪預先擷取快取中已有的網址,系統會從該快取提供預先算繪的導覽,避免多餘的網路要求。
- 監控配額:預先算繪會耗用大量資源。建議為幾個可能的候選項目預先擷取,並為最有可能的導覽保留預先算繪。
- 支援的通訊協定:請確認所有網址都使用強制性 HTTPS 通訊協定。無效的配置或空值輸入會觸發同步
IllegalArgumentException。
其他資源
如要進一步瞭解如何對網頁應用程式偵錯、最佳化 WebView 啟動效能,以及處理轉譯器程序終止問題,請參閱下列資源: