6

我正在使用桌面撰写编写桌面应用程序。但是找不到任何关于如何使用我们应该使用的 android 中的 web-view 的建议。

对于桌面应用程序,我们不能使用 android web-view 任何帮助和建议将不胜感激。

4

1 回答 1

1

我已经WebView在 Compose Desktop 中实现了 JavaFX(WebView此处的附加功能 - http://tutorials.jenkov.com/javafx/webview.html)。我的实际用例是用于映射目的,因为实际上没有任何像样的映射 Java 库。然而,这个例子只是加载一个 web url,但是你可以很容易地html从加载自定义内容的资源中加载一个自定义页面。

设置如下(注意java fx插件只能在实际桌面模块中使用,因为它与android库插件冲突)。

桌面模块build.gradle文件:

import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat

plugins {
    kotlin("multiplatform")
    id("org.openjfx.javafxplugin") version "0.0.10"
    id("org.jetbrains.compose") version "1.0.1"
}

group = "com.example.webview"
version = "1.0.0"

kotlin {
    jvm {
        compilations.all {
            kotlinOptions {
                jvmTarget = "11"
            }
            withJava()
        }
    }

    sourceSets {
        val jvmMain by getting {
            dependencies {
                implementation(project(":shared"))
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-native-mt")
                { version { strictly("1.6.0-native-mt") } }
                implementation(compose.desktop.currentOs)
                //Optional other deps
                implementation(compose.uiTooling)
                implementation(compose.runtime)
                implementation(compose.foundation)
                implementation(compose.material)
                implementation(compose.animation)
                implementation(compose.animationGraphics)
            }
        }
        val jvmTest by getting {
            dependencies {
                // testing deps
            }
        }
    }
}

compose.desktop {
    application {
        mainClass = "Mainkt"
        nativeDistributions {
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
            packageName = "your.package.name"
            packageVersion = "1.0.0"
        }
    }
}

javafx {
    version = "16"
    modules = listOf("javafx.controls", "javafx.swing", "javafx.web", "javafx.graphics")
}

Mainkotlin 文件:

fun main() = application(exitProcessOnExit = true) {
    // Required to make sure the JavaFx event loop doesn't finish (can happen when java fx panels in app are shown/hidden)
    val finishListener = object : PlatformImpl.FinishListener {
        override fun idle(implicitExit: Boolean) {}
        override fun exitCalled() {}
    }
    PlatformImpl.addListener(finishListener)

    Window(
        title = "WebView Test",
        resizable = false,
        state = WindowState(
            placement = Floating,
            size = DpSize(minWidth.dp, minHeight.dp)
        ),
        onCloseRequest = {
            PlatformImpl.removeListener(finishListener)
            exitApplication()
        },
        content = {
            val jfxPanel = remember { JFXPanel() }
            var jsObject = remember<JSObject?> { null }

            Box(modifier = Modifier.fillMaxSize().background(Color.White)) {

                ComposeJFXPanel(
                    composeWindow = window,
                    jfxPanel = jfxPanel,
                    onCreate = {
                        Platform.runLater {
                            val root = WebView()
                            val engine = root.engine
                            val scene = Scene(root)
                            engine.loadWorker.stateProperty().addListener { _, _, newState ->
                                if (newState === Worker.State.SUCCEEDED) {
                                    jsObject = root.engine.executeScript("window") as JSObject
                                    // execute other javascript / setup js callbacks fields etc..
                                }
                            }
                            engine.loadWorker.exceptionProperty().addListener { _, _, newError ->
                                println("page load error : $newError")
                            }
                            jfxPanel.scene = scene
                            engine.load("http://google.com") // can be a html document from resources ..
                            engine.setOnError { error -> println("onError : $error") }
                        }
                    }, onDestroy = {
                        Platform.runLater {
                            jsObject?.let { jsObj ->
                                // clean up code for more complex implementations i.e. removing javascript callbacks etc..
                            }
                        }
                    })
            }
        })
}

@Composable
fun ComposeJFXPanel(
    composeWindow: ComposeWindow,
    jfxPanel: JFXPanel,
    onCreate: () -> Unit,
    onDestroy: () -> Unit = {}
) {
    val jPanel = remember { JPanel() }
    val density = LocalDensity.current.density

    Layout(
        content = {},
        modifier = Modifier.onGloballyPositioned { childCoordinates ->
            val coordinates = childCoordinates.parentCoordinates!!
            val location = coordinates.localToWindow(Offset.Zero).round()
            val size = coordinates.size
            jPanel.setBounds(
                (location.x / density).toInt(),
                (location.y / density).toInt(),
                (size.width / density).toInt(),
                (size.height / density).toInt()
            )
            jPanel.validate()
            jPanel.repaint()
        },
        measurePolicy = { _, _ -> layout(0, 0) {} })

    DisposableEffect(jPanel) {
        composeWindow.add(jPanel)
        jPanel.layout = BorderLayout(0, 0)
        jPanel.add(jfxPanel)
        onCreate()
        onDispose {
            onDestroy()
            composeWindow.remove(jPanel)
        }
    }
}

结果 :

在此处输入图像描述

感谢这篇原始帖子中的代码,它提供了JFXPanel- https://github.com/JetBrains/compose-jb/issues/519#issuecomment-804030550的批量实现以及我自己对 Java FX 事件循环修复的后续评论。

于 2022-01-20T00:20:55.843 回答