在使用WebView开发Android应用时,onShowFileChooser
方法通常用于允许用户从设备中选择文件。如果这个方法只能被触发一次,问题可能在于没有正确处理文件选择的回调结果。在WebView中,onShowFileChooser
方法需要一个ValueCallback<Uri[]>
作为参数,用于接收文件选择的结果。如果你没有正确地调用ValueCallback
来传递结果,系统可能不会允许你再次触发文件选择器。
解决这个问题的关键在于确保你正确地处理了文件选择的结果,并且在文件选择完成后释放了ValueCallback
。以下是一个典型的解决方案:
- 确保你有正确的
WebChromeClient
实现:
在你的Activity
中,确保你已经覆盖了WebChromeClient
的onShowFileChooser
方法。 - 正确处理文件选择结果:
当用户选择了一个文件并返回时,你需要调用ValueCallback
的onReceiveValue
方法来传递所选文件的Uri
数组。 - 重置
ValueCallback
:
一旦你传递了结果,记得将ValueCallback
设置为null
,这样系统才能知道可以选择另一个文件。
以下是一个具体的示例代码:
class MainActivity : AppCompatActivity(), ValueCallback<Array<Uri>> { private var mUploadMessage: ValueCallback<Array<Uri>>? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val webView = findViewById<WebView>(R.id.webView) webView.webViewClient = WebViewClient() webView.webChromeClient = object : WebChromeClient() { override fun onShowFileChooser( window: Window?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams? ): Boolean { if (mUploadMessage != null) { mUploadMessage = null } mUploadMessage = filePathCallback // 启动文件选择器 val intent = fileChooserParams?.createIntent() startActivityForResult(intent, FILECHOOSER_RESULT_CODE) return true } } // 加载网页 webView.loadUrl("https://example.com") } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == FILECHOOSER_RESULT_CODE) { if (mUploadMessage == null) { return } when (resultCode) { Activity.RESULT_OK -> { // 从data Intent中获取Uri val result = if (data == null || data.data == null) { arrayOfNulls<Uri>(0) } else { data.clipData?.let { clipData -> Array(clipData.itemCount) { i -> clipData.getItemAt(i).uri } } ?: arrayOf(data.data!!) } mUploadMessage!!.onReceiveValue(result) mUploadMessage = null } Activity.RESULT_CANCELED -> { mUploadMessage!!.onReceiveValue(null) mUploadMessage = null } } } } override fun onReceiveValue(result: Array<Uri>?) { // 这里不应该有代码,因为我们只需要传递结果给WebView,而不是处理结果 } companion object { private const val FILECHOOSER_RESULT_CODE = 1 } }
在上面的代码中,onShowFileChooser
方法被重写,以处理文件选择的启动。onActivityResult
方法则负责处理文件选择的结果,并通过onReceiveValue
方法将结果传递给WebView。
记住,在处理文件选择时,你可能需要考虑权限问题,特别是从Android 6.0(API级别23)开始,你需要动态请求存储权限。如果在Android 10(API级别29)及以上版本,你可能需要额外处理分区存储的影响。