안녕하세요. 김과자 입니다.
안드로이드 앱 개발중 웹뷰를 사용하여 개발하는 방식은 이제 아주 흔한 일이 되었죠.
네. 그렇습니다.
우리에게 익숙한 웹을 이용해서.
앱개발하는데 활용한다?
아싸 ! 개꿀!! 기존에 웹이 개발되어 있는걸 그냥 넣기만 하면 끝~?!
얼마나 좋습니까?
"그런데 말입니다."
세상이 어디 그리 호락호락 한가요?
구글 새ㄲ... 아 아니 구글 님들이 얼마나 웹뷰를 잘 만들어 놓았느냐.
"하핳하하핳ㅎㅎ하하하하핳..."
환영합니다.
지금 부터 여러분은 웹의 모든 동작을 수동으로 컨트롤 하게 될것입니다. 🙀
자. 그럼 이제부터 웹뷰 관련 셋팅을 연재해보겠습니다.
- 자주 사용하는 것들 10가지 셋팅법
- 최강의 빌런. 파일업로드 문제!!!
- 이건 진짜 심각한 ... window.open 팝업 처리 관련
- 웹에서 유튜브 풀스크린 셋팅 관련(어이없음주의)
- 계속 추가 예정...
웹뷰에서 자주 사용하는 10가지 셋팅들
#1 핀치줌사용
웹뷰내의 핀치줌 모드를 사용할 수 있게 합니다. (컨트롤러 표시 유무)
웹뷰사용시 한번씩 핀치줌 모드를 사용해야하는 경우가 발생하는데요.
핀치 줌을 사용하기위해서는 webview.settings 설정이 필요합니다.
설정은 아래와 같습니다.
webView.settings.setSupportZoom(true); //zoom mode 사용.
webView.settings.setBuiltInZoomControls(true);
webView.settings.setDisplayZoomControls(false); //줌 컨트롤러를 안보이게 셋팅.
잘안될시. 뷰포트문제일수 있으니 확인!
webView.settings.useWideViewPort = false
"WebView가 "viewport"HTML 메타 태그를 지원해야하는지 또는 넓은 뷰포트를 사용해야하는지 여부를 설정합니다.
설정 값이 false인 경우 레이아웃 너비는 항상 장치 독립적 (CSS) 픽셀의 WebView 컨트롤 너비로 설정됩니다.
값이 true이고 페이지에 뷰포트 메타 태그가 포함 된 경우 태그에 지정된 너비 값이 사용됩니다.
페이지에 태그가 없거나 너비를 제공하지 않으면 넓은 뷰포트가 사용됩니다."
참고 :
https://developer.android.com/reference/android/webkit/WebSettings#setUseWideViewPort(boolean)
https://developer.android.com/guide/webapps/targeting?hl=ko
#2 ERR_CACHE_MISS 문제
웹뷰에서 post 데이터 등으로 왔다갔다 하다보면? ERR_CACHE_MISS 를 만나게 됩니다.
모바일에서만 해당되는 문제 는 아니고 PC 일반 브라우저에서도 볼수있는 문제입니다.
아래와 같이 셋팅하면 문제 해결! (보안적인 문제가 발생할수 있으니 주의)
webView.settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //ERR_CACHE_MISS 문제 처리
(그러나 인증페이지나 계정정보를 활용하는등의 페이지에서는 캐시가 날라가는게 보안적으로 맞기때문에
강제로 설정해도 인증처리등이 실패할수 있음. )
#3 앱 웹뷰 캐시문제
앱에서 이미지, css 등의 리소스가 신규적용되지 않고, 지맘대로 캐시질? 을 하고있는 경우가 있는데요.
캐시를 날리기 위해 아래와같이 설정합니다.
캐시를 항상 날리면 항상 새로가져오기 때문에. 네트워크 자원소모등의 문제가 발생합니다.
상황에 맞게 잘 사용해야합니다.
webView.settings.cacheMode = WebSettings.LOAD_NO_CACHE //캐시 X
//onPageFinished 에서 아래와 같이 설정.
this@MyWebView.clearCache(true)
#4 안드로이드 시스템 글꼴 크기 문제
안드로이드는 시스템글꼴을 바꿀수있기에... 앱에서의 글꼴 크기 또한 지맘대로 변하게 됩니다.
웹뷰상에서도 예외없이 글꼴이 적용되는 경우가 발생하는데요.
아래의 셋팅으로 크기를 비율(퍼센테이지)로 고정 할수있습니다.
// "Sets the text zoom of the page in percent. The default is 100."
this.settings?.textZoom = 100 //system 글꼴 크기에 의해 변하는 것 방지
#5 에이전트값 셋팅
현장에서 일하다보면 보안등의 이유로 특정 해더 에이전트값을 요구하는 경우가 있는데요.
해달라면 해줘야죠. 하핳ㅎ하ㅏ하핳
묻지도 따지지도 않고 해주면 됩니다. 아래와 같이 셋팅
val userAgent = this.settings?.userAgentString
webview.settings?.userAgentString = "${userAgent}/my_blues_app"
#6 웹뷰상의 키보드가 올라오지 않는 문제
웹뷰에서 html 의 input box 등에서 소프트 키보드가 올라오지 않는 문제가 생깁니다.
이럴때 강제로 해당 웹뷰에 포커스를 적용한다.
//xml view 위젯 직접설정
//activity_my_webview.xml
<Webview...
android:focusable="true"
android:focusableInTouchMode="true"
...>
//웹뷰 소스상의 설정
webview.isFocusable = true
webview.isFocusableInTouchMode = true
#7 쿠키싱크 설정
웹뷰내의 쿠키설정은 대부분은 자동으로 처리되지만.
수동으로 관리하기도 합니다.
어떨때? 쿠키가 이상하게 잘 안먹는다.
강제 sync 등의 처리할 때입니다.
웹뷰에서 셋팅
//init 이나 onCreate 에서 처리
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {
val cookieManager = CookieManager.getInstance()
cookieManager.setAcceptCookie(true)
cookieManager.setAcceptThirdPartyCookies(this, true)
}else{
//lollipop 이하 버전에서는 수동으로 쿠키 싱크
CookieSyncManager.createInstance(context)
}
//onPageFinished
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.getInstance().sync()
} else {
//쿠키 수동 싱크 (메모리 -> 로컬저장)
//그밖에 싱크는 webview 에서 자동
CookieManager.getInstance().flush()
}
액티비티에서의 셋팅
//activity - onResume, onPause 처리
override fun onResume() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mainWebView.syncWebviewCookies(COOKIE_SYNC_START)
}
}
override fun onPause() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mainWebView.syncWebviewCookies(COOKIE_SYNC_PAUSE)
}
}
그냥 가기 심심하니까... 쿠키 설정 팁 입니다.
커스텀으로 쿠키값을 심어줘야할때 사용하세요.
//쿠키 커스텀값 설정하기 예제.
cookieManager.setCookie(".bluesweater.com", "custom_value=123_123_123ASDF")
#8 post 날리기
대부분의 경우 loadUrl 로 url를 로드하면 되지만
가끔 웹뷰상에서 post 로 날려야 할 경우가 있죠.
그럴땐 아래와 같이 url 과 해당 파라미터를 바이트 배열로 호출하면 됩니다.
val params = "username=" + URLEncoder.encode(my_username, "UTF-8") //get 파라메터부를 URL (BASE64) 인코딩한뒤
webview.postUrl(url, params?.toByteArray()) //요딴식으로처리
약간 비정상? 정식 방법도 사용 가능합니다.
html string 을 만들어서 로드시 submit 시켜버리는거죠.
//무식하게 요딴식으로 처리할수도 있다.
String html = "<!DOCTYPE html>" +
"<html>" +
"<body onload='document.frm1.submit()'>" +
"http://www.yoursite.com/postreceiver' method='post' name='frm1'>" +
" <input type='hidden' name='foo' value='12345'><br>" +
" <input type='hidden' name='bar' value='23456'><br>" +
"</form>" +
"</body>" +
"</html>";
webview.loadData(html, "text/html", "UTF-8");
참고 : https://stackoverflow.com/questions/39506246/how-to-post-data-for-webview-android
#9 해더값 추가
가끔씩 해더 값을 추가하여 request 하는경우가 있는데
이는 get 방식으로만 처리가 가능합니다. (아무리 찾아봐도 post로 날리는 "정상적인 방법" 은 없더군요.)
예를 들어 해더의 referer 값을 추가하는경우...
val extraHeaders = mutableMapOf<String, String>()
extraHeaders["Referer"] = "www.bluesweater.com"
view.loadUrl(targetUrl, extraHeaders)
아무리찾아봐도 post로 날릴방법이 없기에...
http 통신을 써서 따로 request 날리고 response 를 받아서
html string 을 내가 웹뷰에 랜더링(로드)해줘야한다. -_-;
(아오 구글 놈들 왜 이따위로 ... 될거면 다 되던가 안되면 다 안되던가...;;)
이또한 비정상(또?) 적인 방법으로 날려야 합니다.
왠만 하면 그냥 GET방식으로 날리시길...
참고 https://stackoverflow.com/questions/21754526/android-webview-post-request-with-custom-headers
인터셉터 메서드를 통해서 구현도 가능하다.
그러나 여기서 처리할때 주의할점은
모든 리소스 로드시점을 인터셉터한다는것!
override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {
Log.i(TAG, "request headers: ${request?.requestHeaders.toString()}")
request.getRequestHeaders().put("ClientId", "ANDROID");
return super.shouldInterceptRequest(view, request)
}
#10 웹뷰 로드 error 처리...
페이지 로드시점에서 에러는 정말 다양하게 발생한다.
스크립트 에러, ssl 인증서 에러, 서버에러 등등... 당황하지말고
아래와 같이 메서드 오버라이드를 통해 알아서 처리해주면 됩니다요.
@Suppress("DEPRECATION")
@TargetApi(Build.VERSION_CODES.M)
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
onReceivedError(view, error?.errorCode ?:0, error?.description.toString(), request?.url.toString())
}
@SuppressWarnings("deprecation")
override fun onReceivedError(view: WebView?, errorCode: Int, description: String?, failingUrl: String?) {
Log.d(TAG, "======== $errorCode : $description ========")
//if (errorCode == -14) {
// -14 is error for file not found, like 404.
//}
}
@TargetApi(Build.VERSION_CODES.M)
override fun onReceivedHttpError( view: WebView?,request: WebResourceRequest?,errorResponse: WebResourceResponse?) {
Log.d(TAG, "======== ${errorResponse?.statusCode} ========")
}
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
super.onReceivedSslError(view, handler, error)
Log.d(TAG, "======== ${error.toString()} ========")
handler?.proceed()
}
#마무리
이렇게 10가지 잡다한 셋팅방법을 알아보았습니다.
안드로이드 웹뷰는 정말 필요악. 입니다. 아오.
다음편은 바로바로 안드로이드 웹뷰의 절대 빌런계의 쌍두마차죠.
파일업로드와 오픈팝업에 대해 알아보겠습니다.
그럼 개발자님들 오늘도 힘내시길 바라며
끝.
'개발 코딩 정보 공유 > 안드로이드 자바 코틀린' 카테고리의 다른 글
안드로이드에서 사용하는 코루틴 (코틀린) (0) | 2021.02.05 |
---|---|
웹뷰뿌시기 (webview) 파일업로드(사진업로드) (0) | 2020.06.01 |
안드로이드 'ShouldOverrideUrlLoading' 너는 누구냐? (1) | 2019.11.15 |
코틀린사용 - 자바static, 객체식, 객체선언, 컴패니언 (0) | 2019.03.31 |
안드로이드 쓰레드 실체 파악하기 (0) | 2019.03.19 |