Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Do not merge] Experimental request interception #52

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Sat Nov 04 18:43:10 CET 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -31,11 +32,15 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.unit.dp
import co.touchlab.kermit.Logger
import com.multiplatform.webview.cookie.Cookie
import com.multiplatform.webview.request.RequestInterceptor
import com.multiplatform.webview.request.RequestResult
import com.multiplatform.webview.util.KLogSeverity
import com.multiplatform.webview.web.IWebView
import com.multiplatform.webview.web.LoadingState
import com.multiplatform.webview.web.WebView
import com.multiplatform.webview.web.rememberWebViewNavigator
import com.multiplatform.webview.web.rememberWebViewState
import kotlinx.coroutines.delay

/**
* Created By Kevin Zou On 2023/9/8
Expand All @@ -50,6 +55,22 @@ internal fun BasicWebViewSample() {
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/625.20 (KHTML, like Gecko) Version/14.3.43 Safari/625.20"
}
val navigator = rememberWebViewNavigator()

DisposableEffect(Unit) {

navigator.requestInterceptor = RequestInterceptor { data ->
println("Triggering req interceptor for ${data.url}")

if (data.isForMainFrame && !data.url.contains(".com"))
RequestResult.Modify(url = "https://request.urih.com/", mapOf("Authorizations" to "true")) // https://request.urih.com/
else
RequestResult.Allow
}

onDispose { }
}


var textFieldValue by remember(state.lastLoadedUrl) {
mutableStateOf(state.lastLoadedUrl)
}
Expand Down Expand Up @@ -140,4 +161,4 @@ internal fun BasicWebViewSample() {
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package com.multiplatform.webview.web

import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.view.ViewGroup
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
Expand All @@ -16,6 +18,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import com.multiplatform.webview.request.RequestData
import com.multiplatform.webview.request.RequestResult
import com.multiplatform.webview.util.KLogger

/**
Expand Down Expand Up @@ -209,6 +213,29 @@ open class AccompanistWebViewClient : WebViewClient() {
open lateinit var navigator: WebViewNavigator
internal set

override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest): Boolean {
val data = RequestData(
url = request.url.toString(),
isForMainFrame = request.isForMainFrame,
isRedirect = request.isRedirect,
method = request.method,
requestHeaders = request.requestHeaders ?: emptyMap()
)

KLogger.d { "shouldOverrideUrlLoading: $data" }
val result = navigator.requestInterceptor(data)
KLogger.d { "shouldOverrideUrlLoading: load new: $result" }

return when (result) {
RequestResult.Allow -> false
is RequestResult.Modify -> {
navigator.loadUrl(result.url, result.additionalHeaders)
true
}
RequestResult.Reject -> true
}
}

override fun onPageStarted(
view: WebView,
url: String?,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.multiplatform.webview.request


data class RequestData (
val url: String,
val isForMainFrame: Boolean,
val isRedirect: Boolean,

val method: String,
val requestHeaders: Map<String, String>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.multiplatform.webview.request

fun interface RequestInterceptor {
operator fun invoke(data: RequestData): RequestResult
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.multiplatform.webview.request

sealed interface RequestResult {
data object Allow : RequestResult
data object Reject : RequestResult
data class Modify(val url: String, val additionalHeaders: Map<String, String> = emptyMap()) : RequestResult
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import com.multiplatform.webview.util.KLogger
import kotlinx.coroutines.delay
import org.jetbrains.compose.resources.ExperimentalResourceApi

/**
Expand Down Expand Up @@ -34,9 +36,16 @@ fun WebView(
onCreated: () -> Unit = {},
onDispose: () -> Unit = {},
) {
val webView = state.webView
ActualWebView(
state = state,
modifier = modifier,
captureBackPresses = captureBackPresses,
navigator = navigator,
onCreated = onCreated,
onDispose = onDispose,
)

webView?.let { wv ->
state.webView?.let { wv ->
LaunchedEffect(wv, navigator) {
with(navigator) {
wv.handleNavigationEvents()
Expand Down Expand Up @@ -80,14 +89,7 @@ fun WebView(
}
}

ActualWebView(
state = state,
modifier = modifier,
captureBackPresses = captureBackPresses,
navigator = navigator,
onCreated = onCreated,
onDispose = onDispose,
)

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import com.multiplatform.webview.request.RequestInterceptor
import com.multiplatform.webview.request.RequestResult
import com.multiplatform.webview.util.KLogger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -121,6 +125,7 @@ class WebViewNavigator(private val coroutineScope: CoroutineScope) {
internal suspend fun IWebView.handleNavigationEvents(): Nothing =
withContext(Dispatchers.Main) {
navigationEvents.collect { event ->
KLogger.d { "collecting event $event" }
when (event) {
is NavigationEvent.Back -> goBack()
is NavigationEvent.Forward -> goForward()
Expand Down Expand Up @@ -175,7 +180,9 @@ class WebViewNavigator(private val coroutineScope: CoroutineScope) {
url: String,
additionalHttpHeaders: Map<String, String> = emptyMap(),
) {
KLogger.d { "loadUrl with $url $additionalHttpHeaders" }
coroutineScope.launch {
KLogger.d { "loadUrl emitting with $url $additionalHttpHeaders" }
navigationEvents.emit(
NavigationEvent.LoadUrl(
url,
Expand Down Expand Up @@ -291,6 +298,9 @@ class WebViewNavigator(private val coroutineScope: CoroutineScope) {
fun stopLoading() {
coroutineScope.launch { navigationEvents.emit(NavigationEvent.StopLoading) }
}


var requestInterceptor: RequestInterceptor by mutableStateOf(RequestInterceptor { _ -> RequestResult.Allow })
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
package com.multiplatform.webview.web

import com.multiplatform.webview.request.RequestData
import com.multiplatform.webview.request.RequestResult
import com.multiplatform.webview.util.KLogger
import dev.datlag.kcef.KCEFBrowser
import org.cef.CefSettings
import org.cef.browser.CefBrowser
import org.cef.browser.CefFrame
import org.cef.callback.CefAuthCallback
import org.cef.callback.CefCallback
import org.cef.handler.CefCookieAccessFilter
import org.cef.handler.CefDisplayHandler
import org.cef.handler.CefLoadHandler
import org.cef.handler.CefRequestHandler
import org.cef.handler.CefRequestHandlerAdapter
import org.cef.handler.CefResourceHandler
import org.cef.handler.CefResourceRequestHandler
import org.cef.handler.CefResourceRequestHandlerAdapter
import org.cef.misc.BoolRef
import org.cef.misc.StringRef
import org.cef.network.CefRequest
import org.cef.network.CefResponse
import org.cef.network.CefURLRequest
import org.cef.security.CefSSLInfo

/**
* Created By Kevin Zou On 2023/9/12
Expand Down Expand Up @@ -66,10 +82,66 @@ internal fun CefBrowser.addDisplayHandler(state: WebViewState) {
)
}

internal fun KCEFBrowser.addRequestHandler(
state: WebViewState,
navigator: WebViewNavigator
) {

client.addRequestHandler(object : CefRequestHandlerAdapter() {
override fun getResourceRequestHandler(
browser: CefBrowser,
frame: CefFrame,
request: CefRequest,
isNavigation: Boolean,
isDownload: Boolean,
requestInitiator: String,
disableDefaultHandling: BoolRef
) = object : CefResourceRequestHandlerAdapter() {
override fun onBeforeResourceLoad(
browser: CefBrowser,
frame: CefFrame,
request: CefRequest
): Boolean {
val data = RequestData(
url = request.url.toString(),
isForMainFrame = frame.isMain,
isRedirect = false,
method = request.method,
requestHeaders = mutableMapOf<String, String>().also {
request.getHeaderMap(
it
)
}
)

val result =
if (request.resourceType == CefRequest.ResourceType.RT_MAIN_FRAME) navigator.requestInterceptor(
data
) else return false
KLogger.d { "shouldOverrideUrlLoading: load new: $result" }

return when (result) {
RequestResult.Allow -> false
is RequestResult.Modify -> {
KLogger.d { "State is ${state.webView}" }

request.url = result.url
request.setHeaderMap(result.additionalHeaders)
false
}

RequestResult.Reject -> true
}
}
}.also { KLogger.d { "Created a handler" } }
})
}

internal fun CefBrowser.addLoadListener(
state: WebViewState,
navigator: WebViewNavigator,
) {

this.client.addLoadHandler(
object : CefLoadHandler {
override fun onLoadingStateChange(
Expand Down Expand Up @@ -117,7 +189,7 @@ internal fun CefBrowser.addLoadListener(
) {
state.loadingState = LoadingState.Finished
KLogger.e {
"Failed to load url: ${failedUrl}\n$errorText"
"Failed to load url: ${failedUrl} $errorText $errorCode $failedUrl"
}
state.errorsForCurrentRequest.add(
WebViewError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.SwingPanel
import com.multiplatform.webview.util.KLogger
import dev.datlag.kcef.KCEF
import dev.datlag.kcef.KCEFBrowser
import org.cef.browser.CefRendering
Expand Down Expand Up @@ -61,14 +62,16 @@ fun DesktopWebView(

val browser: KCEFBrowser? =
remember(client, state.webSettings.desktopWebSettings, fileContent) {
KLogger.d { "Trying to create a webview now... because $client" }

val rendering =
if (state.webSettings.desktopWebSettings.offScreenRendering) {
CefRendering.OFFSCREEN
} else {
CefRendering.DEFAULT
}

when (val current = state.content) {
val view = when (val current = state.content) {
is WebContent.Url ->
client?.createBrowser(
current.url,
Expand Down Expand Up @@ -100,8 +103,14 @@ fun DesktopWebView(
)
}
}

KLogger.d { "View is $view" }

view
}?.also {
state.webView = DesktopWebView(it)
val ww = DesktopWebView(it)
KLogger.d { "Webview is $ww" }
state.webView = ww
}

browser?.let {
Expand All @@ -110,6 +119,7 @@ fun DesktopWebView(
browser.apply {
addDisplayHandler(state)
addLoadListener(state, navigator)
addRequestHandler(state, navigator)
}
onCreated()
browser.uiComponent
Expand Down