Skip to content

Commit d15106a

Browse files
committed
feat(webview): Optimize KCEF component initialization and cleanup mechanisms
1 parent 83d42ae commit d15106a

File tree

3 files changed

+75
-14
lines changed

3 files changed

+75
-14
lines changed

composeApp/src/jvmMain/kotlin/com/jankinwu/fntv/client/main.kt

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ fun main() {
106106
Logger.setLogWriters(ConsoleLogWriter(), FileLogWriter(logDir))
107107
Logger.withTag("main").i { "Application started. Logs directory: ${logDir.absolutePath}" }
108108

109+
// Cleanup old KCEF directories
110+
val baseDir = kcefBaseDir()
111+
cleanupOldKcefDirs(baseDir, BuildConfig.VERSION_NAME)
112+
109113
application {
110114
LaunchedEffect(Unit) {
111115
WebViewBootstrap.start(
@@ -494,32 +498,49 @@ fun main() {
494498

495499

496500

497-
private fun kcefInstallDir(): File {
501+
private fun kcefBaseDir(): File {
498502
val platform = currentPlatformDesktop()
499-
val baseDir = when (platform) {
503+
return when (platform) {
500504
is Platform.Linux -> File(System.getProperty("user.home"), ".local/share/fly-narwhal")
501505
is Platform.MacOS -> File(System.getProperty("user.home"), "Library/Application Support/fly-narwhal")
502506
is Platform.Windows -> {
503507
val localAppData = System.getenv("LOCALAPPDATA")?.takeIf { it.isNotBlank() }
504508
File(localAppData ?: System.getProperty("user.home"), "FlyNarwhal")
505509
}
506510
}
511+
}
512+
513+
private fun kcefInstallDir(): File {
507514
val version = BuildConfig.VERSION_NAME.replace(Regex("[^A-Za-z0-9._-]"), "_")
508-
return File(baseDir, "kcef-bundle-$version")
515+
return File(kcefBaseDir(), "kcef-bundle-$version")
509516
}
510517

511518
private fun kcefCacheDir(): File {
512-
val platform = currentPlatformDesktop()
513-
val baseDir = when (platform) {
514-
is Platform.Linux -> File(System.getProperty("user.home"), ".local/share/fly-narwhal")
515-
is Platform.MacOS -> File(System.getProperty("user.home"), "Library/Application Support/fly-narwhal")
516-
is Platform.Windows -> {
517-
val localAppData = System.getenv("LOCALAPPDATA")?.takeIf { it.isNotBlank() }
518-
File(localAppData ?: System.getProperty("user.home"), "FlyNarwhal")
519+
val version = BuildConfig.VERSION_NAME.replace(Regex("[^A-Za-z0-9._-]"), "_")
520+
return File(kcefBaseDir(), "kcef-cache-$version")
521+
}
522+
523+
/**
524+
* Cleanup old KCEF bundle and cache directories to save disk space.
525+
* Only keeps the directories for the current version.
526+
*/
527+
private fun cleanupOldKcefDirs(baseDir: File, currentVersion: String) {
528+
val versionTag = currentVersion.replace(Regex("[^A-Za-z0-9._-]"), "_")
529+
val currentBundle = "kcef-bundle-$versionTag"
530+
val currentCache = "kcef-cache-$versionTag"
531+
532+
baseDir.listFiles { file ->
533+
file.isDirectory && (file.name.startsWith("kcef-bundle-") || file.name.startsWith("kcef-cache-"))
534+
}?.forEach { file ->
535+
if (file.name != currentBundle && file.name != currentCache) {
536+
try {
537+
file.deleteRecursively()
538+
Logger.withTag("main").i { "Deleted old KCEF directory: ${file.name}" }
539+
} catch (e: Exception) {
540+
Logger.withTag("main").e(e) { "Failed to delete old KCEF directory: ${file.name}" }
541+
}
519542
}
520543
}
521-
val version = BuildConfig.VERSION_NAME.replace(Regex("[^A-Za-z0-9._-]"), "_")
522-
return File(baseDir, "kcef-cache-$version")
523544
}
524545

525546
/**

composeApp/src/jvmMain/kotlin/com/jankinwu/fntv/client/ui/dialog/KcefInitErrorDialog.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fun KcefInitErrorDialog(
3434
}
3535
},
3636
content = {
37-
Text("KCEF 组件加载失败,部分功能(Fn ID、NAS 登录)将不可用。\n错误信息:${error?.message}")
37+
Text("浏览器组件加载失败,部分功能(Fn ID、NAS 登录)将不可用。\n错误信息:${error?.message}")
3838
}
3939
)
4040
}

composeApp/src/jvmMain/kotlin/com/jankinwu/fntv/client/utils/WebViewBootstrap.kt

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ import java.io.File
1616
import java.io.RandomAccessFile
1717
import java.util.concurrent.atomic.AtomicBoolean
1818
import kotlin.coroutines.CoroutineContext
19+
import io.ktor.client.HttpClient
20+
import io.ktor.client.engine.okhttp.OkHttp
21+
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
22+
import io.ktor.serialization.kotlinx.json.json
23+
import kotlinx.serialization.json.Json
24+
import io.ktor.http.ContentType
25+
import javax.net.ssl.SSLContext
26+
import javax.net.ssl.TrustManager
27+
import javax.net.ssl.X509TrustManager
28+
import java.security.SecureRandom
29+
import java.security.cert.X509Certificate
1930

2031
object WebViewBootstrap {
2132
private val started = AtomicBoolean(false)
@@ -45,6 +56,32 @@ object WebViewBootstrap {
4556

4657
if (!started.compareAndSet(false, true)) return
4758

59+
// Create a custom HttpClient with Trust-All SSL configuration for KCEF download
60+
val kcefClient = HttpClient(OkHttp) {
61+
engine {
62+
config {
63+
val trustAllCerts = arrayOf<TrustManager>(@Suppress("CustomX509TrustManager")
64+
object : X509TrustManager {
65+
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
66+
@Suppress("TrustAllX509TrustManager")
67+
override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {}
68+
@Suppress("TrustAllX509TrustManager")
69+
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {}
70+
})
71+
val sslContext = SSLContext.getInstance("SSL")
72+
sslContext.init(null, trustAllCerts, SecureRandom())
73+
74+
sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
75+
hostnameVerifier { _, _ -> true }
76+
}
77+
}
78+
install(ContentNegotiation) {
79+
val jsonConfig = Json { ignoreUnknownKeys = true }
80+
json(jsonConfig)
81+
json(jsonConfig, ContentType("application", "vnd.github+json"))
82+
}
83+
}
84+
4885
// Clean up legacy kcef.log in logDir if it exists
4986
File(cacheDir, "kcef.log").delete()
5087

@@ -71,13 +108,16 @@ object WebViewBootstrap {
71108
settings {
72109
cachePath = cacheDir.absolutePath
73110
logFile = kcefLog.absolutePath
74-
// logSeverity = KCEFBuilder.Settings.LogSeverity.INFO
75111
}
76112
progress {
77113
onInitialized {
78114
initialized.value = true
79115
}
80116
}
117+
download {
118+
github()
119+
client(kcefClient)
120+
}
81121
},
82122
onError = { throwable ->
83123
initError.value = throwable

0 commit comments

Comments
 (0)