“Android 로봇은 Google에서 제작하여 공유한 저작물을 복제하거나 수정한 것으로 Creative Commons 3.0 저작자 표시 라이선스의 약관에 따라 사용되었습니다.”
WebView를 사용하여 App을 만들 때
Web과 통신을 하거나 Web의 LifeCycle을 제어하고 싶을 때가 있다.
다행히 Android에선 이를 모두 라이브러리로 지원을 하고 있다.
위 3가지를 활용하면 네이티브 App에서도 WebView를 통해
웹페이지를 제어할 수 있다.
이 포스팅에선 JavascriptInterface와 WebChromeClient를 간단한 샘플 앱을 통해 알아보자
JavascriptInterface라는 어노테이션을 Android에서 제공하는데
Web에서 네이티브 기능에 접근하고 싶을 때
해당 기능을 실행하는 메소드에 이 어노테이션을 추가하면
Web에서 해당 메소드를 호출할 수 있다.
토스트 메세지를 띄우는 메소드가 있는 인터페이스를 만들어보자
class JSInterface(private val context: Context) {
@JavascriptInterface
fun showToast(text: String) = Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
}
이제 WebView를 세팅하러 가보자
binding.apply {
webview.apply {
webViewClient = MyWebViewClient()
webChromeClient = MyChromeClient()
settings.apply {
javaScriptEnabled = true
loadWithOverviewMode = true
useWideViewPort = true
cacheMode = WebSettings.LOAD_DEFAULT
}
addJavascriptInterface(JSInterface(this@MainActivity), "JeepChief")
loadUrl("file:///android_asset/index.html")
}
}
addJavascriptInterface(InterfaceClass(), "웹에서 사용할 이름")
추가해주면 WebView에 인터페이스가 추가되어 웹과 주고받을 준비는 끝이다.
WebView의 Setting과 관련된 사항은 이전 포스트를 참고하길 바란다.
샘플로 사용할 웹페이지를 만들어주자
위치는 asset폴더에 저장해주면 된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hybrid Sample</title>
</head>
<body onload="showToast('hello')">
<script type="text/javascript">
// Web에서 네이티브 호출
function showToast(text) {
JeepChief.showToast(text);
}
// 네이티브에서 호출할 Web 메소드
function showAlert(text) {
alert(text);
}
</script>
</body>
</html>
onload()
속성을 사용해서 웹페이지가 열리면
토스트가 호출되도록 만들었다.
이제 실행해보면 위 캡쳐처럼 웹페이지의 로드가 되면 토스트 메세지를 띄우는 것을 볼 수 있다.
그렇다면 반대로 생각을 해볼 수도 있다.
네이티브에서 Web을 호출할 순 없을까?
이 또한 매우 간단하게 가능하다.
webView.loadUrl()
을 호출할 때 매개변수를
Url 대신 javascript 코드를 넣어주면 Web에서 해당 코드를 실행해준다.
필자는 네이티브에서 버튼을 클릭하면 웹에서 정의된 alert을 출력하는 메소드를 호출해보았다.
먼저 클릭할 버튼의 리스너에서 loadUrl
메소드를 호출했다.
btnAlert.setOnClickListener {
webview.loadUrl("javascript:showAlert(\"Hello World!\")")
}
매개변수로 호출할 Javascript 코드를 자유롭게 작성하고
앞에 javascript:
를 붙여주면 웹에서 실행을 해준다.
그리고 이제 앱을 실행해보면..
alert이 네이티브에서도 정상적으로 호출되는 것을 볼 수 있다.
하지만 위의 alert을 커스텀하고 싶을 때가 있다.
title을 다르게 보여주고 싶거나 alert의 style을 지정하는 등의
일을 하고 싶을 때 말이다.
이 또한 Android에선 WebChromeClient를 통해 지원한다.
WebChromeClient는 javascript과 관련된 다양한 콜백을 제공한다.
이 포스팅에선 간단히 몇 개만 소개하고 나머지는 위의 링크를 통해 확인해보길 바란다.
class MyChromeClient : WebChromeClient() {
companion object val TAG = "Hybrid"
private var webTitle = ""
private lateinit var webIcon: Bitmap
override fun onReceivedTitle(view: WebView?, title: String?) {
Log.e(TAG, "onReceivedTitle()")
super.onReceivedTitle(view, title)
title?.let { webTitle = it }
}
override fun onReceivedIcon(view: WebView?, icon: Bitmap?) {
Log.e(TAG, "onReceivedIcon()")
super.onReceivedIcon(view, icon)
icon?.let { webIcon = it }
}
override fun onJsAlert(
view: WebView?,
url: String?,
message: String?,
result: JsResult?
): Boolean {
Log.e(TAG, "onJsAlert()")
view?.context?.let {
AlertDialog.Builder(it)
.setTitle(webTitle)
.setMessage(message)
// .setIcon(BitmapDrawable(view.context.resources, webIcon))
.setPositiveButton("확인") { _, _ -> result?.confirm() }
.setNegativeButton("취소") { _, _ -> result?.cancel() }
.show()
}
return true
}
override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
return super.onConsoleMessage(consoleMessage)
}
}
onReceivedTitle()
onReceivedIcon()
onJsAlert()
onConsoleMessage()
console.log()
를 통해 출력되는 메세지들이다.필자는 onJsAlert()
에서 alert을 커스텀했다.
실행 화면은 아래와 같다.
샘플 앱의 원본 소스는 여기에서 확인할 수 있다.
개인적으로 공부했던 것을 바탕으로 작성하다보니
잘못된 정보가 있을수도 있습니다.
인지하게 되면 추후 수정하겠습니다.
피드백은 언제나 환영합니다.
읽어주셔서 감사합니다.