How to load an URL inside a WebView using Android Kotlin?
Here is the complete working code to load a website in android webView
. Just create a new project from the android studio and use the following code to load the web view. Just change the URL you want to load it in the web view.
- It will load a website in the webview
- It will check internet connection availability
- If there is no internet ask the user to enable WiFi from the snack bar message
- Loads the progress until website loads
- Handles the error if something went wrong while loading website
- Handles the back button press cases
- Handles exit from the app confirmation with toast
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/infoTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt:
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.util.Log
import android.view.KeyEvent
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private var progress: Progress? = null
private var isLoaded: Boolean = false
private var doubleBackToExitPressedOnce = false
private var webURL = "https://www.geeklabs.co.in/" // Change it with your URL
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView.settings.javaScriptEnabled = true
if (!isOnline()) {
showToast(getString(R.string.no_internet))
infoTV.text = getString(R.string.no_internet)
showNoNetSnackBar()
return
}
}
override fun onResume() {
if (isOnline() && !isLoaded) loadWebView()
super.onResume()
}
private fun loadWebView() {
infoTV.text = ""
webView.loadUrl(webURL)
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
val url = request?.url.toString()
view?.loadUrl(url)
return super.shouldOverrideUrlLoading(view, request)
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
setProgressDialogVisibility(true)
super.onPageStarted(view, url, favicon)
}
override fun onPageFinished(view: WebView?, url: String?) {
isLoaded = true
setProgressDialogVisibility(false)
super.onPageFinished(view, url)
}
override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) {
isLoaded = false
val errorMessage = "Got Error! $error"
showToast(errorMessage)
infoTV.text = errorMessage
setProgressDialogVisibility(false)
super.onReceivedError(view, request, error)
}
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (webView.canGoBack()) {
webView.goBack()
} else {
showToastToExit()
}
return true
}
}
return super.onKeyDown(keyCode, event)
}
private fun showToastToExit() {
when {
doubleBackToExitPressedOnce -> {
onBackPressed()
}
else -> {
doubleBackToExitPressedOnce = true
showToast(getString(R.string.back_again_to_exit))
Handler(Looper.myLooper()!!).postDelayed({ doubleBackToExitPressedOnce = false }, 2000)
}
}
}
private fun setProgressDialogVisibility(visible: Boolean) {
if (visible) progress = Progress(this, R.string.please_wait, cancelable = true)
progress?.apply { if (visible) show() else dismiss() }
}
private fun isOnline(): Boolean {
val connectivityManager =
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (capabilities != null) {
when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
Log.i("Internet", "NetworkCapabilities.TRANSPORT_CELLULAR")
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
Log.i("Internet", "NetworkCapabilities.TRANSPORT_WIFI")
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
Log.i("Internet", "NetworkCapabilities.TRANSPORT_ETHERNET")
return true
}
}
}
return false
}
private fun showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun showNoNetSnackBar() {
val snack = Snackbar.make(rootView, getString(R.string.no_internet), Snackbar.LENGTH_INDEFINITE)
snack.setAction(getString(R.string.settings)) {
startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
}
snack.show()
}
}
Progress.kt:
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.annotation.StringRes
class Progress constructor(
context: Context?,
@StringRes private val titleRes: Int,
cancelable: Boolean = false
) {
private var view: View? = null
private var builder: AlertDialog.Builder
private var dialog: Dialog
init {
view = LayoutInflater.from(context).inflate(R.layout.progress, null)
view?.findViewById<TextView>(R.id.text)?.setText(titleRes)
builder = AlertDialog.Builder(context)
builder.setView(view)
dialog = builder.create()
dialog.setCancelable(cancelable)
}
fun setProgressMessage(@StringRes titleRes: Int) {
view?.findViewById<TextView>(R.id.text)?.setText(titleRes)
}
fun show() {
dialog.show()
}
fun dismiss() {
if (dialog.isShowing) {
dialog.dismiss()
}
}
fun setProgressDialogVisibility(isVisible: Boolean) {
}
}
pregress.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.SearchResult.Subtitle"
tools:text="Loading" />
</LinearLayout>
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.geeklabs.webviewkotlin">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:fullBackupContent="false"
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=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
strings.xml:
<resources>
<string name="app_name">WebViewKotlin</string>
<string name="please_wait">Please wait…</string>
<string name="no_internet">No internet connection!</string>
<string name="settings">Settings</string>
<string name="back_again_to_exit">Please click BACK again to exit</string>
</resources>
build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.geeklabs.webviewkotlin"
minSdkVersion 23
targetSdkVersion 30
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.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.1.0'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Here is the complete working code in Git hub. Click here to navigate to Git Hub
Add this to your activity:
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_webview)
val mWebView = findViewById<WebView>(R.id.webview)
val webSettings = mWebView.settings
webSettings.javaScriptEnabled = true
mWebView.loadUrl(getString(R.string.website_url))
mWebView.webViewClient = HelloWebViewClient()
WebView.setWebContentsDebuggingEnabled(false)
}
And add the following to the HelloWebViewClient()
class in order to allow back button navigation and to outbound external links:
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
if (Uri.parse(url).host == getString(R.string.website_domain)) {
return false
}
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
return true
}
override fun onPageFinished(view: WebView, url: String) {
// TODO Auto-generated method stub
super.onPageFinished(view, url)
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK && webview.canGoBack()) {
webview.goBack()
return true
}
return super.onKeyDown(keyCode, event)
}
Add strings defining website_domain
(https://stackoverflow.com/) and website_host
(stackoverflow.com).
If you're dealing with difficulties in order to achieve what you're trying, try this full sample and just follow the instructions so as you just need to edit the URL and the clean domain name of your website.
1.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.kotlinwebview.MainActivity">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp" />
</android.support.constraint.ConstraintLayout>
2.MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webview)
webView.settings.setJavaScriptEnabled(true)
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
view?.loadUrl(url)
return true
}
}
webView.loadUrl("https://www.google.co.in/")
}
}