如何使用evaluateJavascript()从Jetpack Compose中的WebView获取元素

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

我正在尝试在 webview 中查看网页,然后使用 evaluateJavascript() 从页面中获取一些元素......................... ................................

这是代码...

package com.close.practice.webview

import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.AndroidViewModel


@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebPageScreen(urlToRender: String, someViewModel: SomeViewModel) {
Column {

    AndroidView(
        modifier = Modifier
            .height(200.dp),
        factory = { context ->
        WebView(context).apply {
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            webViewClient = WebViewClient()
            settings.javaScriptEnabled = true
            addJavascriptInterface(
                someViewModel.createWebAppInterface(context),
                "Android"
            )
            loadUrl(urlToRender)

        }
    }, update = {
        it.loadUrl(urlToRender)
    })
}



}

class SomeViewModel(application: Application, private val elementValue: MutableState<String>) : AndroidViewModel(application) {
    fun getElementById(webViewObj: WebView, elementId: String) {
        webViewObj.evaluateJavascript(
            "(function() { return document.getElementById('$elementId').innerHTML; })();"
        ) { value ->
            elementValue.value = value
        }
    }

    fun createWebAppInterface(mContext: Context): WebAppInterface {
        return WebAppInterface(mContext)
    }

    inner class WebAppInterface(private val mContext: Context) {
        @JavascriptInterface
        fun webViewCallJs(webViewObj: WebView) {
            // Call the function that gets the element by id and stores it in a variable.
            getElementById(webViewObj, "fname")
        }
    }
}


这是MainActivity

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PracticeTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    
                    Column {
                        val elementValue = remember { mutableStateOf("MainActivity Before") }
                        
                        // To test result before the WebPageScreen is called
                        Text(text = "First Show MAIN Before: ${elementValue.value}")
                        WebPageScreen("https://www.w3schools.com/html/html_forms.asp", SomeViewModel(application, elementValue))
                        
                        // to test result after the WebPageScreen is called
                        Text(text = "First Show MAIN After: ${elementValue.value}")
                    }


                }
            }
        }
    }
}

这就是我运行 apk 时得到的结果 the result

我本来希望获取具有 id (fname) 的元素的值,但代码不起作用

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

我没有看到您正在调用视图模型中您期望的所有函数。您可以使用打印语句和调试器来验证这一点。

此外,您还在 UI 中创建可变状态并将其传递给 veiwModel,然后推测 UI 将被更新。 Java 和 Kotlin 是按值传递的,所以你不能像那样传递变量。

您可以做的是创建一个函数并将其传递给您的 veiwModel,这将允许它更新原始值而不是实际上单独的复制值。您需要通过阅读视图模型来了解如何组织您的 UI,但为了开始测试您的代码,您可以执行以下操作:

update = { newValue ->
     state.value = newValue
}

并将其传递给您的 veiwModel 以更新状态。

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