optimize webview

This commit is contained in:
2026-05-12 19:27:09 +03:30
parent fe17187df2
commit 9ec64fc179
15 changed files with 227 additions and 53 deletions
@@ -2,13 +2,14 @@ package com.example.design_system
import android.annotation.SuppressLint
import android.app.Activity
import android.view.View
import android.view.ViewGroup
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.compose.BackHandler
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
@@ -21,8 +22,10 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import com.example.core.model.PrintEntity
import com.example.design_system.util.PspJavaScriptInterface
import com.example.design_system.util.WebViewManager
import com.example.design_system.util.snackbar.SnackbarController
import com.example.design_system.util.snackbar.SnackbarEvent
import kotlinx.coroutines.launch
@SuppressLint("JavascriptInterface")
@@ -30,9 +33,7 @@ import kotlinx.coroutines.launch
@Composable
fun PspWebView(
url: String,
webView: WebView?,
modifier: Modifier = Modifier,
onWebView: (WebView) -> Unit,
onPayClick: (amount: Long, id: String?) -> Unit,
onDeviceInfo: () -> String,
onPrintClick: (printEntities: List<PrintEntity>) -> Unit,
@@ -42,7 +43,8 @@ fun PspWebView(
val scope = rememberCoroutineScope()
val context = LocalContext.current
var lastBackTime by remember { mutableLongStateOf(0L) }
var isPaymentLaunching by remember { mutableStateOf(false) }
var webView by remember { mutableStateOf<WebView?>(null) }
// Use rememberUpdatedState to ensure the bridge always calls the latest callbacks
val currentOnPayClick by rememberUpdatedState(onPayClick)
@@ -69,7 +71,7 @@ fun PspWebView(
scope.launch {
SnackbarController.sendEvent(
SnackbarEvent(
message = "Press back again to exit"
message = "برای خروج، دوباره بر روی بازگشت کلیک کنید."
)
)
}
@@ -77,42 +79,36 @@ fun PspWebView(
}
}
DisposableEffect(Unit) {
webView = WebViewManager.getWebView(context)
onDispose {
webView?.let { WebViewManager.releaseWebView(it) }
}
}
AndroidView(
modifier = modifier,
factory = { ctx ->
WebView(ctx).apply {
(webView ?: WebViewManager.getWebView(ctx)).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
overScrollMode = View.OVER_SCROLL_NEVER
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
canGoBack.value = view?.canGoBack() ?: false
}
}
settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
loadWithOverviewMode = true
useWideViewPort = true
cacheMode = WebSettings.LOAD_DEFAULT
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
userAgentString =
"Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 Chrome/120.0 Mobile Safari/537.36"
}
addJavascriptInterface(bridge, "NativeBridge")
loadUrl(url)
onWebView(this)
}
},
update = { view ->
onWebView(view)
update = {
it.loadUrl(url)
}
)
@@ -0,0 +1,60 @@
package com.example.design_system.util
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.webkit.WebSettings
import android.webkit.WebView
import java.util.Stack
@SuppressLint("StaticFieldLeak")
object WebViewManager {
private const val POOL_SIZE = 1
private val webViewPool = Stack<WebView>()
fun preload(context: Context) {
if (webViewPool.isEmpty()) {
repeat(POOL_SIZE) {
val webView = createWebView(context)
webViewPool.push(webView)
}
}
}
fun getWebView(context: Context): WebView {
return if (webViewPool.isNotEmpty()) {
webViewPool.pop()
} else {
createWebView(context)
}
}
fun releaseWebView(webView: WebView) {
if (webViewPool.size < POOL_SIZE) {
webViewPool.push(webView)
}
}
@SuppressLint("SetJavaScriptEnabled")
private fun createWebView(context: Context): WebView {
return WebView(context).apply {
setLayerType(View.LAYER_TYPE_HARDWARE, null)
settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
databaseEnabled = true
cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
loadsImagesAutomatically = true
allowFileAccess = false
useWideViewPort = true
loadWithOverviewMode = true
mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
setSupportZoom(false)
builtInZoomControls = false
displayZoomControls = false
userAgentString = "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 Chrome/120.0 Mobile Safari/537.36"
}
}
}
}