[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
[연관 글]