Migrating to WebView in Android 4.4

웹뷰 테스트는 하고 릴리즈하는거니?

marojun
marojun
Nov 24, 2013 · 15 min read

원문 : http://developer.android.com/guide/webapps/migrating.html

안드로이드 4.4에서 사용하는 WebView는 Chromium 기반으로 변경됨에 따라 안드로이드 크롬 브라우저와 동일한 수준의 성능과 호완성을 갖추고 최신 HTML5, CSS3 표준 기술들을 지원하며 V8 자바스크립트 엔진이 탑재된 최신버전으로 적용되었습니다.

이제부터 본격적으로 설명할 것들은 매니페스트에 targetSdkVersion을 19이상으로 설정할 경우 알아야 할 WebView 변경사항들에 대한 설명입니다.

targetSdkVersion이 18또는 이보다 낮은 경우 웹뷰는 quirks mode라는 호환 모드로 동작하도록 구현되어 있습니다. 그러나 4.4의 호환모드에서도 single and narrow column layoutsdefault zoom levels은 지원하지 않으며 이외에도 아직 알려지지 않은 문제가 발행할 수 있으니 안드로이드 4.4 이상에서 꼭 테스트해야합니다.

4.4 웹뷰 최적화 작업중 일어난 이슈에 대해 도움을 주기 위해 setWebContentsDebuggingEnabled()을 이용한 데스크롭 크롬을 통한 원격 디버깅이 가능해졌습나다. 이 기능을 통해 WebView를 실행하는 동안 웹 컨텐츠, 스크립트 및 네트워크 활동을 검사하고 분석 할 수 있습니다. 자세한 내용은 Debugging on Android을 참조하세요.

User Agent Changes

유저 에이전트를 통해 웹뷰에 맞춤형 컨텐츠를 제공하는 경우가 있을 것입니다. 4.4에서는 기존 유저 에이전트 형태와는 달리 크롬 버전을 포함하게 되었습니다.

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

만약 유저 에이전트를 보기만 하고 저장하고 싶지 않다면 스태틱 메서드인 getDefaultUserAgent()을 사용하면 됩니다.

public static String getDefaultUserAgent (Context context)

Added in API level 17

Returns the default User-Agent used by a WebView. An instance of WebView could use a different User-Agent if a call is made to setUserAgentString(String).

그러나 대신 웹뷰객체 생성 후 setUserAgentString()을 이용한 커스텀 에이전트 적용시에는 getUserAgentString()을 사용해야합니다.

public synchronized String getUserAgentString ()

Added in API level 3

Gets the WebView’s user-agent string.

Returns

the WebView’s user-agent string

Multi-threading and Thread Blocking

UI 쓰레드가 아닌 별도의 쓰레드에서 WebView를 호출한다면 예측하지 못한 결과가 생길 수도 있습니다. 예를 들어서 앱에서 멀티 쓰레드를 사용할 경우 웹뷰를 UI에서 사용하기 위해 아래와 같이 runOnUiThread()를 통해 호출되어야 합니다.

runOnUiThread(new Runnable() {
@Override
public void run() {
// Code for WebView goes here
}
});
또한 UI 쓰레드를 차단하면 자바스크립트와의 연동에 문제가 생길 수 있습니다. 예를들어 아래 코드처럼 사용하면 안됩니다.// This code is BAD and will block the UI thread
webView.loadUrl(“javascript:fn()”);
while(result == null) {
Thread.sleep(100);
}

그 대신 비동기로 자바 스크립트를 실행할 수 있게 해주는 evaluateJavascript()를 사용 할 수 있습니다.

public void evaluateJavascript (String script, ValueCallback<String> resultCallback)

Added in API level 19

Asynchronously evaluates JavaScript in the context of the currently displayed page. If non-null, |resultCallback| will be invoked with any result returned from that execution. This method must be called on the UI thread and the callback will be made on the UI thread.

Parametersscriptthe JavaScript to execute.resultCallbackA callback to be invoked when the script execution completes with the result of the execution (if any). May be null if no notificaion of the result is required.

Custom URL Handling

이제 웹뷰를 사용할 때 오직 유효한 URL에 대해서만 shouldOverrideUrlLoading() 또는 shouldInterceptRequest()가 호출 되어집니다.

