Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package cloud.mindbox.mobile_sdk.inapp.webview

import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Build
import android.view.View
import android.webkit.*
import cloud.mindbox.mobile_sdk.annotations.InternalMindboxApi

@InternalMindboxApi
public actual typealias WebViewPlatformView = View

@InternalMindboxApi
public fun WebViewController.Companion.create(
context: android.content.Context,
isDebugEnabled: Boolean
): WebViewController {
return AndroidWebViewController(context, isDebugEnabled)
}

@OptIn(InternalMindboxApi::class)
private class AndroidWebViewController(
context: android.content.Context,
isDebugEnabled: Boolean
) : WebViewController {

private val webView: WebView = WebView(context)
private var eventListener: WebViewEventListener? = null

init {
WebView.setWebContentsDebuggingEnabled(isDebugEnabled)
configureWebView()
webView.webViewClient = createWebViewClient()
}

override val view: WebViewPlatformView
get() = webView

override fun loadContent(content: WebViewHtmlContent) {
webView.loadDataWithBaseURL(
content.baseUrl,
content.html,
"text/html",
"UTF-8",
null
)
}

override fun setVisibility(isVisible: Boolean) {
webView.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
}

override fun setUserAgentSuffix(suffix: String) {
val currentUserAgent: String = webView.settings.userAgentString ?: ""
if (currentUserAgent.contains(suffix)) {
return
}
webView.settings.userAgentString = "$currentUserAgent $suffix".trim()
}

override fun setJsBridge(bridge: WebViewJsBridge, bridgeName: String) {
webView.removeJavascriptInterface(bridgeName)
webView.addJavascriptInterface(AndroidWebViewJsBridge(bridge), bridgeName)
}

override fun setEventListener(listener: WebViewEventListener?) {
eventListener = listener
}

override fun executeOnViewThread(action: () -> Unit) {
webView.post(action)
}

override fun destroy() {
webView.stopLoading()
webView.loadUrl("about:blank")
webView.clearHistory()
webView.removeAllViews()
webView.destroy()
}

@SuppressLint("SetJavaScriptEnabled")
private fun configureWebView() {
with(webView.settings) {
javaScriptEnabled = true
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Думаешь эти настройки останутся такими же и нам не надо выносить возможность их задавать при инициализации?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

думаю сейчас все оставить внутри. Пока сомнительно, чтобы что-то поменялось

domStorageEnabled = true
loadWithOverviewMode = true
builtInZoomControls = true
displayZoomControls = false
defaultTextEncodingName = "utf-8"
cacheMode = WebSettings.LOAD_NO_CACHE
allowContentAccess = true
}
webView.setBackgroundColor(Color.TRANSPARENT)
}

private fun createWebViewClient(): WebViewClient {
return object : WebViewClient() {


override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
val webViewError: WebViewError = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
WebViewError(
code = error?.errorCode,
description = error?.description?.toString(),
url = request?.url?.toString(),
isForMainFrame = request?.isForMainFrame
)
} else {
WebViewError(
code = null,
description = null,
url = request?.url?.toString(),
isForMainFrame = request?.isForMainFrame
)
}
eventListener?.onError(webViewError)
}

@Deprecated("Deprecated in Java")
@Suppress("DEPRECATION")
override fun onReceivedError(
view: WebView?,
errorCode: Int,
description: String?,
failingUrl: String?
) {
val webViewError: WebViewError = WebViewError(
code = errorCode,
description = description,
url = failingUrl,
isForMainFrame = failingUrl == view?.originalUrl
)
eventListener?.onError(webViewError)
}

override fun onPageFinished(view: WebView?, url: String?) {
eventListener?.onPageFinished(url)
}
}
}

private class AndroidWebViewJsBridge(
private val bridge: WebViewJsBridge
) {
@JavascriptInterface
fun receiveParam(key: String): String? {
return bridge.getParam(key)
}

@JavascriptInterface
fun postMessage(action: String, data: String) {
bridge.onAction(action, data)
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cloud.mindbox.mobile_sdk.annotations

@Target(
AnnotationTarget.CLASS,
AnnotationTarget.TYPEALIAS,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY
)
@RequiresOptIn(
message = "Internal API. Use only inside Mindbox SDK.",
level = RequiresOptIn.Level.WARNING
)
public annotation class InternalMindboxApi
Comment thread
enotniy marked this conversation as resolved.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cloud.mindbox.mobile_sdk.inapp.webview

import cloud.mindbox.mobile_sdk.annotations.InternalMindboxApi

@InternalMindboxApi
public expect class WebViewPlatformView

@InternalMindboxApi
public data class WebViewHtmlContent(
val baseUrl: String,
val html: String
)

@InternalMindboxApi
public data class WebViewError(
val code: Int?,
val description: String?,
val url: String?,
val isForMainFrame: Boolean?
)

@InternalMindboxApi
public interface WebViewJsBridge {
public fun getParam(key: String): String?

public fun onAction(action: String, data: String) {
}
}

@InternalMindboxApi
public interface WebViewEventListener {
public fun onPageFinished(url: String?)

public fun onError(error: WebViewError) {
}
}

@InternalMindboxApi
public interface WebViewController {
public val view: WebViewPlatformView

public fun loadContent(content: WebViewHtmlContent)

public fun setVisibility(isVisible: Boolean)

public fun setUserAgentSuffix(suffix: String)

public fun setJsBridge(bridge: WebViewJsBridge, bridgeName: String = DEFAULT_WEBVIEW_BRIDGE_NAME)

public fun setEventListener(listener: WebViewEventListener?)

public fun executeOnViewThread(action: () -> Unit)

public fun destroy()

public companion object
}

public const val DEFAULT_WEBVIEW_BRIDGE_NAME: String = "SdkBridge"

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package cloud.mindbox.mobile_sdk.inapp.webview

import cloud.mindbox.mobile_sdk.annotations.InternalMindboxApi

@InternalMindboxApi
public actual typealias WebViewPlatformView = Any