kevinnzou / compose-webview-multiplatform Goto Github PK
View Code? Open in Web Editor NEWWebView for JetBrains Compose Multiplatform
Home Page: https://kevinnzou.github.io/compose-webview-multiplatform/
License: Apache License 2.0
WebView for JetBrains Compose Multiplatform
Home Page: https://kevinnzou.github.io/compose-webview-multiplatform/
License: Apache License 2.0
Execution failed for task ':desktop:run'.
Could not resolve all files for configuration ':desktop:runtimeClasspath'.
Could not find org.jogamp.gluegen:gluegen-rt:2.5.0.
Searched in the following locations:
- https://dl.google.com/dl/android/maven2/org/jogamp/gluegen/gluegen-rt/2.5.0/gluegen-rt-2.5.0.pom
- https://repo.maven.apache.org/maven2/org/jogamp/gluegen/gluegen-rt/2.5.0/gluegen-rt-2.5.0.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jogamp/gluegen/gluegen-rt/2.5.0/gluegen-rt-2.5.0.pom
- https://s01.oss.sonatype.org/content/repositories/snapshots/org/jogamp/gluegen/gluegen-rt/2.5.0/gluegen-rt-2.5.0.pom
Required by:
project :desktop > project :shared > io.github.kevinnzou:compose-webview-multiplatform:1.7.2 > io.github.kevinnzou:compose-webview-multiplatform-desktop:1.7.2 > dev.datlag:kcef:2023.10.13 > dev.datlag:jcef:2023.10.13
Is it possible to set proxy for the desktop webview?
Hi, I have set captureBackPresses
to false to disable the back navigation of pages. It works as expected on Android, when I click back it goes back to previous screen instead of previous page. But on iOS, the scroll stopped working all together.
Hi I'm working on supporting oAuth flow in 3 platforms.
here is the code base
`@Composable
fun OAuth2WebView(utils: Utils,onAuthorizationCodeReceived: (String) -> Unit) {
val url="${OAuthConfig.AUTH_END_POINT}?response_type=code&client_id=${OAuthConfig.CLIENT_ID}&redirect_uri=${OAuthConfig.REDIRECT_URL}"
val webViewState = rememberWebViewState(url)
LogUtils.logDebug(StringResources.RESPONSE,url)
Column(Modifier.fillMaxSize()) {
val loadingState = webViewState.loadingState
if (loadingState is LoadingState.Loading) {
LinearProgressIndicator(
progress = loadingState.progress,
modifier = Modifier.fillMaxWidth()
)
}
WebView(webViewState, onDispose = {
val currentUrl = webViewState.lastLoadedUrl
LogUtils.logDebug(StringResources.RESPONSE,currentUrl.toString())
if (currentUrl?.startsWith(OAuthConfig.REDIRECT_URL) == true) {
utils.getQueryParameter(currentUrl,"code")?.let {
LogUtils.logDebug(StringResources.RESPONSE,it)
onAuthorizationCodeReceived(it)
}
}
})
}
}`
Problem is when auth success we are geting callback with reDirect url and auth code which we are not geting any control.
I tried onDispose which is working when i click back button but ideally not a good solution.. please give me workaround how to get the loading urls at runtime.
Hi,
I want to update HTML from a UiState. I tested this:
val state = rememberWebViewStateWithHTMLData("initial")
val navigator = rememberWebViewNavigator()
LaunchedEffect(Unit) {
delay(2000)
navigator.loadHtml("<html><body>New HTML</body></html>")
}
Which would be expected to first show "initial", then change to New HTML. It doesn't change.
The problem seems to be in WebViewNavigator line 130 which has this code (collecting the flow):
loadHtml(
event.baseUrl,
event.html,
event.mimeType,
event.encoding,
event.historyUrl,
)
But in AndroidWebView.kt (line 25) the arguments are in different order:
override fun loadHtml(
html: String?,
baseUrl: String?,
mimeType: String?,
encoding: String?,
historyUrl: String?,
)
It seems like baseUrl and html have changed places.
Is that something that can be fixed, or should I send a pull request? Thanks!
Hi, thanks for providing this lib, it has worked very well for our project so far.
It would be great if you could add support for loading PDFs that are linked from a page. At the moment, if I click on a link such as
<a href="https://www.foobar.com/randomfile.pdf" title="randomfile.pdf" download="randomfile.pdf" target="_blank">
nothing happens.
According to https://stackoverflow.com/questions/30461392/android-pdf-not-loading-in-browser-and-webview, if this were only on Android, we could override shouldOverrideUrlLoading
in the WebViewClient
to obtain the behavior we want. However, its not clear if this would actually be the solution, but its worth exploring.
Have you come across this issue before? Many thanks
Hi,
I think this project is filling a really important gap, given that most real world applications with a graphical user interface these days has a webview somewhere.
On Desktop: has the use of webview.dev been considered? Bundling 100MB of Chromium is something that would be better to avoid if possible. There have been a couple projects that aim to allow the use of the system WebView (using webview.dev) on Java: https://github.com/Winterreisender/webviewko and a Java version here: https://github.com/webview/webview_java . Webviewko is looking for a new maintainer.
Maybe this has already been considered. If there's any path to avoid the need to bundle Chromium on the desktop that would massively reduce app sizes.
Solved.
in my windows desktop app, I have no problem making it work for non-release build. However when I'm running using release build I am experiencing an error
I have included modules in build.gradle.kts (includeAllModules = true) as well as followed this readme https://github.com/KevinnZou/compose-webview-multiplatform/blob/main/README.desktop.md
[createContext(...) must not be null] error shows
Exception in thread "AWT-EventQueue-0" java.lang.ClassNotFoundException: org.cef.callback.CefCommandLine_N
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
at org.cef.CefApp.N_Initialize(Native Method)
at org.cef.CefApp.access$400(CefApp.java:25)
at org.cef.CefApp$3.run(CefApp.java:427)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NoSuchMethodError: onBeforeCommandLineProcessing
at org.cef.CefApp.N_Initialize(Native Method)
at org.cef.CefApp.access$400(CefApp.java:25)
at org.cef.CefApp$3.run(CefApp.java:427)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.ClassNotFoundException: org.cef.callback.CefSchemeRegistrar_N
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
at org.cef.CefApp.N_Initialize(Native Method)
at org.cef.CefApp.access$400(CefApp.java:25)
at org.cef.CefApp$3.run(CefApp.java:427)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NoSuchMethodError: onRegisterCustomSchemes
at org.cef.CefApp.N_Initialize(Native Method)
at org.cef.CefApp.access$400(CefApp.java:25)
at org.cef.CefApp$3.run(CefApp.java:427)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "Thread-5" java.lang.NoSuchMethodError: onContextInitialized
Exception in thread "DefaultDispatcher-worker-1" java.lang.NoSuchMethodError: getNativeRef
at org.cef.handler.CefClientHandler.N_CefClientHandler_CTOR(Native Method)
at org.cef.handler.CefClientHandler.<init>(CefClientHandler.java:39)
at org.cef.CefClient.<init>(CefClient.java:110)
at org.cef.CefApp.createClient(CefApp.java:320)
at com.multiplatform.webview.web.Cef.newClient(Cef.kt:98)
at com.multiplatform.webview.web.Cef.newClient$default$4bfbdff3(Cef.kt:93)
at com.multiplatform.webview.web.WebView_desktopKt$DesktopWebView$client$2$1.invokeSuspend(WebView.desktop.kt:51)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:1793)
Exception in thread "DefaultDispatcher-worker-1" java.lang.NoSuchMethodError: setNativeRef
at org.cef.handler.CefClientHandler.N_CefClientHandler_CTOR(Native Method)
at org.cef.handler.CefClientHandler.<init>(CefClientHandler.java:39)
at org.cef.CefClient.<init>(CefClient.java:110)
at org.cef.CefApp.createClient(CefApp.java:320)
at com.multiplatform.webview.web.Cef.newClient(Cef.kt:98)
at com.multiplatform.webview.web.Cef.newClient$default$4bfbdff3(Cef.kt:93)
at com.multiplatform.webview.web.WebView_desktopKt$DesktopWebView$client$2$1.invokeSuspend(WebView.desktop.kt:51)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:1793)
java.lang.UnsatisfiedLinkError: 'org.cef.browser.CefMessageRouter$CefMessageRouterConfig org.cef.browser.CefMessageRouter$CefMessageRouterConfig.N_CreateContext$106d6c7e(org.cef.handler.CefRequestContextHandler)'
at org.cef.browser.CefMessageRouter$CefMessageRouterConfig.N_CreateContext$106d6c7e(Native Method)
at org.cef.browser.CefMessageRouter$CefMessageRouterConfig.createNative$106d6c7e(CefMessageRouter.java:1049)
at org.cef.browser.CefMessageRouter$CefMessageRouterConfig.createContext$7f59e2ed(CefMessageRouter.java:1039)
at com.multiplatform.webview.web.CefRequestExtKt.createModifiedRequestContext$140d9ba5(CefRequestExt.kt:29)
at com.multiplatform.webview.web.WebView_desktopKt.DesktopWebView(WebView.desktop.kt:65)
at com.multiplatform.webview.web.WebView_desktopKt$DesktopWebView$3.invoke(WebView.desktop.kt:1000)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2469)
at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2761)
.....
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: createContext(...) must not be null
at com.multiplatform.webview.web.CefRequestExtKt.createModifiedRequestContext$140d9ba5(CefRequestExt.kt:29)
at com.multiplatform.webview.web.WebView_desktopKt.DesktopWebView(WebView.desktop.kt:65)
at com.multiplatform.webview.web.WebView_desktopKt$DesktopWebView$3.invoke(WebView.desktop.kt:1000)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2469)
at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2761)
The doc of rememberWebViewState
states:
param additionalHttpHeaders Optional, additional HTTP headers that are passed to [AccompanistWebView.loadUrl]. Note that these headers are used for all subsequent requests of the WebView.
It seems the bolded part isn't actually true. The headers are passed along via the initial WebContent.Url
object, but discarded when navigating inside the webview or using navigator.loadUrl()
.
I tried it by attaching an Authorization header to a request; the initial request worked, subsequent requests were rejected.
I can see a few options here:
navigator.loadUrl()
call. That would apply the headers to all requests created via the navigator, but not to requests created by the webview itself.My personal, related issue: I want to attach an Authorization header to all requests (if possible, only requests to a certain domain). I think at the moment this is impossible.
Tested using 1.6.0 and Android, but I think the current master works the same (except that additionalHeaders don't work for desktop at all in 1.6.0).
Thanks for stepping up to build and maintain an KMP webview! 💪
Websites that are able to request and use your GPS don't seem to be working in the WebView. In an ordinary Android app, one could implement a custom WebChromeClient for this to work, see https://stackoverflow.com/questions/42746222/geolocation-is-not-working-on-android-webview
Any solution to this would be greatly appreciated!
I ran an example on Google Pixel, which has absolutely no problems in Chrome. WebView is very slow
Version: 1.7.8
in IOSWebView class
wkWebView.loadHTMLString(
string = concat,
baseURL = baseUrl?.let { NSURL(string = it) },
)
please replace above code with below code
wkWebView.loadHTMLString(
string = concat,
baseURL = baseUrl?.let { NSURL.URLWithString(it) },
)
There are several screens and tabs in my application. On one of the screens in the tab there is a webview. Every time you switch between screens or tablets, webview refreshes the page. I'm not sure if the problem is in the webview or in voyager navigation, or even in my code.
For the accompanist, I found a similar problem where the solution was to use rememberSaveableWebViewState
google/accompanist#1557
However, there is no such class in your library.
My requirement is to communicate with a JavaScript function from native code, similar to what we usually do in the old way by adding ‘addJavascriptInterface’ in WebView. I am exploring this library, but I can’t find any way to communicate with JavaScript code through it.
For a compose desktop application i get this error in state.errorsForCurrentRequest
using the code sample in the README.desktop.md
ERR_ABORTED), WebViewError(code=-3, description=Failed to load url: https://github.com)
Thanks for your efforts for this great library
`class WebSettings {
var isJavaScriptEnabled = true
var customUserAgentString: String? = null
/**
* Android platform specific settings
*/
val androidWebSettings = PlatformWebSettings.AndroidWebSettings()
/**
* Desktop platform specific settings
*/
val desktopWebSettings = PlatformWebSettings.DesktopWebSettings()
/**
* iOS platform specific settings
*/
val iOSWebSettings = PlatformWebSettings.IOSWebSettings
}
`
As you can see there is no support to enable dom storage
Which causes some web pages to turn blank.
Example url : https://economictimes.indiatimes.com/tech/technology/amazon-launches-first-test-satellites-for-internet-network/articleshow/104223101.cms
Description:
There's an issue with the background color not updating to the specified hex color code in a Kotlin Multiplatform for Desktop project. The background remains white, despite the hex code being set correctly in the code. Using named colors like "black" seems to work fine, but hex codes do not.
Steps to Reproduce:
Expected Behavior:
The WebView component's background should display the color corresponding to the hex color code given.
Actual Behavior:
The WebView's background color remains white regardless of the hex color code provided.
Code Snippet:
@Composable
fun BotResponse(
chatMessage: ChatMessage,
chatViewModel: ChatViewModel
) {
chatMessage.botResponse?.let { botResponse ->
val textColorString = "#FFFFFF"
val backgroundColorString = "#222E3A"
val htmlPrefix = "<head><meta name=\"viewport\" content=\"width=device-width, height=device-height, shrink-to-fit=YES\"></head><body style=\"font-family: 'Roboto', sans-serif; color: $textColorString; margin:0px !important; padding:0px!important; background: $backgroundColorString;\"><div id=\"bot-response-container\" style=\"background: $backgroundColorString;\">"
val htmlSuffix = "</div></body>"
val contentHtml = htmlPrefix + botResponse + htmlSuffix
val webViewState = rememberWebViewStateWithHTMLData(
contentHtml,
null,
"utf-8",
"text/html",
null
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth(0.8f)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
WebView(
state = webViewState,
modifier = Modifier.size(320.dp)
)
}
}
}
}
Environment:
OS: [MacOs 13.4]
Kotlin Version: [1.9.10]
Library Version: [1.6.0]
We have to think of a proper way to document certain thinks.
The current documentation is a bit confusing.
We could either use the Wiki feature by GitHub or maybe something like Decompose did.
P.S. please add the following to the desktop ReadMe
> **Note**
> Make sure to exclude the `installDir` from upstreaming by adding it to the `.gitignore`.
> The downloaded files are platform-specific and therefore differ to each user.
Any solution for below issue?
This looks like a very promising library. No problem viewing URLs.
Is it possible to load local HTML files saved in the Resource directory?
Thank you
Title
removed the ä and it works.
there are most likely more letters that also have this problem
We have implemented this library in a kotlin cross platform application (for desktop) and we need to communicate back and forth with the web app we are loading in a webview. As I could see in the documentation we already have a way to send script messages to the web app using the evaluateJavaScript
of the WebViewNavigator
but we don't have a way to implement a scriptMessageHandler
to receive messages from the web app to the app we are building.
Any plan to support this soon? Thanks in advance
when I add it in build.gradle.kt like
repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
maven ("https://maven.aliyun.com/nexus/content/groups/public/")
google()
}
dependencies {
implementation(compose.desktop.currentOs)
testImplementation(kotlin("test"))
val voyagerVersion = "1.0.0-rc07"
implementation("cafe.adriel.voyager:voyager-navigator:$voyagerVersion")
implementation("cafe.adriel.voyager:voyager-bottom-sheet-navigator:$voyagerVersion")
implementation("cafe.adriel.voyager:voyager-tab-navigator:$voyagerVersion")
implementation("cafe.adriel.voyager:voyager-transitions:$voyagerVersion")
antlr("org.antlr:antlr4:4.13.1")
}
kotlin {
sourceSets {
dependencies {
// use api since the desktop app need to access the Cef to initialize it.
api("io.github.kevinnzou:compose-webview-multiplatform:1.5.0")
}
}
}
And then launched the Main.kt
It failed to like this
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'void org.jetbrains.skia.CanvasKt._nTranslate(long, float, float)'
at org.jetbrains.skia.CanvasKt._nTranslate(Native Method)
at org.jetbrains.skia.CanvasKt.access$_nTranslate(Canvas.kt:1)
at org.jetbrains.skia.Canvas.translate(Canvas.kt:1091)
at androidx.compose.ui.graphics.SkiaBackedCanvas.translate(SkiaBackedCanvas.skiko.kt:84)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:357)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:922)
at androidx.compose.ui.platform.SkiaBasedOwner.draw(SkiaBasedOwner.skiko.kt:352)
at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:463)
at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:153)
at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:152)
at androidx.compose.ui.awt.ComposeBridge.catchExceptions(ComposeBridge.desktop.kt:126)
at androidx.compose.ui.awt.ComposeBridge.access$catchExceptions(ComposeBridge.desktop.kt:59)
at androidx.compose.ui.awt.ComposeBridge$skikoView$1.onRender(ComposeBridge.desktop.kt:152)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer.redrawImmediately(Direct3DRedrawer.kt:73)
at org.jetbrains.skiko.SkiaLayer.paint(SkiaLayer.awt.kt:388)
at androidx.compose.ui.awt.WindowComposeBridge$component$1.paint(WindowComposeBridge.desktop.kt:59)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:430)
at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:416)
at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:82)
at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:80)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:59)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:55)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2300)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:471)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:234)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke$performUpdate(UpdateEffect.desktop.kt:55)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:64)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:47)
at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1137)
at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:828)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:849)
at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1041)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:520)
at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
进程已结束,退出代码为 1
Hello, I have integrated your component into my sample application, but now I'm encountering an issue. When I use 'rememberWebViewStateWithHTMLData' to load data in Desktop, it prompts me with the following error message:
Additionally, the content is blank, without any data.
I'm running on Mac and have added the following.
Screen
val html = """
<html>
<head>
<title>Custom Title</title>
</head>
<body>
<h1>Custom HTML</h1>
<p>This is a custom HTML page.</p>
</body>
</html>
""".trimIndent()
val webViewState = rememberWebViewStateWithHTMLData(
html
)
Column(
modifier = Modifier.fillMaxSize()
) {
LedgerTitle(title = state.title, onBack = {
onEvent(AgreementEvent.GoBack)
})
WebView(
modifier = Modifier.fillMaxSize(),
state = webViewState
)
}
Gradle
afterEvaluate {
tasks.withType<JavaExec> {
jvmArgs("--add-opens", "java.desktop/sun.awt=ALL-UNNAMED")
jvmArgs("--add-opens", "java.desktop/java.awt.peer=ALL-UNNAMED")
if (System.getProperty("os.name").contains("Mac")) {
jvmArgs("--add-opens", "java.desktop/sun.awt=ALL-UNNAMED")
jvmArgs("--add-opens", "java.desktop/sun.lwawt=ALL-UNNAMED")
jvmArgs("--add-opens", "java.desktop/sun.lwawt.macosx=ALL-UNNAMED")
}
}
}
I was able to load a url in the webview (inside a Window) and implement js bridge using the SNAPSHOT version. Now I'm facing a different issue. When I got a message from the web app I need to show a popup view with a button for the user to authorize some actions.
I first tried showing the AUTHORIZE view on top of the webview in the same window, and then I tried showing it in a new window. On both cases the webview starts to flicker as shown in the video.
Any ideas what might be causing this?
You can try loading a slow-response URL on Android
, which happens every time, such as browsing https://www.google.com
in China.
Ref: google/accompanist#1442 (comment), there is a way to solve this problem, as follows:
setLayerType(View.LAYER_TYPE_HARDWARE, null) or setLayerType(View.LAYER_TYPE_SOFTWARE, null)
However, there is currently no public API to set layerType, do you have plans for to provide it?
First of all thanks for providing this library.
I need to access the android WebView settings, could you please provide an option to do this.
Maybe a method/value that returns a generic in common, then we can parse it ourself in the specific targets.
I have to change some attributes and apply the settings to the webview again.
People need to add the JavaFx modules themself, because your lib doesn't provide native packages.
Maybe you can extend the build.gradle.kts usage guide.
I did it like this, (a bit overkill but I need this configuration for something else) just strip it down or something:
val javafx = CompileOptions.jvmTarget // jvmTarget set for the whole project
val javafxModules = listOf(
"javafx.base",
"javafx.graphics", // depends on base
"javafx.controls", // depends on base & graphics
"javafx.media", // depends on base & graphics
"javafx.swing", // depends on base & graphics
"javafx.web", // depends on base & graphics & controls & media
)
kotlin {
...
jvm("desktop")
sourceSets {
...
val desktopMain by getting {
dependencies {
...
val javaFxSuffix = getJavaFxSuffix()
javafxModules.forEach { artifact ->
implementation(javaFxLib(artifact, javafx, javaFxSuffix))
}
}
}
}
}
fun getHost(): Host {
return when (osdetector.os) {
"linux" -> Host.Linux
"osx" -> Host.MAC
"windows" -> Host.Windows
else -> {
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
when {
hostOs == "Linux" -> Host.Linux
hostOs == "Mac OS X" -> Host.MAC
isMingwX64 -> Host.Windows
else -> throw IllegalStateException("Unknown OS: ${osdetector.classifier}")
}
}
}
}
fun getJavaFxSuffix(): String {
return when (osdetector.classifier) {
"linux-x86_64" -> "linux"
"linux-aarch_64" -> "linux-aarch64"
"windows-x86_64" -> "win"
"osx-x86_64" -> "mac"
"osx-aarch_64" -> "mac-aarch64"
else -> getHost().label
}
}
fun javaFxLib(artifactId: String, version: String, suffix: String): String {
return "org.openjfx:${artifactId.replace('.', '-')}:${version}:${suffix}"
}
enum class Host(val label: String) {
Linux("linux"),
Windows("win"),
MAC("mac");
}
I want to pass some command line arguments into desktop webview, I tried the following code but it has no effect
KCEF.init(builder = {
addArgs("--disable-web-security","--user-data-dir=~/chromeTemp")
installDir(File("kcef-bundle"))
progress {
onDownloading {
downloading = max(it, 0F)
}
onInitialized {
initialized = true
}
}
settings {
cachePath = File("cache").absolutePath
}
}
I read the documentation and learned that the Desktop platform uses KCEF
, and KCEF
is a wrapper of JCEF
. JCEF
supports passing command arguments to CEFApp
. Am I using it the wrong way? Or KCEF
does not support this now?
btw, I just want to disable CORS restrictions in the webview, is there a better way to do it?
Thanks in advance to all the contributors to this project, it helped me a lot, thank you very much!
Hi There, we used this library in one of our KMM projects, in Android it works perfectly fine, but the issue in iOS it shows scrollable content, instead of making it wrap content
Android Screen shot without scrollabar
iOS Screen shot with scrollbar, how to make it auto adjust according to the height of content
iOS video
After adding this library into commonMain, getting Task :composeApp:compileKotlinIosSimulatorArm64 FAILED
error while running on iosApp.
> Task :composeApp:compileKotlinIosSimulatorArm64 FAILED
error: Could not find "org.jetbrains.kotlin.native.platform.Symbols" in [/Users/shoaib/Downloads/Kart, /Users/shoaib/.konan/klib, /Users/shoaib/.konan/kotlin-native-prebuilt-macos-aarch64-1.9.10/klib/common, /Users/shoaib/.konan/kotlin-native-prebuilt-macos-aarch64-1.9.10/klib/platform/ios_simulator_arm64]
error: Compilation finished with errors
Not sure if it's related with the library but after implementing it I started to get reports from users experiencing a crash with the following error message:
void org.jetbrains.skiko.OpenGLLibraryKt.loadOpenGLLibraryWindows()
Any help will be appreciated. Thanks in advance
java.lang.IllegalAccessError: class org.cef.browser.platform.CefBrowserWindowPlatform (in unnamed module @0x22eab566) cannot access class sun.awt.AWTAccessor (in module java.desktop) because module java.desktop does not export sun.awt to unnamed module @0x22eab566
at org.cef.browser.platform.CefBrowserWindowPlatform.getWindowHandle(CefBrowserWindowPlatform.java:28)
at org.cef.browser.CefBrowserWr.getWindowHandle(CefBrowserWr.java:434)
at org.cef.browser.CefBrowserWr.getWindowHandle(CefBrowserWr.java:426)
at org.cef.browser.CefBrowserWr.createBrowserIfRequired(CefBrowserWr.java:495)
at org.cef.browser.CefBrowserWr$1$1.run(CefBrowserWr.java:65)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Please add media selection support using permission
I just use M3 Scaffold and androidx.compose.ui.window.Dialog
but dim not working in ios
@Composable
internal fun WebViewScreen(
modifier: Modifier = Modifier,
onNavigateUp: () -> Unit,
) {
val uiState = remember { mutableStateOf<WebViewUiState>(WebViewUiState.Url("https://www.naver.com")) }
val webViewDialogVisibleState = remember { mutableStateOf(false) }
Scaffold(
modifier = modifier,
topBar = {
TopBar(
onNavigateUp = onNavigateUp,
onNavigation = { webViewDialogVisibleState.value = true },
)
},
) {
WebView(
modifier = Modifier.fillMaxSize()
.padding(it),
uiState = uiState.value,
)
}
WebViewDialog(
uiState = uiState,
visibleState = webViewDialogVisibleState,
)
}
@Composable
private fun WebViewDialog(
uiState: MutableState<WebViewUiState>,
visibleState: MutableState<Boolean>,
) {
if (visibleState.value) {
Dialog(
onDismissRequest = { visibleState.value = false },
) {
DialogContent(
modifier = Modifier.fillMaxWidth(),
uiState = uiState,
visibleState = visibleState,
)
}
}
}
i want chage "kmpJsBridge" other name
The current implementation of WebView in our application does not maintain the correct aspect ratio when viewed on small laptop devices. This leads to a distorted user interface, affecting the usability and overall user experience.
On laptops with smaller screens, the WebView content appears compressed, leading to layout issues and potential loss of UI functionality.
If we have the option to set the zoom level, we can adjust the correct zoom level on small laptop devices.
Thank you in advance
It's not possible to render composables on top of the WebView on desktop (using JCEF or KCEF. Android/iOS are unaffected). Any composable, even popups or context menus, will be clipped by it.
This isn't a bug with this library but with Compose's Swing interop.
This issue is to keep track of this bug, and to help others who come looking in search of answers.
目前只试了下Mac os,windows未尝试。
在安卓和ios上一切正常。
以下是步骤:
在页面加载完成时做的事情:
val webViewLoadingState = rememberWebViewState(curPageUrl)
if (webViewLoadingState.loadingState == LoadingState.Finished) {
LaunchedEffect(repeatCount) {
// 去执行了 evaluateJavaScript()
}
}
js代码:
evaluateJavaScript(
"""(function() {
var htmlText = document.documentElement.outerHTML;
return htmlText;
})();"""
) { html ->
// 判断页面内容的代码
}
这不是我想要的内容。
我写了个定时循环,如果返回的内容不正确,则间隔0.3s会再次执行这段js,但返回的内容一直是上面的结果
Is there any exposed api for setting and getting cookies from current session ?
couldnt find in readme.
If not there yet, this would be great to have.
Discussion about KCEF
There should be listener support,
where one could listen to events like onLoadStop etc
The android implementation of WebViewClient
contains a method that can be used to intercept and override URLs being loaded by the webview: https://developer.android.com/reference/android/webkit/WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView,%20android.webkit.WebResourceRequest)
It would be nice to have something similar here. :)
We should disable the current logging as it displays unnecessary info for the user and add a interceptor instead.
So the user can decide himself wether it should be enabled or not
I need to get auth cookie when page is loaded.
I try it like this cookies = state.cookieManager.getCookies("https://myurl/")
It works fine on Android, but on iOS I get just []
Hey,
Really nice lib you got there, however, it would be great if you could add support for In-app browsers.
You could use the following implementations.
Android: androidx.browser
iOS: SFSafariViewController
Desktop:
For Windows and Mac, we can use Desktop#browse()
For Linux, we could use xdg-open
Optionally, we can also support Windows via Launcher#LaunchUriAsync for UWP support
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.