From 6821c5b3f3f6fb9e8a3d1164df59238e43c8e200 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 1 Oct 2020 17:55:41 +0300 Subject: [PATCH 1/7] first version --- views/build.gradle | 6 + .../views/widget/web_view/BaseWebView.kt | 117 ++++++++++++++++++ .../widget/web_view/BaseWebViewClient.kt | 67 ++++++++++ .../views/widget/web_view/CustomWebView.kt | 31 +++++ .../views/widget/web_view/WebViewCallback.kt | 9 ++ views/src/main/res/layout/base_web_view.xml | 53 ++++++++ views/src/main/res/values/attrs.xml | 10 ++ 7 files changed, 293 insertions(+) create mode 100644 views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt create mode 100644 views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt create mode 100644 views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt create mode 100644 views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt create mode 100644 views/src/main/res/layout/base_web_view.xml diff --git a/views/build.gradle b/views/build.gradle index e76deb5..c948de1 100644 --- a/views/build.gradle +++ b/views/build.gradle @@ -13,6 +13,7 @@ dependencies { implementation project(":logging") implementation "com.google.android.material:material" + implementation "androidx.constraintlayout:constraintlayout" implementation "androidx.core:core-ktx" constraints { @@ -21,6 +22,11 @@ dependencies { require '1.0.0' } } + implementation("androidx.constraintlayout:constraintlayout") { + version { + require '2.0.0-beta4' + } + } implementation("androidx.core:core-ktx") { version { require '1.3.1' diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt new file mode 100644 index 0000000..4954ed8 --- /dev/null +++ b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt @@ -0,0 +1,117 @@ +package ru.touchin.roboswag.views.widget.web_view + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.webkit.WebView +import androidx.core.content.withStyledAttributes +import androidx.core.widget.TextViewCompat +import ru.touchin.extensions.setOnRippleClickListener +import ru.touchin.roboswag.components.utils.UiUtils +import ru.touchin.roboswag.views.R +import ru.touchin.roboswag.views.databinding.BaseWebViewBinding +import ru.touchin.roboswag.views.widget.Switcher + +open class BaseWebView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int = 0 +) : Switcher(context, attrs), WebViewCallback { + + private val binding = BaseWebViewBinding.inflate(LayoutInflater.from(context), this) + + var onWebViewLoaded: (() -> Unit)? = null + var onWebViewRepeatButtonClicked: (() -> Unit)? = null + var onWebViewScrolled: ((WebView, Int, Int) -> Unit)? = null + + init { + binding.apply { + context.withStyledAttributes(attrs, R.styleable.BaseWebView, defStyleAttr, 0) { + if (hasValue(R.styleable.BaseWebView_errorTextAppearance)) { + TextViewCompat.setTextAppearance(errorText, getResourceId(R.styleable.BaseWebView_errorTextAppearance, 0)) + } + if (hasValue(R.styleable.BaseWebView_repeatButtonTextAppearance)) { + TextViewCompat.setTextAppearance(errorRepeatButton, getResourceId(R.styleable.BaseWebView_repeatButtonTextAppearance, 0)) + } + if (hasValue(R.styleable.BaseWebView_progressBarTintColor)) { + progressBar.indeterminateTintList = ColorStateList.valueOf(getColor(R.styleable.BaseWebView_progressBarTintColor, Color.BLACK)) + } + if (hasValue(R.styleable.BaseWebView_repeatButtonBackground)) { + errorRepeatButton.setBackgroundResource(getResourceId(R.styleable.BaseWebView_repeatButtonBackground, 0)) + } + if (hasValue(R.styleable.BaseWebView_screenBackground)) { + setBackgroundResource(getResourceId(R.styleable.BaseWebView_screenBackground, 0)) + } + if (hasValue(R.styleable.BaseWebView_errorText)) { + errorText.text = getString(R.styleable.BaseWebView_errorText) + } + if (hasValue(R.styleable.BaseWebView_repeatButtonText)) { + errorRepeatButton.text = getString(R.styleable.BaseWebView_repeatButtonText) + } + } + + errorRepeatButton.setOnRippleClickListener { + onWebViewRepeatButtonClicked?.invoke() + } + } + } + + init { + binding.webView.onScrollChanged = { scrollX, scrollY, _, _ -> + onWebViewScrolled?.invoke(binding.webView, scrollX, scrollY) + } + setWebViewPreferences() + } + + override fun onStateChanged(newState: WebViewLoadingState) { + when (newState) { + WebViewLoadingState.LOADED -> { + onWebViewLoaded?.invoke() + showChild(R.id.web_view) + } + WebViewLoadingState.LOADING -> { + showChild(R.id.progress_bar) + } + WebViewLoadingState.ERROR -> { + showChild(R.id.error_layout) + } + } + } + + fun setBaseWebViewClient() { + binding.webView.webViewClient = BaseWebViewClient(this) + } + + fun getWebView() = binding.webView + + fun loadUrl(url: String?) { + binding.webView.loadUrl(url) + } + + fun setState(newState: WebViewLoadingState) { + onStateChanged(newState) + } + + fun setOnWebViewDisplayedContentAction(action: () -> Unit) { + binding.webView.onWebViewDisplayedContent = action + } + + @SuppressLint("SetJavaScriptEnabled") + open fun setWebViewPreferences() { + binding.webView.apply { + scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY + setLayerType(View.LAYER_TYPE_SOFTWARE, null) + with(settings) { + loadsImagesAutomatically = true + javaScriptEnabled = true + domStorageEnabled = true + loadWithOverviewMode = true + } + } + } + +} diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt new file mode 100644 index 0000000..e73c2d9 --- /dev/null +++ b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt @@ -0,0 +1,67 @@ +package ru.touchin.roboswag.views.widget.web_view + +import android.graphics.Bitmap +import android.net.http.SslError +import android.os.Handler +import android.os.Looper +import android.webkit.SslErrorHandler +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.core.os.postDelayed + +open class BaseWebViewClient(private val callback: WebViewCallback) : WebViewClient() { + + companion object { + private const val WEB_VIEW_TIMEOUT_MS = 30 * 1000L // 30 sec + } + + private var isError = false + private var isTimeout = true + + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + isError = false + callback.onStateChanged(WebViewLoadingState.LOADING) + + Looper.myLooper()?.let { looper -> + val handler = Handler(looper) + handler.postDelayed(WEB_VIEW_TIMEOUT_MS) { + if (isTimeout) { + isError = true + pageFinished() + } + isTimeout = true + } + } + } + + override fun onPageFinished(view: WebView, url: String) { + super.onPageFinished(view, url) + isTimeout = false + pageFinished() + } + + override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { + handler.proceed() + } + + override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) { + if (!(error.errorCode == -10 && "about:blank" == request.url.toString())) { + isError = true + } + pageFinished() + } + + private fun pageFinished() { + callback.onStateChanged(if (isError) WebViewLoadingState.ERROR else WebViewLoadingState.LOADED) + } + +} + +enum class WebViewLoadingState { + LOADING, + ERROR, + LOADED +} \ No newline at end of file diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt new file mode 100644 index 0000000..cbb1bfb --- /dev/null +++ b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt @@ -0,0 +1,31 @@ +package ru.touchin.roboswag.views.widget.web_view + +import android.content.Context +import android.util.AttributeSet +import android.webkit.WebView + +class CustomWebView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int = 0 +) : WebView(context, attrs, defStyleAttr) { + + var onWebViewDisplayedContent: (() -> Unit)? = null + var onScrollChanged: ((Int, Int, Int, Int) -> Unit)? = null + + // https://stackoverflow.com/a/14678910 + override fun invalidate() { + super.invalidate() + + if (contentHeight > 0) { + onWebViewDisplayedContent?.invoke() + } + + } + + override fun onScrollChanged(scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) { + super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY) + onScrollChanged?.invoke(scrollX, scrollY, oldScrollX, oldScrollY) + } + +} diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt new file mode 100644 index 0000000..1e26e8d --- /dev/null +++ b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt @@ -0,0 +1,9 @@ +package ru.touchin.roboswag.views.widget.web_view + +import ru.touchin.roboswag.views.widget.web_view.WebViewLoadingState + +interface WebViewCallback { + + fun onStateChanged(newState: WebViewLoadingState) + +} \ No newline at end of file diff --git a/views/src/main/res/layout/base_web_view.xml b/views/src/main/res/layout/base_web_view.xml new file mode 100644 index 0000000..30e21fc --- /dev/null +++ b/views/src/main/res/layout/base_web_view.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + diff --git a/views/src/main/res/values/attrs.xml b/views/src/main/res/values/attrs.xml index bf3eacc..ccd6736 100644 --- a/views/src/main/res/values/attrs.xml +++ b/views/src/main/res/values/attrs.xml @@ -34,4 +34,14 @@ + + + + + + + + + + From 2fc1dcc3a1e493c3d8658052f9bfbf151cb2b344 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 1 Oct 2020 18:30:15 +0300 Subject: [PATCH 2/7] move to another module --- README.md | 1 + .../views/widget/web_view/WebViewCallback.kt | 9 ---- views/src/main/res/values/attrs.xml | 10 ----- webview/.gitignore | 1 + webview/build.gradle | 44 +++++++++++++++++++ webview/src/main/AndroidManifest.xml | 2 + .../roboswag/webview}/web_view/BaseWebView.kt | 7 ++- .../webview}/web_view/BaseWebViewClient.kt | 2 +- .../webview}/web_view/CustomWebView.kt | 2 +- .../webview/web_view/WebViewCallback.kt | 7 +++ .../src/main/res/layout/base_web_view.xml | 3 +- webview/src/main/res/values/attrs.xml | 14 ++++++ webview/src/main/res/values/styles.xml | 3 ++ 13 files changed, 78 insertions(+), 27 deletions(-) delete mode 100644 views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt create mode 100644 webview/.gitignore create mode 100644 webview/build.gradle create mode 100644 webview/src/main/AndroidManifest.xml rename {views/src/main/java/ru/touchin/roboswag/views/widget => webview/src/main/java/ru/touchin/roboswag/webview}/web_view/BaseWebView.kt (95%) rename {views/src/main/java/ru/touchin/roboswag/views/widget => webview/src/main/java/ru/touchin/roboswag/webview}/web_view/BaseWebViewClient.kt (97%) rename {views/src/main/java/ru/touchin/roboswag/views/widget => webview/src/main/java/ru/touchin/roboswag/webview}/web_view/CustomWebView.kt (94%) create mode 100644 webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt rename {views => webview}/src/main/res/layout/base_web_view.xml (94%) create mode 100644 webview/src/main/res/values/attrs.xml create mode 100644 webview/src/main/res/values/styles.xml diff --git a/README.md b/README.md index f48dec0..d1f42a6 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ gradle.ext.roboswag = [ 'base-map', 'yandex-map', 'google-map', + 'webview', 'encrypted-shared-prefs' ] diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt b/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt deleted file mode 100644 index 1e26e8d..0000000 --- a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/WebViewCallback.kt +++ /dev/null @@ -1,9 +0,0 @@ -package ru.touchin.roboswag.views.widget.web_view - -import ru.touchin.roboswag.views.widget.web_view.WebViewLoadingState - -interface WebViewCallback { - - fun onStateChanged(newState: WebViewLoadingState) - -} \ No newline at end of file diff --git a/views/src/main/res/values/attrs.xml b/views/src/main/res/values/attrs.xml index ccd6736..bf3eacc 100644 --- a/views/src/main/res/values/attrs.xml +++ b/views/src/main/res/values/attrs.xml @@ -34,14 +34,4 @@ - - - - - - - - - - diff --git a/webview/.gitignore b/webview/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/webview/.gitignore @@ -0,0 +1 @@ +/build diff --git a/webview/build.gradle b/webview/build.gradle new file mode 100644 index 0000000..5b4bd46 --- /dev/null +++ b/webview/build.gradle @@ -0,0 +1,44 @@ +apply from: "../android-configs/lib-config.gradle" +apply plugin: 'kotlin-android' + +android { + buildFeatures { + viewBinding true + } +} + +dependencies { + implementation project(":views") + implementation project(":kotlin-extensions") + + implementation "com.google.android.material:material" + implementation "androidx.constraintlayout:constraintlayout" + implementation "androidx.core:core-ktx" + + constraints { + implementation("com.google.android.material:material") { + version { + require '1.0.0' + } + } + implementation("androidx.constraintlayout:constraintlayout") { + version { + require '2.0.0-beta4' + } + } + implementation("androidx.core:core-ktx") { + version { + require '1.3.1' + } + } + implementation("org.jetbrains.kotlin:kotlin-stdlib") { + version { + require '1.3.0' + } + } + } +} + +repositories { + mavenCentral() +} diff --git a/webview/src/main/AndroidManifest.xml b/webview/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9157adb --- /dev/null +++ b/webview/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt similarity index 95% rename from views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt rename to webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt index 4954ed8..404bf15 100644 --- a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebView.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt @@ -1,4 +1,4 @@ -package ru.touchin.roboswag.views.widget.web_view +package ru.touchin.roboswag.webview.web_view import android.annotation.SuppressLint import android.content.Context @@ -11,10 +11,9 @@ import android.webkit.WebView import androidx.core.content.withStyledAttributes import androidx.core.widget.TextViewCompat import ru.touchin.extensions.setOnRippleClickListener -import ru.touchin.roboswag.components.utils.UiUtils -import ru.touchin.roboswag.views.R -import ru.touchin.roboswag.views.databinding.BaseWebViewBinding import ru.touchin.roboswag.views.widget.Switcher +import ru.touchin.roboswag.webview.R +import ru.touchin.roboswag.webview.databinding.BaseWebViewBinding open class BaseWebView @JvmOverloads constructor( context: Context, diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt similarity index 97% rename from views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt rename to webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt index e73c2d9..38546d3 100644 --- a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/BaseWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt @@ -1,4 +1,4 @@ -package ru.touchin.roboswag.views.widget.web_view +package ru.touchin.roboswag.webview.web_view import android.graphics.Bitmap import android.net.http.SslError diff --git a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/CustomWebView.kt similarity index 94% rename from views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt rename to webview/src/main/java/ru/touchin/roboswag/webview/web_view/CustomWebView.kt index cbb1bfb..72a4a4e 100644 --- a/views/src/main/java/ru/touchin/roboswag/views/widget/web_view/CustomWebView.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/CustomWebView.kt @@ -1,4 +1,4 @@ -package ru.touchin.roboswag.views.widget.web_view +package ru.touchin.roboswag.webview.web_view import android.content.Context import android.util.AttributeSet diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt new file mode 100644 index 0000000..d12e5bf --- /dev/null +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt @@ -0,0 +1,7 @@ +package ru.touchin.roboswag.webview.web_view + +interface WebViewCallback { + + fun onStateChanged(newState: WebViewLoadingState) + +} \ No newline at end of file diff --git a/views/src/main/res/layout/base_web_view.xml b/webview/src/main/res/layout/base_web_view.xml similarity index 94% rename from views/src/main/res/layout/base_web_view.xml rename to webview/src/main/res/layout/base_web_view.xml index 30e21fc..0576588 100644 --- a/views/src/main/res/layout/base_web_view.xml +++ b/webview/src/main/res/layout/base_web_view.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + + + + + + + + + + + + + diff --git a/webview/src/main/res/values/styles.xml b/webview/src/main/res/values/styles.xml new file mode 100644 index 0000000..045e125 --- /dev/null +++ b/webview/src/main/res/values/styles.xml @@ -0,0 +1,3 @@ + + + From b83ce309e5f8863f65af89ef743488130a5ed802 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 1 Oct 2020 18:31:30 +0300 Subject: [PATCH 3/7] clean --- views/build.gradle | 6 ------ webview/src/main/res/values/styles.xml | 3 --- 2 files changed, 9 deletions(-) delete mode 100644 webview/src/main/res/values/styles.xml diff --git a/views/build.gradle b/views/build.gradle index c948de1..e76deb5 100644 --- a/views/build.gradle +++ b/views/build.gradle @@ -13,7 +13,6 @@ dependencies { implementation project(":logging") implementation "com.google.android.material:material" - implementation "androidx.constraintlayout:constraintlayout" implementation "androidx.core:core-ktx" constraints { @@ -22,11 +21,6 @@ dependencies { require '1.0.0' } } - implementation("androidx.constraintlayout:constraintlayout") { - version { - require '2.0.0-beta4' - } - } implementation("androidx.core:core-ktx") { version { require '1.3.1' diff --git a/webview/src/main/res/values/styles.xml b/webview/src/main/res/values/styles.xml deleted file mode 100644 index 045e125..0000000 --- a/webview/src/main/res/values/styles.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - From 2a3f794819530653913e8190974c462cfc5f893b Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 15 Oct 2020 18:46:02 +0300 Subject: [PATCH 4/7] pull to refresh, alert --- .../web_view/BaseChromeWebViewClient.kt | 41 +++++++++++++++++++ .../roboswag/webview/web_view/BaseWebView.kt | 31 +++++++++++--- .../webview/web_view/BaseWebViewClient.kt | 2 +- .../webview/web_view/WebViewCallback.kt | 2 +- webview/src/main/res/layout/base_web_view.xml | 18 +++++--- 5 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt new file mode 100644 index 0000000..13754f9 --- /dev/null +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt @@ -0,0 +1,41 @@ +package ru.touchin.roboswag.webview.web_view + +import android.webkit.ConsoleMessage +import android.webkit.JsPromptResult +import android.webkit.JsResult +import android.webkit.WebChromeClient +import android.webkit.WebView + +open class BaseChromeWebViewClient( + private val onJsConfirm: (() -> Unit)? = null, + private val onJsAlert: (() -> Unit)? = null, + private val onJsPrompt: ((String?) -> Unit)? = null, + private val onJsError: ((error: ConsoleMessage) -> Unit)? = null +) : WebChromeClient() { + + override fun onJsConfirm(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean { + onJsConfirm?.invoke() + result?.confirm() + return true + } + + override fun onJsAlert(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean { + onJsAlert?.invoke() + result?.confirm() + return true + } + + override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean { + if (consoleMessage?.messageLevel() == ConsoleMessage.MessageLevel.ERROR) { + onJsError?.invoke(consoleMessage) + } + return super.onConsoleMessage(consoleMessage) + } + + override fun onJsPrompt(view: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?): Boolean { + onJsPrompt?.invoke(defaultValue) + result?.confirm() + return true + } + +} diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt index 404bf15..4af2e00 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt @@ -7,6 +7,7 @@ import android.graphics.Color import android.util.AttributeSet import android.view.LayoutInflater import android.view.View +import android.webkit.ConsoleMessage import android.webkit.WebView import androidx.core.content.withStyledAttributes import androidx.core.widget.TextViewCompat @@ -27,7 +28,20 @@ open class BaseWebView @JvmOverloads constructor( var onWebViewRepeatButtonClicked: (() -> Unit)? = null var onWebViewScrolled: ((WebView, Int, Int) -> Unit)? = null + var onJsConfirm: (() -> Unit)? = null + var onJsAlert: (() -> Unit)? = null + var onJsPrompt: ((defaultValue: String?) -> Unit)? = null + var onJsError: ((error: ConsoleMessage) -> Unit)? = null + + var isPullToRefreshEnable = false + set(value) { + binding.pullToRefresh.isEnabled = value + binding.pullToRefresh.isRefreshing = false + field = value + } + init { + binding.pullToRefresh.isEnabled = isPullToRefreshEnable binding.apply { context.withStyledAttributes(attrs, R.styleable.BaseWebView, defStyleAttr, 0) { if (hasValue(R.styleable.BaseWebView_errorTextAppearance)) { @@ -52,7 +66,9 @@ open class BaseWebView @JvmOverloads constructor( errorRepeatButton.text = getString(R.styleable.BaseWebView_repeatButtonText) } } - + pullToRefresh.setOnRefreshListener { + webView.reload() + } errorRepeatButton.setOnRippleClickListener { onWebViewRepeatButtonClicked?.invoke() } @@ -67,15 +83,17 @@ open class BaseWebView @JvmOverloads constructor( } override fun onStateChanged(newState: WebViewLoadingState) { - when (newState) { - WebViewLoadingState.LOADED -> { + when { + newState == WebViewLoadingState.LOADED -> { onWebViewLoaded?.invoke() - showChild(R.id.web_view) + binding.pullToRefresh.isRefreshing = false + showChild(R.id.pull_to_refresh) } - WebViewLoadingState.LOADING -> { + newState == WebViewLoadingState.LOADING + && !binding.pullToRefresh.isRefreshing -> { showChild(R.id.progress_bar) } - WebViewLoadingState.ERROR -> { + newState == WebViewLoadingState.ERROR -> { showChild(R.id.error_layout) } } @@ -83,6 +101,7 @@ open class BaseWebView @JvmOverloads constructor( fun setBaseWebViewClient() { binding.webView.webViewClient = BaseWebViewClient(this) + binding.webView.webChromeClient = BaseChromeWebViewClient(onJsConfirm, onJsAlert, onJsPrompt, onJsError) } fun getWebView() = binding.webView diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt index 38546d3..e5d2d3f 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt @@ -64,4 +64,4 @@ enum class WebViewLoadingState { LOADING, ERROR, LOADED -} \ No newline at end of file +} diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt index d12e5bf..38e6c4e 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt @@ -4,4 +4,4 @@ interface WebViewCallback { fun onStateChanged(newState: WebViewLoadingState) -} \ No newline at end of file +} diff --git a/webview/src/main/res/layout/base_web_view.xml b/webview/src/main/res/layout/base_web_view.xml index 0576588..a167e46 100644 --- a/webview/src/main/res/layout/base_web_view.xml +++ b/webview/src/main/res/layout/base_web_view.xml @@ -4,12 +4,19 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="match_parent"> + + + + Date: Sun, 18 Oct 2020 14:36:00 +0300 Subject: [PATCH 5/7] Added ssl processing, redirect, cookies processing --- .../roboswag/webview/web_view/BaseWebView.kt | 24 ++++++++++------- .../webview/web_view/BaseWebViewClient.kt | 26 +++++++++++++++++-- .../webview/web_view/WebViewCallback.kt | 4 +++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt index 4af2e00..8716804 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt @@ -27,6 +27,7 @@ open class BaseWebView @JvmOverloads constructor( var onWebViewLoaded: (() -> Unit)? = null var onWebViewRepeatButtonClicked: (() -> Unit)? = null var onWebViewScrolled: ((WebView, Int, Int) -> Unit)? = null + var onCookieLoaded: ((cookies: Map) -> Unit)? = null var onJsConfirm: (() -> Unit)? = null var onJsAlert: (() -> Unit)? = null @@ -40,6 +41,8 @@ open class BaseWebView @JvmOverloads constructor( field = value } + var isRedirectEnable = false + init { binding.pullToRefresh.isEnabled = isPullToRefreshEnable binding.apply { @@ -72,16 +75,13 @@ open class BaseWebView @JvmOverloads constructor( errorRepeatButton.setOnRippleClickListener { onWebViewRepeatButtonClicked?.invoke() } + webView.onScrollChanged = { scrollX, scrollY, _, _ -> + onWebViewScrolled?.invoke(binding.webView, scrollX, scrollY) + } + setWebViewPreferences() } } - init { - binding.webView.onScrollChanged = { scrollX, scrollY, _, _ -> - onWebViewScrolled?.invoke(binding.webView, scrollX, scrollY) - } - setWebViewPreferences() - } - override fun onStateChanged(newState: WebViewLoadingState) { when { newState == WebViewLoadingState.LOADED -> { @@ -99,8 +99,14 @@ open class BaseWebView @JvmOverloads constructor( } } - fun setBaseWebViewClient() { - binding.webView.webViewClient = BaseWebViewClient(this) + override fun onOverrideUrlLoading(url: String?): Boolean = isRedirectEnable + + override fun onPageCookiesLoaded(cookies: Map) { + onCookieLoaded?.invoke(cookies) + } + + fun setBaseWebViewClient(isSSlPinningEnable: Boolean = false) { + binding.webView.webViewClient = BaseWebViewClient(this, isSSlPinningEnable) binding.webView.webChromeClient = BaseChromeWebViewClient(onJsConfirm, onJsAlert, onJsPrompt, onJsError) } diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt index e5d2d3f..117806b 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt @@ -4,6 +4,7 @@ import android.graphics.Bitmap import android.net.http.SslError import android.os.Handler import android.os.Looper +import android.webkit.CookieManager import android.webkit.SslErrorHandler import android.webkit.WebResourceError import android.webkit.WebResourceRequest @@ -11,7 +12,7 @@ import android.webkit.WebView import android.webkit.WebViewClient import androidx.core.os.postDelayed -open class BaseWebViewClient(private val callback: WebViewCallback) : WebViewClient() { +open class BaseWebViewClient(private val callback: WebViewCallback, private val isSslPinningEnable: Boolean) : WebViewClient() { companion object { private const val WEB_VIEW_TIMEOUT_MS = 30 * 1000L // 30 sec @@ -40,11 +41,22 @@ open class BaseWebViewClient(private val callback: WebViewCallback) : WebViewCli override fun onPageFinished(view: WebView, url: String) { super.onPageFinished(view, url) isTimeout = false + callback.onPageCookiesLoaded(CookieManager.getInstance().getCookie(url).processCookies()) pageFinished() } + override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean { + return !callback.onOverrideUrlLoading(url) && view.originalUrl != null + } + override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { - handler.proceed() + if (isSslPinningEnable) { + super.onReceivedSslError(view, handler, error) + isError = true + callback.onStateChanged(WebViewLoadingState.ERROR) + } else { + handler.proceed() + } } override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) { @@ -58,6 +70,16 @@ open class BaseWebViewClient(private val callback: WebViewCallback) : WebViewCli callback.onStateChanged(if (isError) WebViewLoadingState.ERROR else WebViewLoadingState.LOADED) } + private fun String.processCookies(): Map { + val cookiesMap = mutableMapOf() + this.split(";") + .forEach { cookie -> + val splittedCookie = cookie.trim().split("=") + cookiesMap[splittedCookie.first()] = splittedCookie.last() + } + return cookiesMap + } + } enum class WebViewLoadingState { diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt index 38e6c4e..59ddc11 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt @@ -4,4 +4,8 @@ interface WebViewCallback { fun onStateChanged(newState: WebViewLoadingState) + fun onOverrideUrlLoading(url: String?): Boolean + + fun onPageCookiesLoaded(cookies: Map) + } From 45a4424679a3df663e9a4ef3161e9a0904cd0e7e Mon Sep 17 00:00:00 2001 From: Vladimir Date: Sun, 18 Oct 2020 16:50:51 +0300 Subject: [PATCH 6/7] fix --- .../ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt index 117806b..c50cef0 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt @@ -75,7 +75,7 @@ open class BaseWebViewClient(private val callback: WebViewCallback, private val this.split(";") .forEach { cookie -> val splittedCookie = cookie.trim().split("=") - cookiesMap[splittedCookie.first()] = splittedCookie.last() + cookiesMap[splittedCookie.first()] = if (splittedCookie.size != 3) "" else splittedCookie.last() } return cookiesMap } From b9c861878270c05bf16734545e3106445c8f6531 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 19 Oct 2020 11:15:03 +0300 Subject: [PATCH 7/7] fixed review --- .../ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt index c50cef0..117806b 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt @@ -75,7 +75,7 @@ open class BaseWebViewClient(private val callback: WebViewCallback, private val this.split(";") .forEach { cookie -> val splittedCookie = cookie.trim().split("=") - cookiesMap[splittedCookie.first()] = if (splittedCookie.size != 3) "" else splittedCookie.last() + cookiesMap[splittedCookie.first()] = splittedCookie.last() } return cookiesMap }