Android Jetpack Compose中WebView图片选择器选中图片后无法提交的问题
Android Jetpack Compose中WebView图片选择器选中图片后无法提交的问题
嘿,我看了你贴的代码,问题很明确:你只是成功唤起了文件选择器,但没把用户选中的图片结果传递回WebView的回调里,WebView根本不知道用户选了啥,自然不会触发提交操作。我给你一步步调整代码来解决这个问题:
首先,你需要保存filePathCallback的引用——这个对象是WebView用来接收选中文件Uri的关键,得在你的类里声明一个全局变量来存储它:
private var filePathCallback: ValueCallback<Array<Uri>>? = null
然后修改onShowFileChooser方法,先清理旧的回调避免重复触发或内存泄漏,再保存新的回调,最后启动选择器(注意要返回true,告诉WebView我们自己处理了文件选择逻辑):
override fun onShowFileChooser( webView: WebView?, callback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams? ): Boolean { // 先清空之前的回调,防止内存泄漏或重复回调 this.filePathCallback?.onReceiveValue(null) this.filePathCallback = callback val intent = fileChooserParams?.createIntent() ?: return false try { // 如果用的是传统startActivityForResult(已废弃,不推荐) (context as Activity).startActivityForResult(intent, 100) // 推荐用Jetpack的Activity Result API,替换成下面这行(需要先注册启动器) // fileChooserLauncher.launch(intent) } catch (e: ActivityNotFoundException) { // 处理找不到文件选择器的异常,比如用户没装文件管理器 filePathCallback = null return false } return true }
接下来就是处理用户选择后的结果了,分两种情况:
情况一:用传统的startActivityForResult
在你的Activity里重写onActivityResult方法,把选中的Uri传递回WebView:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == 100) { val results = when { resultCode == Activity.RESULT_OK && data != null -> { // 兼容单图和多图选择的场景 if (data.clipData != null) { // 多图选择:遍历clipData获取所有Uri val uris = mutableListOf<Uri>() for (i in 0 until data.clipData!!.itemCount) { uris.add(data.clipData!!.getItemAt(i).uri) } uris.toTypedArray() } else { // 单图选择:直接获取data中的Uri arrayOf(data.data!!) } } else -> { // 用户取消选择,返回null告知WebView null } } // 把结果传给WebView的回调,触发提交逻辑 filePathCallback?.onReceiveValue(results) filePathCallback = null // 处理完后清空回调,避免内存泄漏 } }
情况二:用Jetpack的Activity Result API(更推荐)
先在你的Activity里注册一个文件选择启动器:
private val fileChooserLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> val results = when { result.resultCode == Activity.RESULT_OK && result.data != null -> { val data = result.data!! if (data.clipData != null) { val uris = mutableListOf<Uri>() for (i in 0 until data.clipData!!.itemCount) { uris.add(data.clipData!!.getItemAt(i).uri) } uris.toTypedArray() } else { arrayOf(data.data!!) } } else -> null } filePathCallback?.onReceiveValue(results) filePathCallback = null }
然后在onShowFileChooser里用这个启动器唤起选择器就行(就是上面代码里注释掉的那行)。
最后再提个小提醒:虽然你说Manifest里加了权限,但如果是Android 10以下的设备,别忘了申请READ_EXTERNAL_STORAGE的运行时权限;Android 10及以上用MediaStore或SAF的话不需要,但最好做下兼容,避免旧设备出问题。
备注:内容来源于stack exchange,提问作者Mehedi Hasan
相关产品推荐
相关产品推荐