4.4 에서 커스텀 URL 스킴 또는 base URL을 사용하여 리소스들을 불러올때 실패하거나 잘 작동하지 않는다면 RFC 3986을 준수하는 유효한 URL을 지정했는지를 확인하세요.

예를 들어서 새로운 웹뷰에서는 아래와 같은 링크에 대해서는 shouldOverrideUrlLoading()는 호출되지 않을 것입니다.

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

아래의 경우 유저가 링크를 클릭할때 상황에 따라 결과는 달라질 수 있습니다 :

위와 같이 사용하려면 이제는 아래와 같이 스킴을 이용하면 됩니다.

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

이를 통해 shouldOverrideUrlLoading()이 호출되면 아래 함수와 같이 URL을 사용하면 됩니다.

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과 유효한 호스트를 설정할 수 있습니다. 예를 들면 아래와 같습니다.

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

유효한 호스트 이름은 RFC 3986을 준수해야하며 끝에 슬래시를 포함하는 것이 중요합니다, 그렇지 않으면 로드 된 페이지에서 모든 요청은 드롭될 수 있습니다.

Viewport Changes

뷰 포트란 멀티 디바이스들의 해상도에 대응하기 위해 사용되는 태그를 말합니다.

target-densitydpi를 더 이상 지원하지 않습니다.

target-densitydpi의 경우 아이폰에서는 지원하지 않으므로 공통으로 처리할 수 있는 기준을 지원하기 위해 지원하지 않도록 하는것 같습니다.

이전버전의 경우 웹뷰에서 웹페이지의 스크린 density를 지정하는데 사용하는 target-densitydpi이라는 뷰포트 속성이 있었습니다.

<meta name=”viewport” content=”target-densityDpi=device-dpi”>

이 속성은 더 이상 지원되지 않으며 이미지나 CSS에 대해 Pixel-Perfect UI in the WebView에서 볼 수 있는 표준방법으로 마이그레이션 해야할 것입니다.

Viewport zooms in when small

이전에 뷰포트의 넓이가 320이거나 그보다 작았다면 넓이 값은 device-width로, 높이가 웹뷰의 높이보다 작거나 같을경우는 device-height로 설정되었을 것입니다. 그러나 새로운 웹뷰에서는 넓이 또는 높이 값이 값이 준수되며 스크린의 넓이에 맞게 웹뷰가 줌 될 것입니다.

<meta name=”viewport” content=”width=device-width, height=device-height”>

Multiple viewport tags not supported

4.4 이전버전에서는 여러개의 뷰포트 메타태그를 선언하면, 자동으로 그것들이 결합되어 사용되었지만, 이번 버전의 웹뷰에서는 마지막에 선언된 웹뷰만 사용되고 나머지는 무시됩니다.

Default zoom is deprecated

getDefaultZoom()setDefaultZoom() 가 더 이상 지원 되지않습니다.

WebView에서 자동으로 default zoom을 맞춰주기 때문

이 적용사항은 4.4 및 그 이상의 버전 뿐만아니라 targetSdkVersion을 18이나 그 이하로 설정할 경우에도 동작하지 않습니다.

만약 뷰포트의 넓이를 지정하지 않았다면 아래와 같이 setUseWideViewPort() 함수를 통해서 더 큰 뷰포트를 할당 받을 수 있습니다.

public synchronized void setUseWideViewPort (boolean use)

Added in API level 1

Sets whether the WebView should enable support for the “viewport” HTML meta tag or should use a wide viewport. When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used.

Parametersusewhether to enable support for the viewport meta tag

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

Styling Changes

The background CSS shorthand overrides background-size

이번 웹뷰는 배경 스타일을 지정하는 경우 background-size를 위한 CSS 세팅을 재정의합니다. 예를 들어, 아래의 background-size는 기본값으로 변경될 것입니다.

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

// 두 속성의 간의 위치가 변경되었습니다.
.some-class {
background: url(‘images/image.png’) no-repeat;
background-size: contain;
}

Sizes are in CSS pixels instead of screen pixels

