안드로이드 웹뷰에서 alert dialog를 커스터마이징 했을 때의 주의점

김토끼·2022년 2월 9일
1

안드로이드 앱을 개발하다 보면 웹뷰를 사용할 때가 많다.

그리고 보통 웹뷰로 여는 페이지에 alert dialog가 있다면 WebChromeClient 클래스의 onJsAlert(), onJsConfirm() 함수를 오버라이딩 해서 android AlertDialog 혹은 커스터마이징 한 다이얼로그를 표시한다.

이렇게 개발한 웹뷰는 대개의 경우 아주 잘 동작한다. 하지만 alert 메시지가 떴을 때 확인/취소 버튼 대신 핸드폰의 back키 혹은 다이얼로그 외부 영역을 터치(dialog.cancelable = true 일때) 해서 다이얼로그를 닫는 경우가 생긴다.

다이얼로그의 확인/취소 버튼을 눌러 처리한 경우에는 별 문제가 없다. 하지만 back키나 외부영역 터치를 통해 닫은 경우 웹뷰 페이지에 아무런 상호작용도 일어나지 않고 심지어 웹뷰 화면을 닫았다 다시 열어도 페이지가 로딩되지 않는 경우가 생긴다.

원인을 알 수 없어 여러가지 시도를 하다가 찾아낸 원인은 아래와 같았다.

onJsAlert(), onJsConfirm() 함수는 파라미터로 JsResult 라는 객체를 넘긴다. 우리가 커스터마이징한 alert dialog의 버튼을 선택하면 선택한 버튼에 따라 jsResult.confirm() 혹은 jsResult.cancel() 함수를 호출해서 웹페이지에 결과를 전달해 준다.
하지만 확인/취소 버튼을 눌러 다이얼로그를 닫은게 아니라면 이 결과값을 웹페이지에 전달하지 않고 다이얼로그만 닫히게 된다.

즉 웹페이지는 무언가 결과(confirm/cancel)를 기다리고 있는데 아무 응답이 없는 상태가 된다.

해결방법은 간단하다. dialog를 생성할 때 setOnCancelableListener()를 추가로 구현해 주고 이 안에서 jsResult.cancel()를 호출해 주면 된다. 웹페이지는 취소라는 결과를 전달받아 이후 동작을 처리할 것이다.

override fun onJsConfirm(
	view: WebView?,
	url: String?,
	message: String?,
	jsResult: JsResult?
): Boolean {
	AlertDialog.Builder(context)
		.setTitle("dialog title")
		.setMessage("dialog message")
		.setPositiveButton("ok") { _, _ ->
			jsResult?.confirm()
		}
		.setNegativeButton("cancel") { _, _ ->
			jsResult?.cancel()
		}
		.setOnCancelListener {
			jsResult?.cancel()
			it.dismiss()
		}
		.setCancelable(true)
        .create()
		.show()
	return true
}
profile
방구석 김토끼🐰

0개의 댓글