fix(webview): 修复 Office 文件选择后无响应问题

ContentResolver.getType() 对 doc/docx/xls/xlsx 等 Office 文件经常
返回 "application/octet-stream" 而非精确 MIME 类型,导致 allowed
检查失败、文件被拒绝、H5 无响应。

修复:rawMime 为 null 或 application/octet-stream 时,从文件显示名
的扩展名推断精确 MIME(getMimeTypeFromExtension),使 .docx 能正确
匹配 accept 约束并进入缓存复制流程。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-23 14:30:10 +08:00
父节点 efb9721ddf
当前提交 7b66fcf333

查看文件

@ -448,14 +448,28 @@ fun XWebViewView(
// Validate that the selected file's actual MIME type is within the accepted list.
// Some devices show extra file types in the picker (e.g. .doc when only .docx was
// requested). Passing an unsupported type to the WebView renderer can cause a native
// crash. We accept the file only when its MIME type matches, or fall back to passing
// it through when we can't determine the type (to avoid blocking legitimate uploads).
// crash.
val acceptedMimes = pendingAcceptMimes.value
val actualMime = context.contentResolver.getType(uri)
// ContentResolver returns "application/octet-stream" (or null) for most Office files
// from file-system / Downloads providers. Fall back to extension-based inference so
// .docx / .doc / .xls etc. are not incorrectly rejected.
val rawMime = context.contentResolver.getType(uri)
val actualMime: String? = if (rawMime == null || rawMime == "application/octet-stream") {
val name = context.contentResolver.query(
uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null
)?.use { cursor -> if (cursor.moveToFirst()) cursor.getString(0) else null }
val extMime = name?.substringAfterLast('.', "")
?.lowercase(Locale.ROOT)
?.takeIf { it.isNotEmpty() }
?.let { ext -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext) }
extMime ?: rawMime
} else rawMime
val allowed = acceptedMimes.isNullOrEmpty() ||
acceptedMimes.any { accepted ->
accepted == "*/*" ||
(actualMime != null && (actualMime == accepted || actualMime.startsWith(accepted.substringBefore("*"))))
actualMime == null || // truly unknown type — don't block
actualMime == accepted ||
actualMime.startsWith(accepted.substringBefore("*"))
}
if (!allowed) {
android.util.Log.w("XWV", "Rejected file: actualMime=$actualMime not in accepted=$acceptedMimes")