이전에는 window.outerWidth 이나 window.outerHeight를 통해 실제 스크린 픽셀 값을 받았지만 새로운 웹뷰의 경우는 CSS픽셀 기반의 값을 받습니다.

스크린사이즈를 구할때 이전 버전에서는 window.outerWIdth / outerHeight 를 통해 구할 수 있었지만 4.4에서는
outerWidth/Height가 css pixel을 나타내게 됩니다.

이렇게 실제 스크린 픽셀 값을 받아 계산하여 사용하는 것은 나쁜 방법입니다. 이제는 계산작업이 필요없이 JavaScript binding를 이용하여 웹뷰의 실제 픽셀값을 가져올 수 있습니다.

ex) 실제 디바이스 Width : 480 | window.outterWidth : 288

더 자세한 내용은 quirksmode.org을 참조해주세요.

NARROW_COLUMNS and SINGLE_COLUMN no longer supported

새로운 웹뷰에서는 WebSettings.LayoutAlgorithm를 위한 NARROW_COLUMNS 값을 더이상 지원되지 않습니다.

이 적용사항은 4.4 및 그 이상의 버전 뿐만아니라 targetSdkVersion을 18이나 그 이하로 설정할 경우에도 동작하지 않습니다.

다음과 같은 방법으로 이러한 변화를 처리할 수 있습니다.

  • 스타일을 변경 :
    HTML 또는 CSS를 사용하고 있다면 신뢰할 수 있는 방법을 사용해야합니다. 예를 들어 싸이트에서 라이센스를 표현할때는 <pre>안에 텍스트를 넣길 원할 것입니다. 그럴경우 다음과 같이 지정하면 됩니다.
  • <pre style=”word-wrap: break-word; white-space: pre-wrap;”>
  • 이것은 페이지에 대한 뷰포트 속성을 정의하지 않은 경우 특히 도움이 됩니다.
  • 새로운 TEXT_AUTOSIZING layout algorithm 사용 :
    다양한 기기를 지원하기 위해 narrow columns을 사용하고 있었다면 HTML 컨텐츠에 대해 수정을 할 수 없습니다. 새로운 TEXT_AUTOSIZING layout algorithm은 이것에 대한 적절한 대안이 될 수 있습니다.

또한 이번 버전에서는 이전에 deprecated된 SINGLE_COLUMN도 지원하지 않습니다.

웹뷰 자체에서 뷰포트를 관리하게 된 만큼, 이전 버전에서 레이아웃이나 뷰포트에대해 옵션으로 제공하던 method 나 속성들을 모두 제거

Handling Touch Events in JavaScript

웹 페이지에 직접 WebView 터치 이벤트를 처리하는 경우, touchcancel 이벤트를 처리하고 있는지 확인하세요. 아래에는 touchcancel를 호출했을때 수신하지 않을 경우 어떤 문제가 발생할 수 있는 시나리오가 있습니다.

  • 화면을 터치하고(touchstart 와 touchmove가 불림) 페이지를 스크롤 했을때 touchcancel가 발생합니다.
  • 화면을 터치했지만(touchstart가 불림) event.preventDefault()가 안 불린경우(웹뷰에서 터치이벤트를 사용는 것을 원하지 않는다는것을 가정) 이전에 touchcancel 이벤트를 받을 것입니다.

event.preventDefault()란?

// 아래와 같이 작성한 경우 if에 조건에 맞는 키코드의 경우는 이벤트가 발생하지 않도록 하는 역할을 한다. function keyeventtest(event){ if( event.keyCode == ‘’ ){ alert(‘Test’); event.preventDefault(); } }

마크업 관련 감수에는 웹 표준 커뮤니티 클리어보스의 리더이신 조은(apes0123@gmail.com)님이 진행해 주셨습니다. 감사합니다.

    marojun

    Written by

    marojun

    전슬마로. 협업과 공유를 통해 세상을 멋지게 바꿀수 있다고 믿는 개발자. KTH와 SK Planet을 거쳐 NCSOFT에서 iOS와 Android를 개발하고 있다. — 안드로이드 개발 그룹 https://www.facebook.com/groups/junsle/ 에 놀러오세요

    marojun’s Android

    안드로이드 관련 글을 공유합니다. 

    Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
    Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
    Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade