You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 12:33:05