在 Kotlin 的 WebView 的 JavascriptInterface 中执行页面的 JavaScript
Executing a page's JavaScript inside a WebView's JavascriptInterface in Kotlin
作为一个例子,让我们假设一个项目,我有一个 WebView 实例,我正在我的主 activity 加载本地 HTML 文件:
class MainActivity : AppCompatActivity() {
lateinit var myWebView:WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myWebView = findViewById(R.id.webview)
myWebView.getSettings().setAllowContentAccess(true);
myWebView.getSettings().setAllowFileAccess(true);
myWebView.settings.javaScriptEnabled = true;
myWebView.setWebChromeClient(WebChromeClient());
myWebView.loadUrl("file:///android_asset/websrc/mainPage.html")
myWebView.addJavascriptInterface(WebAppInterface(this), "Android")
}
}
class WebAppInterface(private val mContext: Context) {
@JavascriptInterface fun getStatus() {
MainActivity().myWebView.evaluateJavascript("setStatus('good to go!')", null)
//Or: MainActivity().myWebView.loadURL("javascript:setStatus('good to go!')")
}
}
我也有一个 JavascriptInterface,我想从那里调用 HTML 文件中的 Android.getStatus()
:
<html>
<head>
...
</head>
<body>
<div id="status"></div>
</body>
<script>
document.addEventListener('DOMContentLoaded', function() {
Android.getStatus()
})
function setStatus(status) {
document.querySelector('#status').innerHTML = status
}
</script>
</html>
到目前为止,我认为明白为什么这行不通。从我从 this or this, And especially in the documentation for WebView 之类的答案中了解到,我了解到 JavascriptInterface 和 WebView 在不同的线程上 运行,因此不会定义 setStatus()
之类的东西。到目前为止,我已经尝试使用 runOnUiThread
和 Handler()
。查看 runOnUiThread 的示例:
@JavascriptInterface fun getStatus() {
MainActivity().runOnUiThread(
object : Runnable {
override fun run() {
MainActivity().myWebView.evaluateJavascript("setStatus('good to go!')", null)
//Or: MainActivity().myWebView.loadURL("javascript:setStatus('good to go!')")
}
}
)
}
然而,这(以及 Handler 的使用)给了我:E/AndroidRuntime: FATAL EXCEPTION: JavaBridge
和 lateinit property myWebView has not been initialized
。我真的不明白为什么。应该提到我是 Kotlin 的新手并且 Android.
有什么帮助吗?
我只需要将 myWebView
与 this
一起传递到 JavaScript 接口并使用 Runnable
...
正在创建 JS 界面:
myWebView.addJavascriptInterface(WebAppInterface(this, myWebView), "Android")
然后在 @JavascriptInterface
函数中:
myWebView.post(Runnable {
myWebView.loadUrl("javascript:customFunction()")
})
作为一个例子,让我们假设一个项目,我有一个 WebView 实例,我正在我的主 activity 加载本地 HTML 文件:
class MainActivity : AppCompatActivity() {
lateinit var myWebView:WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myWebView = findViewById(R.id.webview)
myWebView.getSettings().setAllowContentAccess(true);
myWebView.getSettings().setAllowFileAccess(true);
myWebView.settings.javaScriptEnabled = true;
myWebView.setWebChromeClient(WebChromeClient());
myWebView.loadUrl("file:///android_asset/websrc/mainPage.html")
myWebView.addJavascriptInterface(WebAppInterface(this), "Android")
}
}
class WebAppInterface(private val mContext: Context) {
@JavascriptInterface fun getStatus() {
MainActivity().myWebView.evaluateJavascript("setStatus('good to go!')", null)
//Or: MainActivity().myWebView.loadURL("javascript:setStatus('good to go!')")
}
}
我也有一个 JavascriptInterface,我想从那里调用 HTML 文件中的 Android.getStatus()
:
<html>
<head>
...
</head>
<body>
<div id="status"></div>
</body>
<script>
document.addEventListener('DOMContentLoaded', function() {
Android.getStatus()
})
function setStatus(status) {
document.querySelector('#status').innerHTML = status
}
</script>
</html>
到目前为止,我认为明白为什么这行不通。从我从 this or this, And especially in the documentation for WebView 之类的答案中了解到,我了解到 JavascriptInterface 和 WebView 在不同的线程上 运行,因此不会定义 setStatus()
之类的东西。到目前为止,我已经尝试使用 runOnUiThread
和 Handler()
。查看 runOnUiThread 的示例:
@JavascriptInterface fun getStatus() {
MainActivity().runOnUiThread(
object : Runnable {
override fun run() {
MainActivity().myWebView.evaluateJavascript("setStatus('good to go!')", null)
//Or: MainActivity().myWebView.loadURL("javascript:setStatus('good to go!')")
}
}
)
}
然而,这(以及 Handler 的使用)给了我:E/AndroidRuntime: FATAL EXCEPTION: JavaBridge
和 lateinit property myWebView has not been initialized
。我真的不明白为什么。应该提到我是 Kotlin 的新手并且 Android.
有什么帮助吗?
我只需要将 myWebView
与 this
一起传递到 JavaScript 接口并使用 Runnable
...
正在创建 JS 界面:
myWebView.addJavascriptInterface(WebAppInterface(this, myWebView), "Android")
然后在 @JavascriptInterface
函数中:
myWebView.post(Runnable {
myWebView.loadUrl("javascript:customFunction()")
})