Android์์ WebView๋ฅผ ํตํด Web๊ณผ ์ํตํ๊ธฐ
- #WebView
- #Android
- #Video
- #FullScreen
๋ค์ด๊ฐ๋ฉฐ
์๋ ํ์ธ์ ๋ ธ๋จธ์ค์์ ์๋๋ก์ด๋ ๊ฐ๋ฐ์ ํ๊ณ ์๋ ์์์ง์ ๋๋ค. ์ด๋ฒ์๋ WebView์ ๊ด๋ จ๋ ์ด์๋ฅผ ํด๊ฒฐํ๋ฉด์ ํ์ตํ๋ ๋ด์ฉ์ ๊ณต์ ํ๊ณ ์ ํฉ๋๋ค.
Android์์ WebView ๋์์ ์ ์ฒดํ๋ฉด์ด ์๋ผ์!
WebView๋ก ๊ตฌ์ฑ๋ ํ๋ฉด์์ ๋์์ ์ ์ฒดํ๋ฉด ๋ฒํผ์ด ๋นํ์ฑํ๋์ด ๋์์์ ์ ์ฒดํ๋ฉด์ผ๋ก ๋ณผ ์ ์๋ ์ด์๊ฐ ๋ฐ๊ฒฌ๋์์ต๋๋ค. ์๋ฟ์ธ.. ios๋ OS์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ฒดํ๋ฉด ๊ธฐ๋ฅ์ ์ ๊ณต์ ํด์ฃผ์ด์ ์ ์ ์๋๋๊ณ ์์์ง๋ง Android๋ ๋ณ๋์ ๊ตฌํ์ ํด์ฃผ์ด์ผ ํ์ฑํ๋๋ ๊ฒ์ด์์ต๋๋ค.
Android Webview์์ ๋์์ ์ ์ฒด๋ณด๊ธฐ ํ์ฑํ
WebChromeClient
์ onShowCustomView()
์ onHideCustomView()
๋ฅผ overrideํ์ฌ ์ ์ฒดํ๋ฉด ์ง์
/ํด์ ์์ ๋์์ ๊ตฌํํด ์ฃผ๋ฉด ํ์ฑํ๋ฉ๋๋ค.
override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
super.onShowCustomView(view, callback)
// ์ ์ฒดํ๋ฉด view๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋ ๋ก์ง
}
override fun onHideCustomView() {
super.onHideCustomView()
// ์ ์ฒดํ๋ฉด view๋ฅผ ์ ๊ฑฐํ๋ ๋ก์ง
}
onShowCustomView()
์ ํ๋ผ๋ฏธํฐ๋ก ๋์ด์ค๋view
๊ฐ ์ ์ฒดํ๋ฉด์ผ๋ก ํ์ํ View ์ ๋๋ค.
ํ์ง๋ง..
์คํํด๋ณด์๋๋ ์ ์ฒดํ๋ฉด ๊ธฐ๋ฅ ์์ฒด๋ ๋์ํ์ง๋ง, ๋์์ ๋น์จ์ ๊ด๊ณ์์ด ์ธ๋ก๋ก๋ง ํ์๋์์ต๋๋ค. ์๋๋ก์ด๋ ๋ค์ดํฐ๋ธ์์ ํ ์ ์๋ ์ด๋ฐ์ ๋ฐ ๋ฐฉ๋ฒ์ ์๋ํด ๋ณด์์ง๋ง ๊ฒฐ๊ตญ ์ ๋ก๋ ์ ์๋ฒ์ ์์ ํฌ๊ธฐ๋ฅผ ์ ์ฅํ์ฌ ํ์ฉํ๋ ๋ฐฉํฅ์ผ๋ก ํด๊ฒฐํ๋๋ก ์ด์ผ๊ธฐ๊ฐ ๋์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ฐ์ผํ ํ์ฅ๋์ ํ๋ง๋๋ฅผ ๋จ๊ธฐ๊ณ ์๋๋ฌ ํ์์ค๋ก ๋ ๋์ จ์ต๋๋ค.
โํ๋ก ํธ ํ์๊ฒ ์์ ํฌ๊ธฐ ์ ๋ฌํ๋๊ฑฐ ๋ง๋ค์ด ๋ฌ๋ผ๊ณ ์์ฒญํด์ฃผ์ธ์~โ
.
.
.
๊ทธ.. ๊ทธ๊ฒ ๋ญ์ฃ ?
WebView ๊ฐ๋ฐ ๊ฒฝํ์ด ์๋ ์ ์ฌ 3๊ฐ์ ์ฐจ ์ ์ ์ด์๋ ์ ๋ ๊ทธ๋ง ํผ๋์ ๋น ์ง๊ณ ๋ง์์ต๋๋คโฆ
- ์๋ฒ์ ์ ์ฅ๋์ด ์์ ์์ ํฌ๊ธฐ๋ฅผ ์ ํ๋ก ํธํ์๊ฒ ์ ๋ฌํด๋ฌ๋ผ๊ณ ์์ฒญํด์ผ ํ๋ ๊ฑฐ์ง????
- ํฐ์์ ๋ฌด์จ ์์์ ๋ณด๋์ง ์ด๋ป๊ฒ ์๊ณ ์์ ํฌ๊ธฐ ์ ๋ฌ์ด ๋๋ ๊ฑฐ์ง???
- ์ ์ด์ ๋ญ ์ด๋ค ํ์์ผ๋ก ๋ง๋ค์ด๋ฌ๋ผ๊ณ ์์ฒญํด์ผ ํ์ง???
๋ธ๋ฆฟ์ง ์ธํฐํ์ด์ค
๋ง์นจ ํ๋ก ํธํ ์๋ฏผ๋์ ์น๋ทฐ(WebView) ๊ฐ๋ฐ ์ ์ฉ๊ธฐ ๊ธฐ์ ๋ธ๋ก๊ทธ ํฌ์คํธ์์ ๊ด๋ จ ๋ด์ฉ์ ๋ค๋ฃจ๊ณ ์์ด์ ์ฝ์ด ๋ณด์๊ณ , ์น๊ณผ ์ฑ๊ฐ์ ๋ธ๋ฆฟ์ง ์ธํฐํ์ด์ค์ ์กด์ฌ๋ฅผ ์๊ฒ ๋์์ต๋๋ค.
JavaScript๋ก Android ์ฝ๋ ์คํ์ํค๊ธฐ
JavaScript ์ฌ์ฉ ํ์ฑํ
webView.settings.javaScriptEnabled = true
WebView
์WebSettings
๋ฅผ ํตํด JavaScript ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค.- JavaScript๊ฐ Android ์ฑ์ ์ ์ดํ๋ ๊ฒ์ ์ ์ฉํ ์ ์์ง๋ง ๋ณด์ ๋ฌธ์ ๊ฐ ๋ ์ ์๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ต๋๋ค.
- ex) WebView์ ํ์๋๋ ํ์ด์ง์ ์ ์์ ์ธ JavaScript ์ฝ๋๊ฐ ํฌํจ๋์ด ์๋ ๊ฒฝ์ฐ
- ์๋๋ก์ด๋ ๊ณต์ ๋ฌธ์์์๋ ์ง์ ์์ฑํ JavaScript ์ธํฐํ์ด์ค๋ฅผ ์คํ์ํค๋ ๊ฒ์ด ์๋๋ผ๋ฉด ๋ธ๋ผ์ฐ์ ์ ํ๋ฆฌ์ผ์ด์
์ผ๋ก ๋งํฌ๋ฅผ ์ด๋๋ก ๊ถ์ฅํ๊ณ ์์ต๋๋ค.
- ๋ ธ๋จธ์ค ํ๋ก ํธํ ํ์๋ถ๋ค์ ๋น์ฐํ ์ ๋ขฐํ ์ ์๊ธฐ ๋๋ฌธ์ ์ต์ ์ ํ์ฉํด ์ค๋๋ค.
์ธํฐํ์ด์ค ์ค๊ณ
- ์๋ฏผ๋์ ๊ธฐ์ ๋ธ๋ก๊ทธ ํฌ์คํธ์ โ์น๊ณผ ์ฑ ๊ฐ์ ์ธํฐํ์ด์ค ์ค๊ณโ ๋จ๋ฝ์์ ๊ณต๊ฐ๋ 3๊ฐ์ง ๋ฉ์๋๋ฅผ ์์ ์ฝ๋๋ก ๋ค๊ฒ ์ต๋๋ค.
internal class FrommAppJsInterface(private val viewModel: InAppBrowserViewModel) {
@JavascriptInterface
fun openBrowser(url: String) {
viewModel.action(InAppBrowserAction.OpenBrowser(url))
}
@JavascriptInterface
fun openInAppBrowser(url: String) {
viewModel.action(InAppBrowserAction.OpenInAppBrowser(url))
}
@JavascriptInterface
fun closeInAppBrowser() {
viewModel.action(InAppBrowserAction.CloseInAppBrowser)
}
}
@JavascriptInterface
์ด๋ ธํ ์ด์ ์ ์ถ๊ฐํจ์ผ๋ก์จ WebView์ JavaScript ์ฝ๋๊ฐFrommAppJsInterface
๊ฐ์ฒด์ ๋ฉ์๋์ ์ ๊ทผํ ์ ์๋๋ก ํฉ๋๋ค.
WebView์ ๋ธ๋ฆฟ์ง ์ธํฐํ์ด์ค๋ฅผ ์์ฑํ ํด๋์ค ๊ฐ์ฒด ์ฃผ์
webView.addJavascriptInterface(FrommAppJsInterface(inAppBrowserViewModel), "Fromm")
addJavascriptInterface
๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ WebView์ ์ฃผ์ ํ์ฌ JavaScript์์ ์ ๊ทผํ ์ ์๋๋ก ํฉ๋๋ค.- ์ฃผ์ ๋ ๊ฐ์ฒด๋ ์นํ์ด์ง์ ๋ชจ๋ ํ๋ ์์์ ์ ๊ทผ ๊ฐ๋ฅํฉ๋๋ค.
android({ url }) {
window.Fromm.openBrowser(url);
},
- ์ ์ฝ๋๋ Web ์ฝ๋์ ์ผ๋ถ์ ๋๋ค. WebView์์ ์ ์ปค๋งจ๋๊ฐ ์คํ๋๋ฉด ์ด์ ์์ํ๋ ์๋์ ๋ค์ดํฐ๋ธ ์ฝ๋๊ฐ ์คํ๋ฉ๋๋ค.
openBrowser()
์ ๊ฒฝ์ฐ์๋ ์ธ์๋ก ๋ค์ด์ค๋url
์ ๋ธ๋ผ์ฐ์ ๋ก ์ฌ๋ ๋ค์ดํฐ๋ธ ์ฝ๋๊ฐ ์คํ๋๊ฒ ์ต๋๋ค.
@JavascriptInterface
fun openBrowser(url: String) {
viewModel.action(InAppBrowserAction.OpenBrowser(url))
}
Android์์ JavaScript ์ฝ๋ ์คํ์ํค๊ธฐ
๋ฐ๋๋ก ์๋๋ก์ด๋์์ webview.evaluateJavascript()
๋ฉ์๋๋ฅผ ํตํด Web์ JavaScript ์ฝ๋๋ฅผ ์คํ์ํฌ ์๋ ์์ต๋๋ค.
webView.evaluateJavascript("javascript:nativeBack()", null)
- ํ์ฌ ๋ก๋๋ ์น ํ์ด์ง์์ JavaScript ์ฝ๋๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์คํํฉ๋๋ค.
resultCallback
์ ๋ฑ๋กํ๋ฉด ์คํ ๊ฒฐ๊ณผ๊ฐ ์ฝ๋ฐฑ์ผ๋ก ๋ฐํ๋ฉ๋๋ค.
- ์์ ์ฝ๋๋ Android์์ ์์คํ
๋ค๋น๊ฒ์ด์
์ ๋ฐฑ๋ฒํผ์ ๋๋ ์ ๋ JavaScript์
nativeBack()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์ฝ๋์ ๋๋ค. - ์๋๋ก์ด๋์์ ํธ์ถํ ๋์๋ WebView์์ ํธํ์ฑ์ ์ํด ๋ฉ์ธ ์ค๋ ๋์์ ์คํํด์ผ ํฉ๋๋ค.
์ด์ ํด๊ฒฐ
- ๋์์ ์ ์ฒด๋ณด๊ธฐ ๋ฒํผ์ ๋๋ฌ ์ ์ฒดํ๋ฉด์ ์ง์
ํ ๋
evaluateJavascript
์ผ๋ก ์น์getVideoDimension()
ํจ์๋ฅผ ํธ์ถํ์ฌ ์ฝ๋ฐฑ์ผ๋ก ์์ ํฌ๊ธฐ๋ฅผ ๋ฐ์์ค๋๋ก ๊ตฌํํ์ต๋๋ค.
Web์ getVideoDimension()
์ฝ๋ ์ผ๋ถ
window.getVideoDimension = function () {
return `${video.width}x${video.height}`;
}
Android
fun isVideoLandscape(onResult: (Boolean) -> Unit) {
webView.evaluateJavascript("javascript:getVideoDimension()") { dimension ->
try {
val (width, height) = dimension.replace("\"", "").split("x").map { it.toIntOrNull() ?: 0 }
onResult(width > height)
} catch (e: Throwable) {
onResult(false)
}
}
}
getVideoDimension()
์ ์ฝ๋ฐฑ์ผ๋ก ์ป์ ์์ ์ฌ์ด์ฆ โwidthxheightโ๋ฅผ ๊ฐ๊ณตํ์ฌ ์์์ ๋ฐฉํฅ์ ํ๋จํฉ๋๋ค.- ์๋ฒ์ ์์ ํฌ๊ธฐ๊ฐ ์ ์ฅ๋์ด ์์ง ์๋ ๋ฑ ์ ํจํ์ง ์์ ๊ฐ์ด ์จ๋ค๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ๋ก๋ก ๋ณด์ฌ์ฃผ๋๋ก ์ฒ๋ฆฌํ์ต๋๋ค.
is InAppBrowserEffect.Web.EnterFullScreen -> {
webViewContainer.isVideoLandscape { isLandscape ->
if (isLandscape) {
(context as Activity).requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
}
- ์ ์ฒดํ๋ฉด ๋ฒํผ์ ๋๋ ์ ๋, ์์ ๊ตฌํํ
isVideoLandscape()
๋ฅผ ํธ์ถํ๊ณ , ๊ฐ๋ก ๋ฐฉํฅ์ ์์์ผ ๊ฒฝ์ฐ ๊ฐ์ ๋ก Activity์ ๋ฐฉํฅ์ ๋ฐ๊พธ์ด ์ฃผ์ด ์์์ด ํ๋ฉด์ ๊ฝ~ ์ฐฐ ์ ์๋๋ก ํด์ฃผ์์ต๋๋ค.
๋ง์น๋ฉฐ
๋น๊ต์ ๊ฐ๋จํ ์ด์์์ง๋ง WebView ๊ฐ๋ฐ ๊ฒฝํ์ด ์๋ ์ ์ Android ๊ฐ๋ฐ์์ธ ์ ์๊ฒ ๊ท์คํ ํ์ต์ ๊ธฐํ์์ต๋๋ค. ์ ํ ๋ชฐ๋๋ WebView์ ์กฐ๊ธ ์ต์ํด์ง ์ ์์๊ณ , ํ๋ก ํธ ํ๊ณผ ๋ฐฑ์๋ ํ๊ณผ์ ํ์ ๋ ๊ฒฝํํด ๋ณผ ์ ์์์ต๋๋ค. ๋ Web๊ณผ Android ๊ฐ ํต์ ์ด ํ์ํ๊ฒ ๋๋ฉด ์ฉ๋์ ๋ง๊ฒ ์ธํฐํ์ด์ค๋ฅผ ์ค๊ณํ ์ ์๋๋ก ํด๋ณด๊ฒ ์ต๋๋ค~