๐ฑ dreaming DiNO
[Kotlin] Webview ์ ๋ฆฌ ๋ณธ๋ฌธ

WebView
- ์น ํ์๊ณผ ์น ๋ธ๋ผ์ฐ์ ๋ Android, iOS, PC ๋ชจ๋ ๊ฐ์ง ๊ธฐ๋ฅ์ ๋๋ค.
- WebView๋ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ๊ตฌ์ฑํ๋ HTML๊ณผ ๊ฐ์ ์์๋ค์ ๋ฐ์๋ค์ฌ ์ด๋ฅผ ๋ธ๋ผ์ฐ์ ์ ๋์ผํ ํ์์ผ๋ก ํด์ํด์ ํํํด์ฃผ๋ ๋ทฐ์ ๋๋ค.
- ๊ทธ๋์ WebView๋ PC์ ์๋ฒ์์ response ํ ์น ํ์ผ์ ๋ฐ์์ Android์์๋ ๋๊ฐ์ด ๋ณด์ฌ์ฃผ๊ณ ๋ค๋ฃฐ ์ ์๊ณ , ๋๋ฐ์ด์ค ์๊ด์์ด ์ ๋ณด ๊ณต์ ๊ฐ ๊ฐ๋ฅํ ํ์ด๋ธ๋ฆฌ๋ ์ฑ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋๋ก ๋์์ค๋๋ค.
URL ์น ํ์ด์ง ์์ฒญ
- ๋จ์ํ WebView๋ฅผ ์ฐธ์กฐํ๊ณ loadUrl๋ก ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์คํํ์ฌ ํด๋น url์ ๋ก๋ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
- loadUrl ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ํด๋น ์ฃผ์์ ์์ฒญ์ ๋ณด๋ด๊ณ , ์๋ต๋ฐ์ html ํ์ผ์ ์ฌ์ฉํ์ฌ ์น ํ๋ฉด์ ํ์ํฉ๋๋ค.
- WebView์ WebViewClient๋ฅผ ์ ๊ณตํจ์ผ๋ก์จ ์น ํ์ด์ง๋ฅผ WebView์ ๋์ธ ์ ์๊ฒ ๋ฉ๋๋ค.
binding.webView.apply {
webViewClient = WebViewClient()
loadUrl("https://www.google.com/")
}

๋ด๋ถ html ์์ฒญ
- ๊ฐ๋ฐ์๊ฐ ๊ฐ์ง html ํ์ผ์ ํ์ํ๋ ค๋ฉด, ์ด ํ์ผ์ด assets ํด๋ ์์ ์กด์ฌํด์ผ ํฉ๋๋ค.
- assets์ resํด๋ ์ฒ๋ผ ๋ฆฌ์์ค๋ฅผ ๋ชจ์๋๋ ๊ณณ์ธ๋ฐ, res์์ ๋ถ๋ฅํ ํ์ ์ธ์ html, css, js ๋ฑ์ ์ฌ์ฉํ ๋์ ์ฌ์ฉํ๋ ํด๋์ ๋๋ค.
- ์๋์ ๊ฐ์ด assets ํด๋ ์์ html ํ์ผ์ ๋ฃ๊ณ loadUrl ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ๋ฌ์ต๋๋ค.

