我正在编写我的第一个 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 窗口中观看了控制台。
我没有看到你在哪里声明了这一行的
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 之前的输出
按下 IconButton 后的输出