[#1497] WebView: Localstorage (#1500)

* [#1497] WebView: Localstorage

* WebView: Transition to our own header/postData system

This is also what is recommended by most other posts, I haven't seen the
context used anywhere, and `KCEFResourceRequestHandler` seems to just
bypass a lot of CEF

* Lint
This commit is contained in:
Constantin Piber
2025-07-06 18:09:31 +02:00
committed by GitHub
parent fe121f59b0
commit 6234e897a8
3 changed files with 56 additions and 46 deletions

View File

@@ -53,7 +53,6 @@ import android.webkit.WebViewRenderProcessClient
import dev.datlag.kcef.KCEF import dev.datlag.kcef.KCEF
import dev.datlag.kcef.KCEFBrowser import dev.datlag.kcef.KCEFBrowser
import dev.datlag.kcef.KCEFClient import dev.datlag.kcef.KCEFClient
import dev.datlag.kcef.KCEFResourceRequestHandler
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@@ -62,7 +61,6 @@ import org.cef.browser.CefBrowser
import org.cef.browser.CefFrame import org.cef.browser.CefFrame
import org.cef.browser.CefMessageRouter import org.cef.browser.CefMessageRouter
import org.cef.browser.CefRendering import org.cef.browser.CefRendering
import org.cef.browser.CefRequestContext
import org.cef.callback.CefCallback import org.cef.callback.CefCallback
import org.cef.callback.CefQueryCallback import org.cef.callback.CefQueryCallback
import org.cef.handler.CefDisplayHandlerAdapter import org.cef.handler.CefDisplayHandlerAdapter
@@ -101,6 +99,7 @@ class KcefWebViewProvider(
private var chromeClient = WebChromeClient() private var chromeClient = WebChromeClient()
private val mappings: MutableList<FunctionMapping> = mutableListOf() private val mappings: MutableList<FunctionMapping> = mutableListOf()
private val urlHttpMapping: MutableMap<String, String> = mutableMapOf() private val urlHttpMapping: MutableMap<String, String> = mutableMapOf()
private var initialRequestData: InitialRequestData? = null
private var kcefClient: KCEFClient? = null private var kcefClient: KCEFClient? = null
private var browser: KCEFBrowser? = null private var browser: KCEFBrowser? = null
@@ -119,6 +118,33 @@ class KcefWebViewProvider(
public fun init(provider: KcefWebViewProvider): Unit public fun init(provider: KcefWebViewProvider): Unit
} }
private data class InitialRequestData(
private val additionalHttpHeaders: Map<String, String>? = null,
private val myPostData: ByteArray? = null,
) {
fun apply(request: CefRequest?) {
request?.apply {
Log.v(TAG, "Initial request: applying headers and post data")
if (!additionalHttpHeaders.isNullOrEmpty()) {
additionalHttpHeaders.forEach {
setHeaderByName(it.key, it.value, true)
}
}
if (myPostData != null) {
this.postData =
CefPostData.create().apply {
addElement(
CefPostDataElement.create().apply {
setToBytes(myPostData.size, myPostData)
},
)
}
}
}
}
}
private class CefWebResourceRequest( private class CefWebResourceRequest(
val request: CefRequest?, val request: CefRequest?,
val frame: CefFrame?, val frame: CefFrame?,
@@ -375,6 +401,8 @@ class KcefWebViewProvider(
frame: CefFrame?, frame: CefFrame?,
request: CefRequest, request: CefRequest,
): Boolean { ): Boolean {
initialRequestData?.apply(request)
initialRequestData = null
request.setHeaderByName("user-agent", settings.userAgentString, true) request.setHeaderByName("user-agent", settings.userAgentString, true)
// TODO: we should be calling this on the handler, since CEF calls us on its IO thread // TODO: we should be calling this on the handler, since CEF calls us on its IO thread
@@ -528,12 +556,12 @@ class KcefWebViewProvider(
browser?.close(true) browser?.close(true)
browser?.dispose() browser?.dispose()
chromeClient.onProgressChanged(view, 0) chromeClient.onProgressChanged(view, 0)
initialRequestData = InitialRequestData(additionalHttpHeaders = additionalHttpHeaders)
browser = browser =
kcefClient!! kcefClient!!
.createBrowser( .createBrowser(
loadUrl, loadUrl,
CefRendering.OFFSCREEN, CefRendering.OFFSCREEN,
context = createContext(additionalHttpHeaders),
).apply { ).apply {
// NOTE: Without this, we don't seem to be receiving any events // NOTE: Without this, we don't seem to be receiving any events
createImmediately() createImmediately()
@@ -552,12 +580,12 @@ class KcefWebViewProvider(
browser?.close(true) browser?.close(true)
browser?.dispose() browser?.dispose()
chromeClient.onProgressChanged(view, 0) chromeClient.onProgressChanged(view, 0)
initialRequestData = InitialRequestData(myPostData = postData)
browser = browser =
kcefClient!! kcefClient!!
.createBrowser( .createBrowser(
url, url,
CefRendering.OFFSCREEN, CefRendering.OFFSCREEN,
context = createContext(postData = postData),
).apply { ).apply {
// NOTE: Without this, we don't seem to be receiving any events // NOTE: Without this, we don't seem to be receiving any events
createImmediately() createImmediately()
@@ -1067,45 +1095,4 @@ class KcefWebViewProvider(
override fun computeScroll(): Unit = throw RuntimeException("Stub!") override fun computeScroll(): Unit = throw RuntimeException("Stub!")
} }
private fun createContext(
additionalHttpHeaders: Map<String, String>? = null,
postData: ByteArray? = null,
): CefRequestContext =
CefRequestContext.createContext {
browser,
frame,
request,
isNavigation,
isDownload,
requestInitiator,
disableDefaultHandling,
->
KCEFResourceRequestHandler.globalHandler(
browser,
frame,
request.apply {
if (!additionalHttpHeaders.isNullOrEmpty()) {
additionalHttpHeaders.forEach {
setHeaderByName(it.key, it.value, true)
}
}
if (postData != null) {
this.postData =
CefPostData.create().apply {
addElement(
CefPostDataElement.create().apply {
setToBytes(postData.size, postData)
},
)
}
}
},
isNavigation,
isDownload,
requestInitiator,
disableDefaultHandling,
)
}
} }

View File

@@ -18,9 +18,13 @@ import org.cef.handler.CefDisplayHandlerAdapter
import org.cef.handler.CefLoadHandler import org.cef.handler.CefLoadHandler
import org.cef.handler.CefLoadHandlerAdapter import org.cef.handler.CefLoadHandlerAdapter
import org.cef.handler.CefRenderHandlerAdapter import org.cef.handler.CefRenderHandlerAdapter
import org.cef.handler.CefRequestHandlerAdapter
import org.cef.handler.CefResourceRequestHandler
import org.cef.input.CefTouchEvent import org.cef.input.CefTouchEvent
import org.cef.misc.BoolRef
import org.cef.network.CefCookie import org.cef.network.CefCookie
import org.cef.network.CefCookieManager import org.cef.network.CefCookieManager
import org.cef.network.CefRequest
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.awt.Component import java.awt.Component
import java.awt.Rectangle import java.awt.Rectangle
@@ -176,6 +180,21 @@ class KcefWebView {
} }
} }
private inner class RequestHandler : CefRequestHandlerAdapter() {
override fun getResourceRequestHandler(
browser: CefBrowser,
frame: CefFrame,
request: CefRequest,
isNavigation: Boolean,
isDownload: Boolean,
requestInitiator: String,
disableDefaultHandling: BoolRef,
): CefResourceRequestHandler? {
logger.info { "Load resource: ${frame.name} - ${request.url}" }
return null
}
}
// Loosely based on // Loosely based on
// https://github.com/JetBrains/jcef/blob/main/java/org/cef/browser/CefBrowserOsr.java // https://github.com/JetBrains/jcef/blob/main/java/org/cef/browser/CefBrowserOsr.java
private inner class RenderHandler : CefRenderHandlerAdapter() { private inner class RenderHandler : CefRenderHandlerAdapter() {
@@ -222,6 +241,7 @@ class KcefWebView {
KCEF.newClientBlocking().apply { KCEF.newClientBlocking().apply {
addDisplayHandler(DisplayHandler()) addDisplayHandler(DisplayHandler())
addLoadHandler(LoadHandler()) addLoadHandler(LoadHandler())
addRequestHandler(RequestHandler())
} }
logger.info { "Start loading cookies" } logger.info { "Start loading cookies" }

View File

@@ -468,7 +468,10 @@ fun applicationSetup() {
} }
} }
download { github() } download { github() }
settings { windowlessRenderingEnabled = true } settings {
windowlessRenderingEnabled = true
cachePath = (Path(applicationDirs.dataRoot) / "cache/kcef").toString()
}
appHandler( appHandler(
KCEF.AppHandler( KCEF.AppHandler(
arrayOf("--disable-gpu", "--off-screen-rendering-enabled", "--disable-dev-shm-usage"), arrayOf("--disable-gpu", "--off-screen-rendering-enabled", "--disable-dev-shm-usage"),