webView.loadUrl("file:///android_asset/www/index.html")
html์ parsingํ์ฌ ๋ณด์ฌ์ฃผ๊ธฐ
- ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ๋ loadUrl() ๋ฉ์๋๋ก html์ parsing ํ์ฌ ํ์ํ ๋ถ๋ถ๋ง ๋ณด์ฌ์ค ์ ์์ต๋๋ค.
- ์ด๋ฌํ ๊ฒฝ์ฐ loadData ๋ฉ์๋๋ loadDataWithBaseURL ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ๋ฉ๋๋ค.
- loadData(String data, String mimeType, String encoding) -> data : encoding์ผ๋ก ์์ฑ๋ data๋ html ์ฝ๋๋ฅผ string ํํ๋ก ๋ฃ์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค. mimeType : ๋ฌธ์์ ๋ค์์ฑ์ ์๋ ค์ฃผ๊ธฐ ์ํจ์ผ๋ก "text/html" ๋ฑ์ ๊ฐ์ ๊ฐ์ง ์ ์์ต๋๋ค. encoding : data๊ฐ ์ด๋ค ํํ์ encoding์ผ๋ก ์์ฑ๋์๋์ง ์๋ ค์ค๋๋ค.
- ํ์ง๋ง, loadData ๋ฉ์๋๋ network ์์ content๋ฅผ WebView์ ๋ณด์ฌ์ค ์ ์์ต๋๋ค. ์ฆ html ๋ด์ฉ ์ค ์๋ ๊ฒฝ๋ก๋ก ์๋ ์คํ์ผ์ด๋ ์ด๋ฏธ์ง ๋ฑ์ ๋ชป ๊ฐ์ ธ์ค๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
- ์๋ฅผ ๋ค์ด <link="stylesheet" href="/Content/Css/main.css?2016011909href="/Content/Css/main.css? 2016011909" /> ์ด๋ฐ css๊ฐ ์๋ค๊ณ ํ๋ฉด /Content ํด๋๊ฐ ์ด๋ ๊ฒฝ๋ก๋ฅผ ๊ธฐ์ ์ธ์ง ์ ์๊ฐ ์์ด loadDataWithBaseUrl์ ์ฌ์ฉํ์ฌ ํด๊ฒฐํฉ๋๋ค.
- loadDataWithURL(String baseUrl, String data, String mimeType, String encoding, String histroyUrl) -> baseUrl : ์๋ ๊ฒฝ๋ก๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ์ฉ๋จ. historyUrl : histroy entry๋ก ์ฌ์ฉ๋จ.
loadData(url, "text/html; charset=utf-8", "UTF-8")
loadDataWithBaseURL(null, url, "text/html; charset=utf-8", "UTF-8", null)
java script ์ฐ๋ (์ฑ -> ์น๋ทฐ JavaScript ํธ์ถ)
- ์น ๋ธ๋ผ์ฐ์ ๋ java script๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ๋จ์ํ ๋ฐ์์จ ์ฝ๋๋ฅผ ํด์ํ๋ ๊ฒ์ ๋ฌธ์ ๊ฐ ์์์ง ๋ชฐ๋ผ๋, ํ๋ฉด์ ํ์๋๋ ์น ํ์ด์ง์ ์๋๋ก์ด๋ ์ฝ๋๊ฐ ์ ๊ธฐ์ ์ผ๋ก ๋์ํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
- ํ์ง๋ง, ์ด๋ฅผ ์ง์ํด์ฃผ๋ api๊ฐ ์กด์ฌํฉ๋๋ค.
- loadUrl ๋ฉ์๋์ java script์ ํจ์๋ช ์ ์ ์ด์ฃผ์ด, ์ ์๋ ํจ์๋ฅผ ์คํ์ํฌ ์ ์์ต๋๋ค.
- ์ฑ์ ๋์์ ์ฐ๋ํ์ฌ java script์ ์ด๋ ํ ๋์์ ํ๋๋ก ์ด๋ฒคํธ๋ฅผ ๊ฑธ ๋ ์ฌ์ฉํ๋ฉด ์ข์ต๋๋ค.
webView.loadUrl("javascript:alerthello()")
WebView์ ์ฑ ํต์ (์น๋ทฐ -> ์ฑ ์ฝ๋ ํธ์ถ)
- WebView๋ ๋ณด์์์ ์ด์ ๋ก ๋๋ฐ์ด์ค ์์์ 100% ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ณดํต ์๋๋ก์ด๋๋ ๋๋ฐ์ด์ค ์ ์ผ ๊ฐ์ผ๋ก Android Id๋ฅผ ์ฌ์ฉํ๋๋ฐ ๋๋ฐ์ด์ค ์์ญ์ผ๋ก ์น๋ทฐ์์ ๋ฐ๋ก ์ ๊ทผํ์ฌ ์ถ์ถํ ์ ์์ต๋๋ค.
- ํ์ง๋ง, ๋ค์ดํฐ๋ธ์์๋ ํด๋น ๊ฐ์ ์์ ๋กญ๊ฒ ์ถ์ถ ๊ฐ๋ฅํฉ๋๋ค. ์ด์ ๊ฐ์ ๊ฒฝ์ฐ ์น๋ทฐ์ ๋ค์ดํฐ๋ธ์ ์ฐ๋์ ํตํด ๊ฐ์ ์ ๋ฌํฉ๋๋ค.
- ๋ณธ ์ฐ๋๋ฐฉ์์ ์๋๋ก์ด๋ OS 4.1 JELLY_BEAN ์ดํ ๋๋ฐ์ด์ค์์๋ ๋ณด์์ ๋ฌธ์ ๊ฐ ์์ด, ์๋๋ก์ด๋ OS 4.2 ์ด์์์ ์ฌ์ฉ์ ๊ถ์ฅํ๊ณ ์์ต๋๋ค. ์๋๋ก์ด๋ OS 4.1 ์ดํ์์๋ @JavaScriptinterface ์ด๋ ธํ ์ด์ ์ด ๋์ํ์ง ์์ต๋๋ค.

