From 25edb4ff1e0fbded63a4ce2b9de5159259974bb6 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Wed, 31 Dec 2025 11:45:52 +0100 Subject: [PATCH] perf(android): prewarm WebView during idle time to speed up startup Load WebView native libraries during main thread idle time using IdleHandler and WebSettings.getDefaultUserAgent(). This reduces the 200-300ms freeze on first WebView creation. --- .../superproductivity/App.kt | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/superproductivity/superproductivity/App.kt b/android/app/src/main/java/com/superproductivity/superproductivity/App.kt index bb9d9443a..540af3e9f 100644 --- a/android/app/src/main/java/com/superproductivity/superproductivity/App.kt +++ b/android/app/src/main/java/com/superproductivity/superproductivity/App.kt @@ -1,16 +1,15 @@ package com.superproductivity.superproductivity import android.app.Application +import android.os.Looper +import android.os.MessageQueue +import android.util.Log +import android.webkit.WebSettings import com.superproductivity.superproductivity.app.AppLifecycleObserver import com.superproductivity.superproductivity.app.KeyValStore class App : Application() { - // NOTE using the web view like this causes all html5 inputs not to work -// val wv: WebView by lazy { -// WebHelper().instanceView(this) -// } - val keyValStore: KeyValStore by lazy { KeyValStore(this) } @@ -20,5 +19,36 @@ class App : Application() { // Initialize AppLifecycleObserver at app startup AppLifecycleObserver.getInstance() + + // Prewarm WebView by loading native libraries during idle time + prewarmWebView() + } + + /** + * Prewarms the WebView's Chromium engine by triggering native library loading + * during main thread idle time. This reduces the 200-300ms freeze that occurs + * on first WebView creation. + * + * Uses WebSettings.getDefaultUserAgent() as recommended by the Chromium team - + * it loads WebView libraries without side effects. + */ + private fun prewarmWebView() { + try { + Looper.getMainLooper().queue.addIdleHandler(object : MessageQueue.IdleHandler { + override fun queueIdle(): Boolean { + try { + val startTime = System.currentTimeMillis() + WebSettings.getDefaultUserAgent(this@App) + val duration = System.currentTimeMillis() - startTime + Log.d("SP-WebView", "WebView prewarmed in ${duration}ms") + } catch (e: Exception) { + Log.w("SP-WebView", "WebView prewarm failed: ${e.message}") + } + return false // Remove handler after execution + } + }) + } catch (e: Exception) { + Log.w("SP-WebView", "Failed to schedule WebView prewarm: ${e.message}") + } } }