탐색 지연 시간은 사용자 환경에 중요한 측정항목입니다. 개발자가 이 지연 시간을 줄일 수 있도록 WebView는 추측 로드를 위한 API를 제공하여 사용자가 명시적으로 콘텐츠로 이동하기 전에 앱이 콘텐츠를 가져오거나 렌더링할 수 있습니다.
WebView는 Preconnect, Prefetch, Prerender의 세 가지 기본 유형의 추측 로드를 지원합니다.
추측 로드 전략을 구현하면 다음을 달성할 수 있습니다.
- 웹 콘텐츠 로드 지연 시간 대폭 감소: 네트워크 시작 시간을 앱 수명 주기 초기로 이동합니다.
- 탐색 성공률 향상: 네트워크와 캐시를 미리 워밍하면 일시적인 네트워크 문제로 인해 탐색이 실패할 가능성이 줄어듭니다.
- 더 나은 인식된 응답성: 특히 사전 렌더링을 사용하면 앱이 훨씬 더 빠르게 느껴지는 즉각적인 전환이 가능합니다.
추측 로드 전략 선택
이러한 전략의 주요 차이점은 범위에 있습니다. 사전 연결 API는 출처 기반이므로 타겟 도메인만 필요합니다. 프리패치 및 사전 렌더링 API는 URL 기반이므로 정확한 웹페이지 경로가 필요합니다.
사전 연결은 출처 수준에서 작동하므로 사용자가 이동할 특정 콘텐츠나 페이지를 알기 전에도 앱 수명 주기에서 훨씬 일찍 시작할 수 있습니다.
다음 표에서는 이러한 세 가지 전략을 비교하여 사용 사례에 적합한 전략을 선택할 수 있도록 지원합니다.
| 기능 | 사전 연결 | 프리페치 | 사전 렌더링 |
|---|---|---|---|
| 기본 목표 | 연결 워밍업 | 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, 메모리, 네트워크) |
| 사용하는 경우 | 타겟 출처는 알려져 있지만 구체적인 URL은 아직 결정되지 않은 경우 | 정확한 URL을 알고 탐색이 가능하며 캐싱이 WebView 간에 공유되는 경우 | 정확한 URL을 알고 특정 WebView 내에서 탐색이 확실한 경우 |
| 이점 | 출처의 모든 URL에 대한 더 빠른 연결 설정 | 일치하는 URL의 네트워크 로드 속도 향상 | 활성화 시 진정한 즉시 탐색 |
출처에 미리 연결
사전 연결은 지정된 출처에 대해 DNS 조회 및 TCP/TLS 핸드셰이크를 선제적으로 실행하여 향후 로드를 가속화합니다.
정확한 대상 URL이 필요한 미리 가져오기 및 사전 렌더링과 달리 사전 연결은 엄격하게 출처 기반입니다. 이를 통해 Prefetch 및 Prerender보다 훨씬 일찍 Preconnect 호출을 할 수 있습니다.
이 리소스가 적은 프로필 수준 전략은 출처를 아직 방문하지 않은 경우 해당 프로필을 공유하는 모든 WebView의 초기 지연 시간을 줄입니다. 연결은 약 30초 동안 열려 있으므로 핸드셰이크 오버헤드를 없애 후속 교차 출처 HTTP 요청, 탐색 또는 하위 리소스에 도움이 됩니다.
구현
사전 연결을 시작하려면 Profile 인스턴스에서 preconnect(String url)를 호출합니다. 이 API는 UI 스레드에서 호출해야 하며 WebViewFeature.PRECONNECT가 지원되어야 합니다.
API는 출처에서 작동하지만 편의를 위해 전체 URL(예: 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
}
자바
// 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 구성과 같은 URL 일치를 위한 추가 헤더와 힌트를 제공할 수 있습니다.
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()
자바
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();
콘텐츠 미리 가져오기
프리패치는 URL의 기본 HTML 리소스를 다운로드하여 프로필의 네트워크 캐시에 저장합니다. WebView에서 Profile는 쿠키, HTTP 캐시, 서비스 워커 등 브라우저 데이터의 컨테이너 역할을 합니다. 프리패치는 프로필 수준 작업이므로 해당 프로필과 연결된 모든 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
}
}
}
}
)
자바
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() 콜백이 트리거되는 시점과 방식을 변경합니다. 이는 미리 가져온 콘텐츠가 성공적으로 사용되는지 여부에 직접적인 영향을 미치므로 다음의 2단계 수명 주기를 이해하는 것이 중요합니다.

