Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

Android 4.4에서 WebView로 이전

Android 4.4(API 수준 19)에는 Chromium에 기반한 새 버전의 WebView가 도입되었습니다. 이 변경으로 인해 HTML5, CSS3 및 자바스크립트에 관한 WebView 성능 및 표준 지원이 최신 웹브라우저에 맞게 업그레이드되었습니다. WebView를 사용하는 앱은 Android 4.4 이상에서 실행될 경우 이러한 업그레이드를 상속합니다.

이 문서에서는 targetSdkVersion을 '19' 이상으로 설정할 때 알아야 하는 WebView의 추가 변경사항을 설명합니다.

참고: targetSdkVersion이 '18' 이하로 설정된 경우 WebView는 앱의 성능과 웹 표준을 업그레이드하면서도 아래에 설명된 동작 변경을 최대한 주의하여 피하고자 '쿼크 모드'에서 작동합니다. 그러나 단일 및 좁은 열 레이아웃기본 확대/축소 수준은 Android 4.4에서 전혀 지원되지 않으며 확인되지 않은 동작 차이가 있을 수 있습니다. 따라서 targetSdkVersion을 '18' 이하로 계속 설정할 경우 앱을 Android 4.4 이상에서 테스트해야 합니다.

앱을 Android 4.4의 WebView로 이전할 때 발생할 수 있는 문제를 쉽게 해결하려면 setWebContentsDebuggingEnabled()를 호출하여 데스크톱에서 Chrome을 통해 원격 디버깅을 사용 설정하면 됩니다. WebView의 이 새 기능을 사용하면 WebView에서 실행되는 동안 웹 콘텐츠, 스크립트 및 네트워크 활동을 검사하고 분석할 수 있습니다. 자세한 내용은 Android에서의 원격 디버깅을 참조하세요.

사용자 에이전트 변경

사용자 에이전트를 기반으로 WebView에 콘텐츠를 제공하는 경우 사용자 에이전트 문자열이 약간 변경되었으며 현재 다음 Chrome 버전을 포함하고 있음을 알아 두어야 합니다.

    Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36
    (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
    

사용자 에이전트를 가져오긴 해야 하지만 앱에 저장할 필요가 없거나 WebView를 인스턴스화하고 싶지 않은 경우 정적 메서드 getDefaultUserAgent()를 사용해야 합니다. 그러나 WebView에서 사용자 에이전트 문자열을 재정의하려는 경우에는 대신 getUserAgentString()을 사용할 수 있습니다.

멀티스레딩 및 스레드 차단

앱의 UI 스레드가 아닌 다른 스레드에서 WebView에 메서드를 호출하는 경우 예기치 않은 결과가 발생할 수 있습니다. 예를 들어 앱에 스레드가 여러 개 사용되는 경우 코드를 UI 스레드에서 빠짐없이 실행하려면 runOnUiThread() 메서드를 사용하면 됩니다.

Kotlin

    runOnUiThread {
        // Code for WebView goes here
    }
    

자바

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // Code for WebView goes here
        }
    });
    

또한 UI 스레드를 차단해서는 안 됩니다. 일부 앱은 자바스크립트 콜백을 기다리는 동안 UI 스레드를 차단하는 실수를 하는 경우가 있습니다. 예를 들어 다음과 같은 코드를 사용하지 않도록 합니다.

Kotlin

    // This code is BAD and will block the UI thread
    webView.loadUrl("javascript:fn()")
    while (result == null) {
        Thread.sleep(100)
    }
    

자바

    // This code is BAD and will block the UI thread
    webView.loadUrl("javascript:fn()");
    while(result == null) {
      Thread.sleep(100);
    }
    

대신 새 메서드 evaluateJavascript()를 사용하여 자바스크립트를 비동기적으로 실행할 수 있습니다.

맞춤 URL 처리

WebView는 맞춤 URL 스키마를 사용하는 링크를 확인하고 리소스를 요청할 때 추가 제한사항을 적용합니다. 예를 들어 shouldOverrideUrlLoading() 또는 shouldInterceptRequest() 같은 콜백을 구현 중이라면 WebView는 유효한 URL인 경우에만 이러한 콜백을 호출합니다.

맞춤 URL 스키마 또는 기본 URL을 사용할 때 Android 4.4에서 앱이 콜백 호출을 이전보다 적게 수신하거나 리소스를 로드하지 못하는 경우 요청 시 지정되는 URL이 RFC 3986을 준수하는 유효한 URL인지 확인합니다.

