如何在 Android WebView 的 Web 应用程序端使用 backpress 事件?
How to consume backpress events in web app side in Android WebView?
使用 JS 接口开发 Kotlin
WebView
,我的 Web 应用程序需要从本机端检测 KeyEvent.KEYCODE_BACK
事件,以便在呈现时关闭 Web 应用程序对话框。如果对话框被关闭,我应该在本机端什么也不做(return true to super),否则我需要完成 web view activity(return false to super)。为了理解我的意图,请阅读下面的代码,我在我的自定义 WebView
上实现了一个线索,
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
this.evaluateJavascript("onDeviceBackPressed();", ValueCallback {
if (it == "1") {
// "Web app consumed onDeviceBackPressed event!"
} else {
// "Web app did not consume onDeviceBackPressed event!"
// super.onKeyDown(keyCode, event) won't work
}
})
// I am required to make the return call wait
// return true/false base on status returned by js func
}
}
}
return super.onKeyDown(keyCode, event)
}
但我知道异步等待超级调用是不可能的。我该如何以其他方式处理这种情况?
您可以在等待 JS 时在第一次按下事件期间使用 KeyEvent,然后在获得结果时 re-use 使用它。
我曾经对触摸事件使用过这样的技巧,所以它应该可以工作。
var delayedKeyCode : Int? = null
var delayedKeyEvent : KeyEvent? = null
var keyDownJSResult : String? = null
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
// see if there's "result" provided from JS
keyDownJSResult?.let{
keyDownJSResult = null // wipe out result so it's not triggered twice
if (it == "1") {
// "Web app consumed onDeviceBackPressed event!"
return true
} else {
// "Web app did not consume onDeviceBackPressed event!"
return super.onKeyDown(keyCode, event)
}
}
// otherwise store keyDown arguments for later and trigger JS
delayedKeyCode = keyCode
delayedKeyEvent = event
this.evaluateJavascript("onDeviceBackPressed();", ValueCallback {
// when JS returns value, trigger this onKeyDown event again
val oldCode = delayedKeyCode
val oldEv = delayedKeyEvent
delayedKeyCode = null
delayedKeyEvent = null
keyDownJSResult = it
onKeyDown(oldCode, oldEv)
})
// always consume event when waiting for JS result
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
终于,我的一个小技巧解决了我的问题,
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
this.evaluateJavascript("onDeviceBackPressed();", ValueCallback {
if (it == "1") {
// consumed by web app, do nothing
} else {
// not consumed by web app, fire explicit back press event
mContext.onBackPressed()
}
})
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
使用 JS 接口开发 Kotlin
WebView
,我的 Web 应用程序需要从本机端检测 KeyEvent.KEYCODE_BACK
事件,以便在呈现时关闭 Web 应用程序对话框。如果对话框被关闭,我应该在本机端什么也不做(return true to super),否则我需要完成 web view activity(return false to super)。为了理解我的意图,请阅读下面的代码,我在我的自定义 WebView
上实现了一个线索,
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
this.evaluateJavascript("onDeviceBackPressed();", ValueCallback {
if (it == "1") {
// "Web app consumed onDeviceBackPressed event!"
} else {
// "Web app did not consume onDeviceBackPressed event!"
// super.onKeyDown(keyCode, event) won't work
}
})
// I am required to make the return call wait
// return true/false base on status returned by js func
}
}
}
return super.onKeyDown(keyCode, event)
}
但我知道异步等待超级调用是不可能的。我该如何以其他方式处理这种情况?
您可以在等待 JS 时在第一次按下事件期间使用 KeyEvent,然后在获得结果时 re-use 使用它。
我曾经对触摸事件使用过这样的技巧,所以它应该可以工作。
var delayedKeyCode : Int? = null
var delayedKeyEvent : KeyEvent? = null
var keyDownJSResult : String? = null
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
// see if there's "result" provided from JS
keyDownJSResult?.let{
keyDownJSResult = null // wipe out result so it's not triggered twice
if (it == "1") {
// "Web app consumed onDeviceBackPressed event!"
return true
} else {
// "Web app did not consume onDeviceBackPressed event!"
return super.onKeyDown(keyCode, event)
}
}
// otherwise store keyDown arguments for later and trigger JS
delayedKeyCode = keyCode
delayedKeyEvent = event
this.evaluateJavascript("onDeviceBackPressed();", ValueCallback {
// when JS returns value, trigger this onKeyDown event again
val oldCode = delayedKeyCode
val oldEv = delayedKeyEvent
delayedKeyCode = null
delayedKeyEvent = null
keyDownJSResult = it
onKeyDown(oldCode, oldEv)
})
// always consume event when waiting for JS result
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
终于,我的一个小技巧解决了我的问题,
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
this.evaluateJavascript("onDeviceBackPressed();", ValueCallback {
if (it == "1") {
// consumed by web app, do nothing
} else {
// not consumed by web app, fire explicit back press event
mContext.onBackPressed()
}
})
return true
}
}
}
return super.onKeyDown(keyCode, event)
}