1. 추측 단계 (미리 가져오기 요청)
prefetchUrlAsync()가 호출되면 WebView는 백그라운드에서 기본 HTML 리소스를 다운로드합니다. 이 백그라운드 요청에서는 shouldInterceptRequest()가 완전히 건너뜁니다. 인터셉터 내에서 일반적으로 처리되는 맞춤 로직, 승인 토큰 또는 헤더 삽입은 미리 가져온 HTML 리소스에 적용되지 않습니다.
2. 탐색 단계 (사용자 활성화)
앱이 명시적으로 URL로 이동하거나 (예: loadUrl() 사용) 사용자가 일치하는 링크를 클릭하면 WebView는 미리 가져온 캐시를 사용할 수 있는지 확인합니다.
기본 HTML 평가: 이 시점에서 WebView는 기본 HTML에 대해
shouldInterceptRequest()를 트리거합니다. 프리패치 캐시에서 페이지를 성공적으로 제공하려면 인터셉터가null를 반환해야 합니다. 맞춤WebResourceResponse를 반환하면 WebView가 인터셉터를 존중하고 프리패치 캐시를 완전히 우회합니다.하위 리소스 평가: 미리 가져온 HTML을 사용할 수 있게 되면 페이지 렌더링을 완료하는 데 필요한 모든 후속 하위 리소스(예: 이미지, 스크립트, CSS)에 대해
shouldInterceptRequest()가 정상적으로 트리거됩니다.
주요 행동
다음 작동 특성 및 자격 요건 확인은 WebView가 프리패치 요청을 시작하고 관리하는 방식을 관리합니다.
- 스레드 안전: 요청은 모든 스레드에서 시작할 수 있습니다.
- 자격 요건: 가져오기를 시작하기 전에 WebView는 다음을 확인하여 요청이 안전하고 컨텍스트에 적합한지 확인합니다.
- 기존 쿠키: 사용자 개인 정보를 보호하고 CSRF와 유사한 부작용을 방지하기 위해 요청에 서버에서 상태 변경을 트리거할 수 있는 특정 인증된 쿠키가 필요한 경우 WebView는 미리 가져오기를 건너뛸 수 있습니다.
- 서비스 워커 존재: 서비스 워커가 이미 URL 범위를 제어하고 있는 경우 WebView는 표준 네트워크 미리 가져오기를 시작하는 대신 서비스 워커의 가져오기 핸들러를 따를 수 있습니다.
- 프록시 가용성: WebView는 복잡한 네트워크 구성에서 추측 요청이 실패하지 않도록 현재 네트워크 경로(구성된 프록시 포함)가 안정적인지 확인합니다.
- 유효한 매개변수가 있어도 프리패치가 시작되지 않는 경우 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)
}
}
)
자바
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가 사전 렌더링된 URL을 취소합니다.
- 허용되지 않는 API: JavaScript가 백그라운드 컨텍스트에서 특정 API (예: 오디오 재생, 알림)에 액세스하려고 하면 사전 렌더링이 즉시 종료됩니다.
- 인스턴스 제한: WebView당 허용되는 활성 사전 렌더링 URL의 수가 제한되어 있습니다.
URL 일치 및 No-Vary-Search (NVS)
WebView에는 미리 로드된 리소스가 의도된 탐색에만 제공되도록 안정적인 일치 알고리즘이 필요합니다.
일치검색과 NVS 일치
기본적으로 사전 가져오기 및 사전 렌더링에는 정확한 URL 일치가 필요합니다. 탐색된 URL이 미리 로드된 URL과 동일한 경우 캐시에서 즉시 제공됩니다. 쿼리 매개변수가 다른 경우 WebView는 다음 No-Vary-Search (NVS) 규칙을 사용합니다.
- 힌트: 개발자는 초기화 중에
setExpectedNoVarySearchHeader()힌트를 제공합니다. 탐색된 URL이 힌트가 지정된 매개변수를 제외한 요청 URL과 일치하면 WebView는 서버의 실제 헤더를 기다리기 위해 잠시 차단됩니다. - 서버 헤더: 서버의 NVS 응답 헤더가 최종 권한입니다. 서버에서 쿼리 차이를 무시해야 한다고 확인하면 캐시에서 일치 항목이 제공됩니다. 그렇지 않으면 WebView가 콜드 네트워크 로드로 대체됩니다.
No-Vary-Search (NVS)는 고급 사용을 위한 것이며, 대부분의 개발자는 미리 가져오기와 loadUrl()에 정확히 동일한 URL을 전달하므로 필요하지 않을 수 있습니다. 이 안내는 프리패치 URL과 loadUrl() URL 간에 쿼리 매개변수에 차이가 있는 경우에만 필요합니다.
전역 구성
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)
자바
// 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 (예: 오디오 재생) 사용으로 인한 실패와 같은 모든 사전 렌더링 관련 오류의 상위 클래스입니다.
최적화 전략
시스템 리소스를 절약하면서 추측 로딩의 이점을 극대화하려면 다음 권장사항을 따르세요.
- 일찍 시작: 앱 시작 중에 또는 탐색 대상이 예상되는 즉시 미리 가져오기를 시작합니다.
- 통합 전략: 미리 가져오기 캐시에 이미 있는 URL을 사전 렌더링하면 사전 렌더링 탐색이 해당 캐시에서 제공되어 중복 네트워크 요청을 방지합니다.
- 할당량 모니터링: 사전 렌더링은 리소스를 많이 사용합니다. 가능성이 높은 후보 여러 개에 대해 미리 가져오기를 선호하고 가능성이 가장 높은 탐색 하나에 대해 사전 렌더링을 예약합니다.
- 스키마 지원: 모든 URL이 필수 HTTPS 스키마를 사용하는지 확인합니다. 잘못된 스키마 또는 null 입력은 동기식
IllegalArgumentException를 트리거합니다.
추가 리소스
웹 앱 디버깅, WebView 시작 성능 최적화, 렌더러 프로세스 종료 처리에 관해 자세히 알아보려면 다음 리소스를 참고하세요.