예를 들어 다음과 같은 링크의 경우 새 WebViewshouldOverrideUrlLoading() 메서드를 호출할 수 없습니다.

<a href="showProfile">Show Profile</a>

사용자가 이러한 링크를 클릭했을 때의 결과는 다음과 같이 다양할 수 있습니다.

  • 무효한 또는 null 형태의 기본 URL이 포함된 loadData() 또는 loadDataWithBaseURL()을 호출하여 페이지를 로드하면 페이지에는 이 유형의 링크와 관련한 shouldOverrideUrlLoading() 콜백이 수신되지 않습니다

    참고: loadDataWithBaseURL()을 사용할 때 기본 URL이 무효하거나 null로 설정된 경우 로드하는 콘텐츠의 모든 링크가 절대 링크여야 합니다.

  • loadUrl()을 호출하여 페이지를 로드하거나 loadDataWithBaseURL()에 유효한 기본 URL을 제공하면 페이지에는 이 유형의 링크와 관련된 shouldOverrideUrlLoading() 콜백이 수신됩니다. 하지만 수신되는 URL은 현재 페이지를 기준으로 한 절대 URL입니다. 예를 들어 "showProfile"이 아닌 "http://www.example.com/showProfile"의 URL이 수신됩니다.

위와 같이 링크에 간단한 문자열을 사용하는 대신 다음과 같은 맞춤 스키마를 사용할 수 있습니다.

<a href="example-app:showProfile">Show Profile</a>

이 경우 다음과 같이 shouldOverrideUrlLoading() 메서드로 이 URL을 처리할 수 있습니다.

Kotlin

    // The URL scheme should be non-hierarchical (no trailing slashes)
    const val APP_SCHEME = "example-app:"

    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        return if (url?.startsWith(APP_SCHEME) == true) {
            urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8")
            respondToData(urlData)
            true
        } else {
            false
        }
    }
    

자바

    // The URL scheme should be non-hierarchical (no trailing slashes)
    private static final String APP_SCHEME = "example-app:";

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith(APP_SCHEME)) {
            urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
            respondToData(urlData);
            return true;
        }
        return false;
    }
    

HTML을 변경할 수 없는 경우 loadDataWithBaseURL()을 사용하고 "example-app://<valid_host_name>/" 같은 유효한 호스트와 맞춤 스키마로 구성된 기본 URL을 설정할 수 있습니다. 예:

Kotlin

    webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA, null, "UTF-8", null)
    

자바

    webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA,
            null, "UTF-8", null);
    

유효한 호스트 이름은 RFC 3986을 준수해야 하고 끝에 후행 슬래시를 넣어야 합니다. 그러지 않으면 로드된 페이지에서 모든 요청이 삭제될 수 있습니다.

표시 영역 변경

이제 표시 영역 target-densitydpi는 지원되지 않음

이전에는 웹페이지에 의도된 화면 밀도가 정확하게 지정되도록 WebViewtarget-densitydpi라는 표시 영역 속성을 지원했습니다. 이 속성은 더 이상 지원되지 않습니다. 따라서 WebView의 Pixel-Perfect UI에 설명된 대로 이미지 및 CSS가 포함된 표준 솔루션을 사용하는 방법을 택해야 합니다.

크기가 작을 경우 표시 영역이 확대됨

이전에는 표시 영역 너비의 경우 '320' 이하의 값으로 설정되면 '기기 너비'로 설정되고, 표시 영역 높이의 경우 WebView 높이보다 작거나 같은 값으로 설정되면 '기기 높이'로 설정되었습니다. 그러나 새 WebView에서 실행하면 너비 또는 높이 값이 준수되어 WebView는 화면 너비를 채우도록 확대됩니다.

다중 표시 영역 태그는 지원되지 않음

이전에는 웹페이지에 여러 개의 표시 영역 태그가 포함되어 있으면 WebView는 모든 태그의 속성을 병합했습니다. 새 WebView에서는 마지막 표시 영역만 사용되고 다른 모든 표시 영역은 무시됩니다.

기본 확대/축소가 지원 중단됨

페이지에 초기 확대/축소 수준을 가져오고 설정하기 위한 메서드 getDefaultZoom()setDefaultZoom()은 더 이상 지원되지 않습니다. 대신에 웹페이지에 적합한 표시 영역을 정의해야 합니다.

주의: 이러한 API는 Android 4.4 이상에서는 전혀 지원되지 않습니다. targetSdkVersion을 '18' 이하로 설정하더라도 이러한 API는 작동하지 않습니다.

