[android : kotlin] 코틀린 웹뷰(WebView) 사용 설정 방법 및 예제 총정리
WebView의 사용법에 대해 알아봅니다. WebView는 앱내에서 웹페이지를 표시하는데 사용됩니다.
코틀린 웹뷰(WebView) 사용 설정
웹뷰(WebView)를 사용하려면 제일 먼저 인터넷 권한을 AndroidMenifest.xml 파일에 추가해야합니다.
<uses-permission android:name="android.permission.INTERNET" />
[AndroidMenifest.xml]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="edu.kotlin.study">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity3"></activity>
<activity android:name=".MainActivity2" />
<activity android:name=".AnotherActivity" />
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustPan|adjustUnspecified">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
다음으로 레이아웃에 WebVew를 추가합니다. 웹뷰를 불러오는 동안 로딩바를 추가하기 위해 ProgressBar를 하나 추가합니다.
[activity_main.xml]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webView1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/progress1"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
가장심플한 방법으로 웹뷰를 코드 두줄로 호출할 수 있습니다. 하지만 많은 기능의 제약이 있습니다. loadUrl()메서드를 사용하여 웹사이트를 호출할 수 있습니다.
val webView: WebView = findViewById(R.id.webView1)
webView.loadUrl("https://ddolcat.tistory.com/")
웹뷰를 제대로 활용하기 위해서는 apply() 메서드를 사용하여 웹뷰에 필요한 설정을 진행합니다. webViewClient와 webChromeClient 역시 활용해야합니다.
[MainActivity.kt]
package edu.kotlin.study
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Bitmap
import android.media.MediaPlayer
import android.net.http.SslError
import android.os.Build
import android.os.Bundle
import android.os.Message
import android.view.View
import android.view.ViewGroup
import android.webkit.*
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
private lateinit var mProgressBar: ProgressBar
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webView1)
mProgressBar = findViewById(R.id.progress1)
webView.apply {
webViewClient = WebViewClientClass() // new WebViewClient()); //클릭시 새창 안뜨게
//팝업이나 파일 업로드 등 설정해주기 위해 webView.webChromeClient를 설정
//웹뷰에서 크롬이 실행가능&& 새창띄우기는 안됨
//webChromeClient = WebChromeClient()
//웹뷰에서 팝업창 호출하기 위해
webChromeClient = object : WebChromeClient() {
override fun onCreateWindow(view: WebView?, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message?): Boolean {
val newWebView = WebView(this@MainActivity).apply {
webViewClient = WebViewClient()
settings.javaScriptEnabled = true
}
val dialog = Dialog(this@MainActivity).apply {
setContentView(newWebView)
window!!.attributes.width = ViewGroup.LayoutParams.MATCH_PARENT
window!!.attributes.height = ViewGroup.LayoutParams.MATCH_PARENT
show()
}
newWebView.webChromeClient = object : WebChromeClient() {
override fun onCloseWindow(window: WebView?) {
dialog.dismiss()
}
}
(resultMsg?.obj as WebView.WebViewTransport).webView = newWebView
resultMsg.sendToTarget()
return true
}
}
settings.javaScriptEnabled = true
settings.setSupportMultipleWindows(true) // 새창띄우기 허용여부
settings.javaScriptCanOpenWindowsAutomatically = true // 자바스크립트 새창뛰우기 (멀티뷰) 허용여부
settings.loadWithOverviewMode = true //메타태크 허용여부
settings.useWideViewPort = true //화면 사이즈 맞추기 허용여부
settings.setSupportZoom(true) //화면 줌 허용여부
settings.builtInZoomControls = true //화면 확대 축소 허용여부
// Enable and setup web view cache
settings.cacheMode =
WebSettings.LOAD_NO_CACHE //브라우저 캐시 허용여부 // WebSettings.LOAD_DEFAULT
settings.domStorageEnabled = true //로컬저장소 허용여부
settings.displayZoomControls = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings.safeBrowsingEnabled = true // api 26
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
settings.mediaPlaybackRequiresUserGesture = false
}
settings.allowContentAccess = true
settings.setGeolocationEnabled(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
settings.allowUniversalAccessFromFileURLs = true
}
settings.allowFileAccess = true
//settings.loadsImagesAutomatically = true
fitsSystemWindows = true
}
val url = "https://ddolcat.tistory.com/"
webView.loadUrl(url)
//
// //프로그레스 다이얼로그
// btn5.setOnClickListener {
//
// val progressBar = ProgressBar(this, null, android.R.attr.progressBarStyleLarge)
// var params = RelativeLayout.LayoutParams(100, 100)
// params.addRule(RelativeLayout.CENTER_IN_PARENT)
// main_layout.addView(progressBar, params)
//
// // 핸들러를 통해서 종료 작업을 한다.
//// var handler = Handler()
//// var thread = Runnable { pro?.cancel() }
//// handler.postDelayed(thread, 5000) // 딜레이는 5초
// }
}
//웹뷰에서 홈페이지를 띄웠을때 새창이 아닌 기존창에서 실행이 되도록 아래 코드를 넣어준다.
inner class WebViewClientClass : WebViewClient() {
//페이지 이동
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return true
}
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
mProgressBar.visibility = ProgressBar.VISIBLE
webView.visibility = View.INVISIBLE
}
override fun onPageCommitVisible(view: WebView, url: String) {
super.onPageCommitVisible(view, url)
mProgressBar.visibility = ProgressBar.GONE
webView.visibility = View.VISIBLE
}
override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) {
var builder: android.app.AlertDialog.Builder =
android.app.AlertDialog.Builder(this@MainActivity)
var message = "SSL Certificate error."
when (error.primaryError) {
SslError.SSL_UNTRUSTED -> message = "The certificate authority is not trusted."
SslError.SSL_EXPIRED -> message = "The certificate has expired."
SslError.SSL_IDMISMATCH -> message = "The certificate Hostname mismatch."
SslError.SSL_NOTYETVALID -> message = "The certificate is not yet valid."
}
message += " Do you want to continue anyway?"
builder.setTitle("SSL Certificate Error")
builder.setMessage(message)
builder.setPositiveButton("continue",
DialogInterface.OnClickListener { _, _ -> handler.proceed() })
builder.setNegativeButton("cancel",
DialogInterface.OnClickListener { dialog, which -> handler.cancel() })
val dialog: android.app.AlertDialog? = builder.create()
dialog?.show()
}
}
}
■HTML 문자열을 로드하는 방법은 loadData()메서드를 사용합니다.
val tempHtml = "<html><body><h1>또 다른 세계</h1>" +
"<h1>안녕</h1><h2>만나서 방갑습니다.</h2><h3>오늘은 금요일입니다.</h3>" +
"<p>웹뷰 사용법에 대해 알아보고 있습니다.</p>" +
"</body></html>"
webView.loadData(tempHtml, "text/html", "UTF-8")
webView.loadDataWithBaseURL(null, tempHtml, "text/html", "utf-8", null)
■웹뷰 히스토리를 이용하여 이전페이지와 앞페이지 이동을 할 수 있습니다. 레이아웃에 버튼 두개를 추가하였습니다.
그리고 모든 히스토리를 삭제할 수 있습니다. clearHistory()메서드를 사용하여 삭제합니다.
webView.clearHistory()
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btm_layout"/>
<ProgressBar
android:id="@+id/progress1"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/btm_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<Button
android:id="@+id/previos_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="이전페이지" />
<Button
android:id="@+id/next_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="다음 페이지" />
</LinearLayout>
</RelativeLayout>
웹뷰의 canGoBack()메서드와 canGoForward()메서드를 사용하여 true값이 반환되면 goBack()메서드를 사용하여 이전 페이지로 돌아갈 수 있습니다. goForward()메서드를 사용하여 앞 페이지로 갈 수 있습니다.
previos_btn.setOnClickListener {
val canGoBack: Boolean = webView.canGoBack()
if (canGoBack) {
webView.goBack()
}
}
next_btn.setOnClickListener {
val canGoForward: Boolean = webView.canGoForward()
if (canGoForward) {
webView.goForward()
}
}
■로컬에 있는 html파일을 웹뷰에 보여주는 방법은 loadURL()메서드를 사용합니다.
webView.loadUrl("file:///android_asset/" + "test_sample.html")
assets폴더를 생성하는 방법은 아래글을 확인하세요.
[프로그래밍/Android Studio] – [Android] assets 폴더(folder)를 생성하는 방법: HTML , JSON파일용
■TextView에 HTML문자열을 값으로 설정하고 싶은 경우에는 Html.fromHtml()메서드를 활용합니다.
val tempHtml = "<html><body><h1>또 다른 세계</h1>" +
"<h1>안녕</h1><h2>만나서 방갑습니다.</h2><h3>오늘은 금요일입니다.</h3>" +
"<p>웹뷰 사용법에 대해 알아보고 있습니다.</p>" +
"</body></html>"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textView1.text = Html.fromHtml(tempHtml, Html.FROM_HTML_MODE_LEGACY)
} else {
textView1.text = Html.fromHtml(tempHtml)
}
[build.gradle(Module:app)]
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
defaultConfig {
applicationId "edu.kotlin.study"
minSdkVersion 22
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
[build.gradle(Project)]
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.3.72"
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
[REFERENCE]
프로그래밍/Android] – [Android] WebView 웹뷰에서 PDF 불러오는 방법
m.blog.naver.com/hando1220/221884820467
developer.android.com/reference/kotlin/android/webkit/WebView
[연관 글]

