Notice
Recent Posts
Recent Comments
Link
ยซ   2024/10   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐ŸŒฑ dreaming DiNO

[Kotlin] Webview ์ •๋ฆฌ ๋ณธ๋ฌธ

Android

[Kotlin] Webview ์ •๋ฆฌ

MK_____ 2023. 4. 3. 10:46

 

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์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
  • JavaScript์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ ํ˜ธ์ถœ -> ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ๊ฐ€ JavaScriptInterface ์–ด๋…ธํ…Œ์ด์…˜์ด ์ง€์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ง€์ •๋˜์–ด ์žˆ์œผ๋ฉด ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ -> ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ์˜ ์‹คํ–‰๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜.

 

๋„ค์ดํ‹ฐ๋ธŒ์—์„œ JavaScript ํ˜ธ์ถœ
  • 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() // ๋ธŒ๋ผ์šฐ์ € ํฌ๋กฌ์— ํŠนํ™”
       }