通过 Jetpack Compose IconButton 评估 WebView 中的 Javascript

问题描述 投票:0回答:1

我正在编写我的第一个 Android 应用程序,经过大量的试验和错误,我成功地获得了一个带有顶栏、底栏和 Web 视图的工作脚手架结构。我现在想做的是让我添加到底部栏中的按钮可以在 Webview 内执行 Javascript。截至目前,页面已正确加载,但单击

IconButton(onClick = {    webView.evaluateJavascript("console.log('Hello World');", null)  })
不执行任何操作。我知道这可能与 webView 变量未正确定义有关,但我不知道如何修复它。我花了一个小时对这段代码进行故障排除,但没有成功,任何帮助将不胜感激!

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            PDFJSTheme {
                MainContent()
            }
        }
    }
}

@SuppressLint("SetJavaScriptEnabled", "UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainContent() {
    Scaffold(
        topBar = {
            TopAppBar(
                colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primaryContainer,
                    titleContentColor = MaterialTheme.colorScheme.primary,
                ),
                title = {
                    Text("PDF.js")
                },
                actions = {
                    Icon(
                        imageVector = Icons.Default.MoreVert,
                        contentDescription = "image"
                    )
                }
            )
        },
        bottomBar = {
            BottomAppBar(
                actions = {
                    /* Freehand Highlighter */
                    IconButton(onClick = {
                        webView.evaluateJavascript("console.log('Hello World');", null)
                    }) {
                        Icon(painterResource(id = R.drawable.sharp_ink_highlighter_24), contentDescription = "Localized description")
                    }
                    /* Text Highlighter */
                    IconButton(onClick = { /* do something */ }) {
                        Icon(
                            Icons.Default.TextFormat,
                            contentDescription = "Localized description",
                        )
                    }
                    /* Draw  */
                    IconButton(onClick = { /* do something */ }) {
                        Icon(
                            Icons.Default.Draw,
                            contentDescription = "Localized description",
                        )
                    }
                    /* Eraser */
                    IconButton(onClick = { /* do something */ }) {
                        Icon(painterResource(id = R.drawable.sharp_ink_eraser_24), contentDescription = "Localized description")
                    }
                    /* Add Image */
                    IconButton(onClick = { /* do something */ }) {
                        Icon(
                            Icons.Default.Image,
                            contentDescription = "Localized description",
                        )
                    }
                }
            )
        },
    ) { innerPadding ->
        Column(
            modifier = Modifier
                .padding(innerPadding),
            verticalArrangement = Arrangement.spacedBy(16.dp),
        ) {
            MyWebView()
        }
    }
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MyWebView() {
    AndroidView(
        factory = { context ->
            WebView(context).apply {
                layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
                settings.javaScriptEnabled = true
                webViewClient = WebViewClient()
                WebView.setWebContentsDebuggingEnabled(true)
                settings.loadWithOverviewMode = true
                settings.useWideViewPort = true
                settings.allowFileAccess = true
                settings.mixedContentMode = MIXED_CONTENT_ALWAYS_ALLOW
                settings.allowFileAccessFromFileURLs = true
                settings.allowUniversalAccessFromFileURLs = true
            }
        },
        update = { webView ->
            webView.loadUrl("file:///android_asset/web/viewer.html")
        }
    )
}

单击徒手荧光笔图标按钮应触发 console.log 事件,但不会出现任何内容。我在远程 Chromium 窗口中观看了控制台。

android kotlin webview android-jetpack-compose
1个回答
0
投票

我没有看到你在哪里声明了这一行的

webView
变量:

webView.evaluateJavascript

我假设您的文件中某处有一个变量,但这不是推荐的方法。相反,尝试将

String
向下传递给
WebView
,其中包含
WebView
应执行的 JavaScript。然后,一旦
String
非空,就执行
update
函数中的 JavaScript。

请尝试以下代码:

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MyWebView(javascriptString: String, onJavaScriptPerformed: () -> Unit) {

    var initialLoading by remember {
        mutableStateOf(true)
    }

    AndroidView(
        factory = { context ->
            WebView(context).apply {
                //...
            }
        },
        update = { webView ->
            // if our JavaScript modifies the web page, we want to load the web page only at the first time, 
            // otherwise our changes will always be overwritten
            if (initialLoading) {
                webView.loadUrl("https://dl.google.com/")
                initialLoading = false
            }
            if (javascriptString.isNotBlank()) {
                webView.evaluateJavascript(javascriptString, null)
                onJavaScriptPerformed()
            }
        }
    )
}

然后,在您的父可组合项中,像这样调用

MyWebView
可组合项:

var javascriptString by remember {
    mutableStateOf("")
}

Column(
    modifier = Modifier
        .padding(innerPadding),
    verticalArrangement = Arrangement.spacedBy(16.dp),
) {
    MyWebView(
        javascriptString = javascriptString,
        onJavaScriptPerformed = {
            Log.d("MainActivity", "Javascript was executed")
            javascriptString = ""
        }
    )
}

根据文档

WebView
将在最初膨胀时执行
update
函数,然后每当
update
块中使用的状态变量发生更改时执行。

update = { view ->

    // View's been inflated or state read in this block has been updated
    // As selectedItem is read here, AndroidView will recompose
    // whenever the state changes
    // Example of Compose -> View communication
    view.selectedItem = selectedItem
}

按下 IconButton 之前的输出

Screenshot A

按下 IconButton 后的输出

Screenshot B

© www.soinside.com 2019 - 2024. All rights reserved.