HTML에 표시 영역 속성을 정의하는 방법에 관한 자세한 내용은 WebView의 Pixel-Perfect UI를 참조하세요.

HTML에 표시 영역 너비를 설정할 수 없는 경우에는 setUseWideViewPort()를 호출하여 페이지의 표시 영역을 확대해야 합니다. 예:

Kotlin

    webView.settings.apply {
        useWideViewPort = true
        loadWithOverviewMode = true
    }
    

자바

    WebSettings settings = webView.getSettings();
    settings.setUseWideViewPort(true);
    settings.setLoadWithOverviewMode(true);
    

스타일 변경

배경 CSS 단축 속성이 background-size보다 우선 적용됨

Chrome 및 기타 브라우저는 한동안 이러한 방식으로 작동했지만 이제 개발자가 background 스타일도 지정하면 WebViewbackground-size의 CSS 설정보다 우선 적용됩니다. 예를 들어 여기서 크기는 기본값으로 재설정됩니다.

    .some-class {
      background-size: contain;
      background: url('images/image.png') no-repeat;
    }
    

해결 방법은 두 속성의 위치를 바꾸는 것입니다.

    .some-class {
      background: url('images/image.png') no-repeat;
      background-size: contain;
    }
    

크기가 화면 픽셀 대신 CSS 픽셀로 반환됨

이전에는 window.outerWidth, window.outerHeight 같은 크기 매개변수는 실제 화면 픽셀로 값을 반환했습니다. 새 WebView에서 이러한 매개변수는 CSS 픽셀 기준의 값을 반환합니다.

대개 요소 크기를 조정하거나 다른 계산을 할 때 실제 크기를 픽셀 단위로 계산하는 것은 바람직하지 않습니다. 그러나 확대/축소를 중지하고 초기 스케일을 1.0으로 설정하면 window.devicePixelRatio를 사용하여 스케일을 얻은 다음 그 스케일에 CSS 픽셀 값을 곱할 수 있습니다. 이 대신 자바스크립트 결합을 만들어 WebView 자체에서 픽셀 크기를 쿼리할 수도 있습니다.

자세한 내용은 quirksmode.org를 참조하세요.

NARROW_COLUMNS 및 SINGLE_COLUMN은 더 이상 지원되지 않음

WebView에서는 WebSettings.LayoutAlgorithmNARROW_COLUMNS 값이 지원되지 않습니다.

주의: 이러한 API는 Android 4.4 이상에서는 전혀 지원되지 않습니다. targetSdkVersion을 '18' 이하로 설정하더라도 이러한 API는 작동하지 않습니다.

이 변경사항은 다음 방법으로 처리할 수 있습니다.

  • 애플리케이션 스타일 변경:

    페이지의 HTML과 CSS를 제어할 수 있다면 콘텐츠 디자인을 변경하는 것이 가장 안정된 접근 방법일 수 있습니다. 예를 들어 라이선스를 언급하는 화면의 경우 다음과 같은 스타일로 <pre> 태그 내에 텍스트를 래핑하는 것이 좋습니다.

    <pre style="word-wrap: break-word; white-space: pre-wrap;">

    이 방법은 페이지의 표시 영역 속성을 정의하지 않은 경우에 특히 유용할 수 있습니다.

  • TEXT_AUTOSIZING 레이아웃 알고리즘 사용:

    다양한 데스크톱 사이트를 휴대기기에서 더 읽기 쉽게 만들기 위해 좁은 열을 사용하고 있을 때 HTML 콘텐츠를 변경할 수 없다면 NARROW_COLUMNS 대신에 새 TEXT_AUTOSIZING 알고리즘을 사용하는 것이 적합할 수 있습니다.

또한 이전에 지원 중단된 SINGLE_COLUMN 값도 새 WebView에서 지원되지 않습니다.

자바스크립트에서 터치 이벤트 처리

WebView에서 터치 이벤트가 웹페이지에 의해 직접 처리되는 경우 반드시 touchcancel 이벤트도 처리해야 합니다. touchcancel이 호출되는 몇 가지 시나리오가 있으며 이 이벤트가 수신되지 않으면 다음과 같은 문제가 발생할 수 있습니다.

  • 요소가 터치되고(이에 따라 touchstarttouchmove가 호출됨) 페이지가 스크롤되는 경우 touchcancel이 발생합니다.
  • 요소가 터치되지만(touchstart가 호출됨) event.preventDefault()가 호출되지 않는 경우 touchcancel이 일찍 발생합니다(따라서 WebView는 개발자가 터치 이벤트를 사용하지 않으려 할 것으로 가정함).