- JavaScript์์ ๋ค์ดํฐ๋ธ ์ฝ๋ ํธ์ถ -> ๋ค์ดํฐ๋ธ ์ฝ๋๊ฐ JavaScriptInterface ์ด๋ ธํ ์ด์ ์ด ์ง์ ๋์๋์ง ํ์ธํ๊ณ ์ง์ ๋์ด ์์ผ๋ฉด ๋ค์ดํฐ๋ธ ๋ฉ์๋๋ฅผ ์คํ -> ๋ค์ดํฐ๋ธ ๋ฉ์๋์ ์คํ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ.

- evaluteJavascript๋ฅผ ํตํด JavaScript ํธ์ถ -> ์คํ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ.
์น๋ทฐ์์ ์ฑ ์ฝ๋๋ฅผ ํธ์ถํ๋ ์์ ๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
- assets ํด๋์ html ํ์ผ์ ๋ง๋ค์ด์ค๋๋ค. ์๋๋ก์ด๋์์ ์ ์ธํ ํจ์๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
<input type="button" value="WebView Test" onClick="showAndroidToast('Connection Success!')"/>
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
- @JavascriptInterface ํจ์ ์์ฑ.
webview.settings.javaScriptEnabled = true
webview.addJavascriptInterface(WebAppInterface(this), "Android")
webview.loadUrl("file:///android_asset/www/index.html")
/** Instantiate the interface and set the context */
class WebAppInterface(private val mContext: Context) {
/** Show a toast from the web page */
@JavascriptInterface
fun showToast(toast: String) =
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()
}
Full Screen Issue
- HTML video ํ๊ทธ ํน์ ๋น๋์ค ์ ์ฒด ํ๋ฉด ๋ฒํผ ์์ฒด๊ฐ ๋ณด์ด์ง ์์ ๋, ๋ํ ์ ์ฒดํ๋ฉด ๋ชจ๋์์ ๊ฐ๋ก๋ชจ๋๋ก ํ๋ ์ด๋์ง ์์ ๋.
WebView Settings
binding.webView.settings.apply {
setSupportMultipleWindows(false) // ์์ฐฝ ๋์ฐ๊ธฐ ํ์ฉ
setSupportZoom(false) // ํ๋ฉด ํ๋ ํ์ฉ
javaScriptEnabled = true // ์๋ฐ์คํฌ๋ฆฝํธ ํ์ฉ
javaScriptCanOpenWindowsAutomatically = false // ์๋ฐ์คํฌ๋ฆฝํธ ์์ฐฝ ๋์ฐ๊ธฐ ํ์ฉ
loadWithOverviewMode = true // html์ ์ปจํ
์ธ ๊ฐ ์น๋ทฐ๋ณด๋ค ํด ๊ฒฝ์ฐ ์คํฌ๋ฆฐ ํฌ๊ธฐ์ ๋ง๊ฒ ์กฐ์
useWideViewPort = true // html์ viewport ๋ฉํ ํ๊ทธ ์ง์
builtInZoomControls = false // ๊ธฐ๋ณธ์ ์ผ๋ก ์ค ๊ธฐ๋ฅ์ด ๋์ง ์์ต๋๋ค.
displayZoomControls = false // ํ๋ฉด ํ๋/์ถ์ ํ์ฉ
layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN // ์ปจํ
์ธ ์ฌ์ด์ฆ ๋ง์ถ๊ธฐ
cacheMode = WebSettings.LOAD_NO_CACHE // ๋ธ๋ผ์ฐ์ ์บ์ฌ ํ์ฉ
domStorageEnabled = true // ๋ก์ปฌ ์ ์ฅ ํ์ฉ
databaseEnabled = true
/**
* * This request has been blocked; the content must be served over HTTPS
* * https ์์ ์ด๋ฏธ์ง๊ฐ ํ์ ์๋๋ ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ฒ๋ฆฌ
* */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
}
binding.webView.apply {
webViewClient = WebViewClient() // WebView ์์ ฏ์ ์ฌ์ฉํด ์ฌ๋ฌ ๊ธฐ๋ฅ ์ฌ์ฉ
webChromeClient = WebChromeClient() // ๋ธ๋ผ์ฐ์ ํฌ๋กฌ์ ํนํ
}