요즘 회사에서 WebView 이슈로 여러 번 앱 업데이트를 하고 있는데요. 이번 글의 주제는 WebView의 Alert가 안 나오는 이슈가 있어서 알아보게 되었습니다. 이번 글에서는 WebView의 Alert를 표시하는 방법에 대해서 소개해보려고 합니다.
Alert가 안 나온다면
//문제의 코드
override fun onJsAlert(
view: WebView,
url: String,
message: String,
result: JsResult
): Boolean {
return true
}
저처럼 Alert가 표시되지 않는 이슈를 겪고 있으시다면 WebChromeClient의 onJsAlert 함수에서 아무 처리도 하지 않고 그냥 true를 반환하고 있는지 확인해 보세요
onJsAlert 정의를 따라가 보면 주석으로 친절하게 설명이 되어있는데요. onJsAlert는 WebView에서 Alert를 표시하고자 할 때 콜백으로 호출되는 함수입니다. false를 반환하면 WebView System Alert를 그대로 띄우며, true를 반환할 경우 WebView System Alert를 표시하지 않고 자체적인 Dialog를 띄우겠다는 의미입니다.
따라서 true를 반환하고 아무 동작을 안 한다면 저처럼 Alert가 표시되지 않는 이슈를 겪을 수 있습니다 하하..
Alert Custom
WebView Alert를 그대로 사용할 경우 이미지처럼 못생긴 Dialog가 표시됩니다. 못생긴 UI 뿐만 아니라 Html를 직접 로드한 경우 표시되는 "JavaScript"라는 타이틀과 URL을 로드했을 때 표시되는 도메인 주소는 사용자에게 불필요한 정보입니다.
override fun onJsAlert(
view: WebView,
url: String,
message: String,
result: JsResult
): Boolean {
AlertDialog.Builder(view.context)
.setTitle("Custom")
.setMessage(message)
.setPositiveButton("확인") { _, _ ->
result.confirm()
}.setOnCancelListener {
result.cancel()
}.show()
return true
}
커스텀 Dialog를 보여주기 위해서 WebChromClient의 onJsAlert를 재정의해야 해서 true를 반환하도록 수정해야 합니다. 그리고 원하는 Dialog를 표시하는 코드를 구현합니다.
여기서 중요한 점은 JsResult 객체를 통해 Alert의 Action을 Web으로 다시 전달해 주는 것입니다.
//Handle the result if the user cancelled the dialog.
public final void cancel() {
mResult = false;
wakeUp();
}
//Handle a confirmation response from the user.
public final void confirm() {
mResult = true;
wakeUp();
}
JsResult confirm 함수는 positive Button을 클릭했을 때 호출하도록 구현해 주면 됩니다.
JsResult cancel 함수는 Dialog의 취소 버튼을 누르거나, Dialog 외곽을 눌러 취소했을 때 호출해 주도록 구현하는 것이 좋습니다. Alert는 대부분 알림 메시지를 확인하는 용도로 사용하기 때문에 취소 버튼 대신 cancel Listener에서 cancel를 호출하도록 구현하는 것이 좋을 것 같습니다.
Confirm, Prompt도 동일하게 구현하기
Js Confirm, Prompt도 Alert처럼 사용자에게 다이얼로그를 노출하는 기능인데요. Alert와 다르게 사용자의 입력 또는 액션을 기다리는 특징이 있습니다.
Confirm Custom
override fun onJsConfirm(
view: WebView,
url: String,
message: String,
result: JsResult
): Boolean {
AlertDialog.Builder(view.context)
.setTitle("Custom")
.setMessage(message)
.setPositiveButton("확인") { _, _ ->
result.confirm()
}.setNegativeButton("취소") { _, _ ->
result.cancel()
}.setOnCancelListener {
result.cancel()
}.show()
return true
}
구현 코드는 onJsAlert와 매우 유사하지만 사용자의 취소 액션을 버튼을 통해 직접적으로 받는 Dialog이기 때문에 Negative Button이 추가된 점을 확인할 수 있습니다. onJsAlert와 달리 Confirm에서 주의할 점은 result.cancel을 반드시 해야 하는 점입니다. Confirm은 사용자의 액션을 받을 때까지 대기하기 때문에 cancel을 호출해주지 않으면 웹이 멈춰버릴 수도 있습니다
Prompt Custom
override fun onJsPrompt(
view: WebView,
url: String,
message: String,
defaultValue: String,
result: JsPromptResult
): Boolean {
val inflater = LayoutInflater.from(view.context)
val promptView: View = inflater.inflate(R.layout.dialog_prompt, null, false)
val messageView = promptView.findViewById<TextView>(R.id.message)
messageView.text = message
val valueView = promptView.findViewById<EditText>(R.id.value)
valueView.setText(defaultValue)
AlertDialog.Builder(view.context)
.setView(promptView)
.setPositiveButton("확인") { _, _ ->
result.confirm(
valueView.text.toString()
)
}
.setOnCancelListener { _ -> result.cancel() }
.show()
return true
}
prompt는 사용자에게 문자열을 입력받는 Dialog이기 때문에 커스텀하려면 EditText가 있는 Custom View를 설정해줘야 합니다. 그래서 LayoutInflater를 통해 원하는 Custom View를 생성하고 message와 defaultValue 값으로 뷰를 초기화해 주고 확인 버튼을 눌렀을 때 입력한 값을 넘겨주는 코드입니다.
'Android > WebView' 카테고리의 다른 글
[Android] WebView로 파일을 업로드하는 방법 (0) | 2023.09.14 |
---|---|
[Android] WebView Exception 처리하기 (0) | 2023.07.15 |
[Android] WebView에서 유투브 전체 화면을 올바르게 표시하는 방법 (0) | 2023.06.10 |